mirror of
https://github.com/owncloud/android-library.git
synced 2025-06-08 00:16:09 +00:00
Compare commits
No commits in common. "master" and "oc-android-library-0.9.21" have entirely different histories.
master
...
oc-android
9
.classpath
Normal file
9
.classpath
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
|
</classpath>
|
@ -1,5 +0,0 @@
|
|||||||
[*]
|
|
||||||
max_line_length = 150
|
|
||||||
|
|
||||||
[*.{kt, kts}]
|
|
||||||
disabled_rules=no-consecutive-blank-lines,no-wildcard-imports,max-line-length,no-blank-line-before-rbrace,final-newline,indent,no-multi-spaces,comment-spacing,parameter-list-wrapping
|
|
17
.github/dependabot.yml
vendored
17
.github/dependabot.yml
vendored
@ -1,17 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "gradle"
|
|
||||||
directory: "/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
labels:
|
|
||||||
- "dependencies"
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
10
.github/workflows/gradle-wrapper-validation.yml
vendored
10
.github/workflows/gradle-wrapper-validation.yml
vendored
@ -1,10 +0,0 @@
|
|||||||
name: "Validate Gradle Wrapper"
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validation:
|
|
||||||
name: "Validation"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: gradle/wrapper-validation-action@v1
|
|
15
.gitignore
vendored
15
.gitignore
vendored
@ -2,9 +2,6 @@
|
|||||||
*.apk
|
*.apk
|
||||||
*.ap_
|
*.ap_
|
||||||
|
|
||||||
.idea/*
|
|
||||||
!.idea/codeStyles/
|
|
||||||
|
|
||||||
# files for the dex VM
|
# files for the dex VM
|
||||||
*.dex
|
*.dex
|
||||||
|
|
||||||
@ -12,13 +9,25 @@
|
|||||||
*.class
|
*.class
|
||||||
|
|
||||||
# generated files
|
# generated files
|
||||||
|
bin/
|
||||||
build/
|
build/
|
||||||
gen/
|
gen/
|
||||||
|
target/
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
# Local configuration files (sdk path, etc)
|
# Local configuration files (sdk path, etc)
|
||||||
|
.idea/
|
||||||
.gradle/
|
.gradle/
|
||||||
local.properties
|
local.properties
|
||||||
|
sample_client/local.properties
|
||||||
|
tests/local.properties
|
||||||
|
tests/test_cases/local.properties
|
||||||
|
|
||||||
# Mac .DS_Store files
|
# Mac .DS_Store files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Proguard README
|
||||||
|
proguard-project.txt
|
||||||
|
sample_client/proguard-project.txt
|
||||||
|
tests/proguard-project.txt
|
||||||
|
tests/test_cases/proguard-project.txt
|
378
.idea/codeStyles/Project.xml
generated
378
.idea/codeStyles/Project.xml
generated
@ -1,378 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<option name="LINE_SEPARATOR" value=" " />
|
|
||||||
<option name="RIGHT_MARGIN" value="150" />
|
|
||||||
<JavaCodeStyleSettings>
|
|
||||||
<option name="FIELD_NAME_PREFIX" value="m" />
|
|
||||||
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
|
|
||||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
|
|
||||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
|
|
||||||
<option name="IMPORT_LAYOUT_TABLE">
|
|
||||||
<value>
|
|
||||||
<package name="android" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="javax" withSubpackages="true" static="false" />
|
|
||||||
<package name="java" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="" withSubpackages="true" static="true" />
|
|
||||||
<emptyLine />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
</JavaCodeStyleSettings>
|
|
||||||
<JetCodeStyleSettings>
|
|
||||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
|
||||||
<value>
|
|
||||||
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</JetCodeStyleSettings>
|
|
||||||
<MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<option name="RIGHT_MARGIN" value="72" />
|
|
||||||
</MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<XML>
|
|
||||||
<option name="XML_ATTRIBUTE_WRAP" value="0" />
|
|
||||||
<option name="XML_KEEP_BLANK_LINES" value="1" />
|
|
||||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
|
||||||
</XML>
|
|
||||||
<codeStyleSettings language="JAVA">
|
|
||||||
<option name="RIGHT_MARGIN" value="150" />
|
|
||||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
|
||||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
|
||||||
<option name="IF_BRACE_FORCE" value="3" />
|
|
||||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="FOR_BRACE_FORCE" value="3" />
|
|
||||||
<option name="WRAP_LONG_LINES" value="true" />
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<FINAL>true</FINAL>
|
|
||||||
<PUBLIC>true</PUBLIC>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<FINAL>true</FINAL>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<PUBLIC>true</PUBLIC>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<FINAL>true</FINAL>
|
|
||||||
<PUBLIC>true</PUBLIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<FINAL>true</FINAL>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
<PUBLIC>true</PUBLIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<FIELD>true</FIELD>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<CONSTRUCTOR>true</CONSTRUCTOR>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD>true</METHOD>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<METHOD>true</METHOD>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<ENUM>true</ENUM>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<INTERFACE>true</INTERFACE>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<CLASS>true</CLASS>
|
|
||||||
<STATIC>true</STATIC>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<CLASS>true</CLASS>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_width</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_height</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_.*</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:width</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:height</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="kotlin">
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
|
||||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
|
||||||
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
33
.project
Normal file
33
.project
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ownCloud Android Library</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
4
.settings/org.eclipse.jdt.core.prefs
Normal file
4
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.6
|
55
.travis.yml
Normal file
55
.travis.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
sudo: false
|
||||||
|
language: android
|
||||||
|
jdk:
|
||||||
|
- oraclejdk8
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
install:
|
||||||
|
# Let's use the new command 'sdkmanager' to install Android SDK components
|
||||||
|
- yes | sdkmanager --verbose "build-tools;26.0.2"
|
||||||
|
- yes | sdkmanager --verbose "platform-tools"
|
||||||
|
- yes | sdkmanager --verbose "tools"
|
||||||
|
- yes | sdkmanager --verbose "platforms;android-26"
|
||||||
|
- yes | sdkmanager --verbose "system-images;android-24;default;armeabi-v7a"
|
||||||
|
|
||||||
|
# Check tools and dependencies installed
|
||||||
|
- yes | sdkmanager --list
|
||||||
|
|
||||||
|
# After Travis updated image with Android base environment, building via ant is not possible anymore.
|
||||||
|
# Library tests are old-style tests, and trust on legacy Android ant environment.
|
||||||
|
# Need to disable tests until they are ported to JUnit 4 and gradle build.
|
||||||
|
#- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M
|
||||||
|
#- emulator -avd test -no-window &
|
||||||
|
- rm pom.xml
|
||||||
|
#- android update project -p .
|
||||||
|
#- chmod +x ./wait_for_emulator.sh
|
||||||
|
#- ./wait_for_emulator.sh
|
||||||
|
#
|
||||||
|
# On the other hand, Travis still uses 'android' command behind the 'components' section update.
|
||||||
|
# That command is obsolete and cannot update Android SDK Tools after 25.2.5.
|
||||||
|
# Let's solve it here with the new command 'sdkmanager'
|
||||||
|
- yes | sdkmanager --verbose tools
|
||||||
|
script:
|
||||||
|
#- ant clean
|
||||||
|
#- ant debug
|
||||||
|
#- cd test_client/tests
|
||||||
|
#- ant acceptance-test
|
||||||
|
#- cd ../..
|
||||||
|
- ./gradlew clean build
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
|
# via the "travis encrypt" command using the project repo's public key
|
||||||
|
- secure: epTZ0zZGDbHL3o6vSC9uNkZsi5j5SA6O/tvQBH7QW/dluuzIJxIjfhNbZHDyBReYDleirLzUFQpdWAUdvulCMLs/qZdIzFGlYXZSpxEnvPYMGQcilwADdJcxLw8L+3+ET5hSexxhjrTGw427IljkqGUpqQTxaLwFdFu98lDWSbc=
|
||||||
|
matrix:
|
||||||
|
- ANDROID_TARGET=android-26 ANDROID_ABI=armeabi-v7a
|
||||||
|
addons:
|
||||||
|
coverity_scan:
|
||||||
|
project:
|
||||||
|
name: owncloud/android-library
|
||||||
|
description: Build submitted via Travis CI
|
||||||
|
notification_email: lukas@owncloud.com
|
||||||
|
build_command_prepend: gradle clean
|
||||||
|
build_command: gradle build
|
||||||
|
branch_pattern: coverity_scan
|
41
AndroidManifest.xml
Normal file
41
AndroidManifest.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.owncloud.android.lib"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<!-- USE_CREDENTIALS, MANAGE_ACCOUNTS and AUTHENTICATE_ACCOUNTS are needed for API < 23.
|
||||||
|
In API >= 23 the do not exist anymore -->
|
||||||
|
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||||
|
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||||
|
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="14"
|
||||||
|
android:targetSdkVersion="26" />
|
||||||
|
|
||||||
|
</manifest>
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
ownCloud Android Library is available under MIT license
|
ownCloud Android Library is available under MIT license
|
||||||
|
|
||||||
Copyright (C) 2020 ownCloud GmbH.
|
Copyright (C) 2018 ownCloud GmbH.
|
||||||
Copyright (C) 2012 Bartek Przybylski
|
Copyright (C) 2012 Bartek Przybylski
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -44,11 +44,11 @@ ownCloud Android Library is available under MIT license. See the file LICENSE.md
|
|||||||
|
|
||||||
#### Third party libraries
|
#### Third party libraries
|
||||||
|
|
||||||
ownCloud Android Library uses OkHttp version 4.6.0, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0
|
ownCloud Android Library uses OkHttp version 3.10, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0
|
||||||
|
|
||||||
|
|
||||||
### Compatibility
|
### Compatibility
|
||||||
|
|
||||||
ownCloud Android Library is valid for Android systems from version Android 6 (android:minSdkVersion="23" android:targetSdkVersion="33").
|
ownCloud Android Library is valid for Android systems from version Android 2.2 (android:minSdkVersion="8" android:targetSdkVersion="19").
|
||||||
|
|
||||||
ownCloud Android library supports ownCloud server from version 4.5.
|
ownCloud Android library supports ownCloud server from version 4.5.
|
||||||
|
8
ant.properties
Normal file
8
ant.properties
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# This file contains custom properties used by the Ant build system.
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Java version options
|
||||||
|
java.source=1.7
|
||||||
|
java.target=1.7
|
61
build.gradle
61
build.gradle
@ -1,34 +1,61 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
|
||||||
orgJetbrainsKotlin = '1.8.10'
|
|
||||||
comSquareupMoshi = '1.14.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
jcenter()
|
||||||
maven { url "https://plugins.gradle.org/m2/" }
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jlleitschuh.gradle:ktlint-gradle:11.1.0"
|
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$orgJetbrainsKotlin"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
apply plugin: 'com.android.library'
|
||||||
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
jcenter()
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
dependencies {
|
||||||
apply plugin: "org.jlleitschuh.gradle.ktlint"
|
api 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||||
apply plugin: "com.google.devtools.ksp"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.51"
|
||||||
|
implementation 'com.gitlab.ownclouders:dav4android:oc_support'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 26
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile 'AndroidManifest.xml'
|
||||||
|
java.srcDirs = ['src']
|
||||||
|
resources.srcDirs = ['src']
|
||||||
|
aidl.srcDirs = ['src']
|
||||||
|
renderscript.srcDirs = ['src']
|
||||||
|
res.srcDirs = ['res']
|
||||||
|
assets.srcDirs = ['assets']
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the tests to tests/java, tests/res, etc...
|
||||||
|
androidTest.setRoot('tests')
|
||||||
|
|
||||||
|
// Move the build types to build-types/<type>
|
||||||
|
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
|
||||||
|
// This moves them out of them default location under src/<type>/... which would
|
||||||
|
// conflict with src/ being used by the main source set.
|
||||||
|
// Adding new build types or product flavors should be accompanied
|
||||||
|
// by a similar customization.
|
||||||
|
debug.setRoot('build-types/debug')
|
||||||
|
release.setRoot('build-types/release')
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
92
build.xml
Normal file
92
build.xml
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="owncloud-android-library" default="help">
|
||||||
|
|
||||||
|
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||||
|
It contains the path to the SDK. It should *NOT* be checked into
|
||||||
|
Version Control Systems. -->
|
||||||
|
<property file="local.properties" />
|
||||||
|
|
||||||
|
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||||
|
'android' tool to add properties to it.
|
||||||
|
This is the place to change some Ant specific build properties.
|
||||||
|
Here are some properties you may want to change/update:
|
||||||
|
|
||||||
|
source.dir
|
||||||
|
The name of the source directory. Default is 'src'.
|
||||||
|
out.dir
|
||||||
|
The name of the output directory. Default is 'bin'.
|
||||||
|
|
||||||
|
For other overridable properties, look at the beginning of the rules
|
||||||
|
files in the SDK, at tools/ant/build.xml
|
||||||
|
|
||||||
|
Properties related to the SDK location or the project target should
|
||||||
|
be updated using the 'android' tool with the 'update' action.
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<property file="ant.properties" />
|
||||||
|
|
||||||
|
<!-- if sdk.dir was not set from one of the property file, then
|
||||||
|
get it from the ANDROID_HOME env var.
|
||||||
|
This must be done before we load project.properties since
|
||||||
|
the proguard config can use sdk.dir -->
|
||||||
|
<property environment="env" />
|
||||||
|
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||||
|
<isset property="env.ANDROID_HOME" />
|
||||||
|
</condition>
|
||||||
|
|
||||||
|
<!-- The project.properties file is created and updated by the 'android'
|
||||||
|
tool, as well as ADT.
|
||||||
|
|
||||||
|
This contains project specific properties such as project target, and library
|
||||||
|
dependencies. Lower level build properties are stored in ant.properties
|
||||||
|
(or in .classpath for Eclipse projects).
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems. -->
|
||||||
|
<loadproperties srcFile="project.properties" />
|
||||||
|
|
||||||
|
<!-- quick check on sdk.dir -->
|
||||||
|
<fail
|
||||||
|
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||||
|
unless="sdk.dir"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Import per project custom build rules if present at the root of the project.
|
||||||
|
This is the place to put custom intermediary targets such as:
|
||||||
|
-pre-build
|
||||||
|
-pre-compile
|
||||||
|
-post-compile (This is typically used for code obfuscation.
|
||||||
|
Compiled code location: ${out.classes.absolute.dir}
|
||||||
|
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||||
|
-post-package
|
||||||
|
-post-build
|
||||||
|
-pre-clean
|
||||||
|
-->
|
||||||
|
<import file="custom_rules.xml" optional="true" />
|
||||||
|
|
||||||
|
<!-- Import the actual build file.
|
||||||
|
|
||||||
|
To customize existing targets, there are two options:
|
||||||
|
- Customize only one target:
|
||||||
|
- copy/paste the target into this file, *before* the
|
||||||
|
<import> task.
|
||||||
|
- customize it to your needs.
|
||||||
|
- Customize the whole content of build.xml
|
||||||
|
- copy/paste the content of the rules files (minus the top node)
|
||||||
|
into this file, replacing the <import> task.
|
||||||
|
- customize to your needs.
|
||||||
|
|
||||||
|
***********************
|
||||||
|
****** IMPORTANT ******
|
||||||
|
***********************
|
||||||
|
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||||
|
in order to avoid having your file be overridden by tools such as "android update project"
|
||||||
|
-->
|
||||||
|
<!-- version-tag: 1 -->
|
||||||
|
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||||
|
|
||||||
|
</project>
|
@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
check_license_in_file() {
|
|
||||||
if ! head -n 20 $FILE | grep -q "Permission is hereby granted, free of charge, to any person obtaining a copy"
|
|
||||||
then
|
|
||||||
echo "$FILE does not contain a current copyright header"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
for FILE in $(find owncloudComLibrary/src -name "*.java" -o -name "*.kt")
|
|
||||||
do
|
|
||||||
check_license_in_file
|
|
||||||
done
|
|
||||||
|
|
||||||
./gradlew ktlintFormat
|
|
7
custom_rules.xml
Normal file
7
custom_rules.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="custom_rules">
|
||||||
|
<target name="-post-compile">
|
||||||
|
<echo>Copying jar file for binary distribution</echo>
|
||||||
|
<copy file="${out.absolute.dir}/classes.jar" toFile="${out.absolute.dir}/${ant.project.name}.jar" />
|
||||||
|
</target>
|
||||||
|
</project>
|
@ -1,3 +0,0 @@
|
|||||||
android.enableJetifier=true
|
|
||||||
android.useAndroidX=true
|
|
||||||
org.gradle.jvmargs=-Xmx1536M
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,6 @@
|
|||||||
|
#Wed Aug 17 12:51:45 CEST 2016
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
298
gradlew
vendored
298
gradlew
vendored
@ -1,129 +1,79 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright © 2015-2021 the original authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
##
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
## Gradle start up script for UN*X
|
||||||
#
|
##
|
||||||
# Important for running:
|
|
||||||
#
|
|
||||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
||||||
# noncompliant, but you have some other compliant shell such as ksh or
|
|
||||||
# bash, then to run this script, type that shell name before the whole
|
|
||||||
# command line, like:
|
|
||||||
#
|
|
||||||
# ksh Gradle
|
|
||||||
#
|
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
|
||||||
# requires all of these POSIX shell features:
|
|
||||||
# * functions;
|
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
|
||||||
#
|
|
||||||
# Important for patching:
|
|
||||||
#
|
|
||||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
||||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
||||||
#
|
|
||||||
# The "traditional" practice of packing multiple parameters into a
|
|
||||||
# space-separated string is a well documented source of bugs and security
|
|
||||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
||||||
# options in "$@", and eventually passing that to Java.
|
|
||||||
#
|
|
||||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
||||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
||||||
# see the in-line comments for details.
|
|
||||||
#
|
|
||||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
||||||
# Darwin, MinGW, and NonStop.
|
|
||||||
#
|
|
||||||
# (3) This script is generated from the Groovy template
|
|
||||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
||||||
# within the Gradle project.
|
|
||||||
#
|
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
||||||
#
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
app_path=$0
|
|
||||||
|
|
||||||
# Need this for daisy-chained symlinks.
|
|
||||||
while
|
|
||||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
|
||||||
[ -h "$app_path" ]
|
|
||||||
do
|
|
||||||
ls=$( ls -ld "$app_path" )
|
|
||||||
link=${ls#*' -> '}
|
|
||||||
case $link in #(
|
|
||||||
/*) app_path=$link ;; #(
|
|
||||||
*) app_path=$APP_HOME$link ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=${0##*/}
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD="maximum"
|
||||||
|
|
||||||
warn () {
|
warn ( ) {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
} >&2
|
}
|
||||||
|
|
||||||
die () {
|
die ( ) {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
} >&2
|
}
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
case "`uname`" in
|
||||||
case "$( uname )" in #(
|
CYGWIN* )
|
||||||
CYGWIN* ) cygwin=true ;; #(
|
cygwin=true
|
||||||
Darwin* ) darwin=true ;; #(
|
;;
|
||||||
MSYS* | MINGW* ) msys=true ;; #(
|
Darwin* )
|
||||||
NONSTOP* ) nonstop=true ;;
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >&-
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >&-
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
else
|
else
|
||||||
JAVACMD=$JAVA_HOME/bin/java
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@ -132,7 +82,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD="java"
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
@ -140,95 +90,75 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||||
case $MAX_FD in #(
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
max*)
|
if [ $? -eq 0 ] ; then
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
warn "Could not query maximum file descriptor limit"
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
esac
|
fi
|
||||||
case $MAX_FD in #(
|
ulimit -n $MAX_FD
|
||||||
'' | soft) :;; #(
|
if [ $? -ne 0 ] ; then
|
||||||
*)
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
ulimit -n "$MAX_FD" ||
|
fi
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
else
|
||||||
esac
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, stacking in reverse order:
|
|
||||||
# * args from the command line
|
|
||||||
# * the main class name
|
|
||||||
# * -classpath
|
|
||||||
# * -D...appname settings
|
|
||||||
# * --module-path (only if needed)
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if "$cygwin" || "$msys" ; then
|
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
|
||||||
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
for arg do
|
|
||||||
if
|
|
||||||
case $arg in #(
|
|
||||||
-*) false ;; # don't mess with options #(
|
|
||||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
|
||||||
[ -e "$t" ] ;; #(
|
|
||||||
*) false ;;
|
|
||||||
esac
|
|
||||||
then
|
|
||||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
||||||
fi
|
fi
|
||||||
# Roll the args list around exactly as many times as the number of
|
|
||||||
# args, so each arg winds up back in the position where it started, but
|
|
||||||
# possibly modified.
|
|
||||||
#
|
|
||||||
# NB: a `for` loop captures its iteration list before it begins, so
|
|
||||||
# changing the positional parameters here affects neither the number of
|
|
||||||
# iterations, nor the values presented in `arg`.
|
|
||||||
shift # remove old arg
|
|
||||||
set -- "$@" "$arg" # push replacement arg
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
if $darwin; then
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
# double quotes to make sure that they get re-expanded; and
|
fi
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
|
||||||
|
|
||||||
set -- \
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
if $cygwin ; then
|
||||||
-classpath "$CLASSPATH" \
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
"$@"
|
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
#
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
SEP=""
|
||||||
#
|
for dir in $ROOTDIRSRAW ; do
|
||||||
# In Bash we could simply go:
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
#
|
SEP="|"
|
||||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
done
|
||||||
# set -- "${ARGS[@]}" "$@"
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
#
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
# character that might be a shell metacharacter, then use eval to reverse
|
fi
|
||||||
# that process (while maintaining the separation between arguments), and wrap
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
# the whole thing up as a single "set" statement.
|
i=0
|
||||||
#
|
for arg in "$@" ; do
|
||||||
# This will of course break if any of these variables contains a newline or
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
# an unmatched quote.
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
#
|
|
||||||
|
|
||||||
eval "set -- $(
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
xargs -n1 |
|
else
|
||||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
eval `echo args$i`="\"$arg\""
|
||||||
tr '\n' ' '
|
fi
|
||||||
)" '"$@"'
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||||
|
53
gradlew.bat
vendored
53
gradlew.bat
vendored
@ -1,19 +1,3 @@
|
|||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@ -24,23 +8,20 @@
|
|||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@ -54,7 +35,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@ -64,14 +45,34 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windowz variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
goto execute
|
||||||
|
|
||||||
|
:4NT_args
|
||||||
|
@rem Get arguments from the 4NT Shell from JP Software
|
||||||
|
set CMD_LINE_ARGS=%$
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
BIN
libs/commons-httpclient-3.1.jar
Normal file
BIN
libs/commons-httpclient-3.1.jar
Normal file
Binary file not shown.
BIN
libs/jackrabbit-webdav-2.12.4.jar
Normal file
BIN
libs/jackrabbit-webdav-2.12.4.jar
Normal file
Binary file not shown.
BIN
libs/slf4j-api-1.7.5.jar
Normal file
BIN
libs/slf4j-api-1.7.5.jar
Normal file
Binary file not shown.
@ -1,43 +0,0 @@
|
|||||||
apply plugin: 'com.android.library'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
apply plugin: 'com.google.devtools.ksp'
|
|
||||||
apply plugin: 'kotlin-parcelize'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
api 'com.squareup.okhttp3:okhttp:4.6.0'
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$orgJetbrainsKotlin"
|
|
||||||
api 'com.gitlab.ownclouders:dav4android:oc_support_2.1.5'
|
|
||||||
api 'com.github.AppDevNext.Logcat:LogcatCore:2.2.2'
|
|
||||||
|
|
||||||
// Moshi
|
|
||||||
implementation("com.squareup.moshi:moshi-kotlin:$comSquareupMoshi") {
|
|
||||||
exclude module: "kotlin-reflect"
|
|
||||||
}
|
|
||||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
|
||||||
ksp "com.squareup.moshi:moshi-kotlin-codegen:$comSquareupMoshi"
|
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.2'
|
|
||||||
testImplementation 'org.robolectric:robolectric:4.10'
|
|
||||||
debugImplementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 33
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion 23
|
|
||||||
targetSdkVersion 33
|
|
||||||
}
|
|
||||||
|
|
||||||
lint {
|
|
||||||
abortOnError false
|
|
||||||
ignoreWarnings true
|
|
||||||
}
|
|
||||||
|
|
||||||
testOptions {
|
|
||||||
unitTests {
|
|
||||||
includeAndroidResources = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace 'com.owncloud.android.lib'
|
|
||||||
}
|
|
@ -1,30 +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.http
|
|
||||||
|
|
||||||
import com.facebook.stetho.okhttp3.StethoInterceptor
|
|
||||||
|
|
||||||
object DebugInterceptorFactory {
|
|
||||||
fun getInterceptor() = StethoInterceptor()
|
|
||||||
}
|
|
@ -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.common
|
|
||||||
|
|
||||||
import android.accounts.AccountManager
|
|
||||||
import android.accounts.AccountsException
|
|
||||||
import android.content.Context
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
|
|
||||||
import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation
|
|
||||||
import com.owncloud.android.lib.resources.status.RemoteServerInfo
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ConnectionValidator
|
|
||||||
*
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
*/
|
|
||||||
class ConnectionValidator(
|
|
||||||
val context: Context,
|
|
||||||
private val clearCookiesOnValidation: Boolean
|
|
||||||
) {
|
|
||||||
fun validate(baseClient: OwnCloudClient, singleSessionManager: SingleSessionManager, context: Context): Boolean {
|
|
||||||
try {
|
|
||||||
var validationRetryCount = 0
|
|
||||||
val client = OwnCloudClient(baseClient.baseUri, null, false, singleSessionManager, context)
|
|
||||||
if (clearCookiesOnValidation) {
|
|
||||||
client.clearCookies()
|
|
||||||
} else {
|
|
||||||
client.cookiesForBaseUri = baseClient.cookiesForBaseUri
|
|
||||||
}
|
|
||||||
|
|
||||||
client.account = baseClient.account
|
|
||||||
client.credentials = baseClient.credentials
|
|
||||||
while (validationRetryCount < VALIDATION_RETRY_COUNT) {
|
|
||||||
Timber.d("validationRetryCount %d", validationRetryCount)
|
|
||||||
var successCounter = 0
|
|
||||||
var failCounter = 0
|
|
||||||
|
|
||||||
client.setFollowRedirects(true)
|
|
||||||
if (isOwnCloudStatusOk(client)) {
|
|
||||||
successCounter++
|
|
||||||
} else {
|
|
||||||
failCounter++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the part where we try to check if we can access the parts where we have to be logged in... if we are not logged in
|
|
||||||
if (baseClient.credentials !is OwnCloudAnonymousCredentials) {
|
|
||||||
client.setFollowRedirects(false)
|
|
||||||
val contentReply = canAccessRootFolder(client)
|
|
||||||
if (contentReply.httpCode == HttpConstants.HTTP_OK) {
|
|
||||||
if (contentReply.data == true) { //if data is true it means that the content reply was ok
|
|
||||||
successCounter++
|
|
||||||
} else {
|
|
||||||
failCounter++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
failCounter++
|
|
||||||
if (contentReply.httpCode == HttpConstants.HTTP_UNAUTHORIZED) {
|
|
||||||
checkUnauthorizedAccess(client, singleSessionManager, contentReply.httpCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (successCounter >= failCounter) {
|
|
||||||
baseClient.credentials = client.credentials
|
|
||||||
baseClient.cookiesForBaseUri = client.cookiesForBaseUri
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
validationRetryCount++
|
|
||||||
}
|
|
||||||
Timber.d("Could not authenticate or get valid data from owncloud")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.d(ExceptionUtils.getStackTrace(e))
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isOwnCloudStatusOk(client: OwnCloudClient): Boolean {
|
|
||||||
val reply = getOwnCloudStatus(client)
|
|
||||||
// dont check status code. It currently relais on the broken redirect code of the owncloud client
|
|
||||||
// TODO: Use okhttp redirect and add this check again
|
|
||||||
// return reply.httpCode == HttpConstants.HTTP_OK &&
|
|
||||||
return !reply.isException &&
|
|
||||||
reply.data != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getOwnCloudStatus(client: OwnCloudClient): RemoteOperationResult<RemoteServerInfo> {
|
|
||||||
val remoteStatusOperation = GetRemoteStatusOperation()
|
|
||||||
return remoteStatusOperation.execute(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canAccessRootFolder(client: OwnCloudClient): RemoteOperationResult<Boolean> {
|
|
||||||
val checkPathExistenceRemoteOperation = CheckPathExistenceRemoteOperation("/", true)
|
|
||||||
return checkPathExistenceRemoteOperation.execute(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if credentials should be invalidated according the to the HTTPS status
|
|
||||||
* of a network request just performed.
|
|
||||||
*
|
|
||||||
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
|
|
||||||
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
|
|
||||||
* cannot be invalidated with the given arguments.
|
|
||||||
*/
|
|
||||||
private fun shouldInvalidateAccountCredentials(credentials: OwnCloudCredentials, account: OwnCloudAccount, httpStatusCode: Int): Boolean {
|
|
||||||
var shouldInvalidateAccountCredentials = httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED
|
|
||||||
shouldInvalidateAccountCredentials = shouldInvalidateAccountCredentials and // real credentials
|
|
||||||
(credentials !is OwnCloudAnonymousCredentials)
|
|
||||||
|
|
||||||
// test if have all the needed to effectively invalidate ...
|
|
||||||
shouldInvalidateAccountCredentials =
|
|
||||||
shouldInvalidateAccountCredentials and (account.savedAccount != null)
|
|
||||||
Timber.d(
|
|
||||||
"""Received error: $httpStatusCode,
|
|
||||||
account: ${account.name}
|
|
||||||
credentials are real: ${credentials !is OwnCloudAnonymousCredentials},
|
|
||||||
so we need to invalidate credentials for account ${account.name} : $shouldInvalidateAccountCredentials"""
|
|
||||||
)
|
|
||||||
return shouldInvalidateAccountCredentials
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates credentials stored for the given account in the system [AccountManager] and in
|
|
||||||
* current [SingleSessionManager.getDefaultSingleton] instance.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* [.shouldInvalidateAccountCredentials] should be called first.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private fun invalidateAccountCredentials(account: OwnCloudAccount, credentials: OwnCloudCredentials) {
|
|
||||||
Timber.i("Invalidating account credentials for account $account")
|
|
||||||
val am = AccountManager.get(context)
|
|
||||||
am.invalidateAuthToken(
|
|
||||||
account.savedAccount.type,
|
|
||||||
credentials.authToken
|
|
||||||
)
|
|
||||||
am.clearPassword(account.savedAccount) // being strict, only needed for Basic Auth credentials
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Invalidates current credentials if the request failed as anauthorized.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Refresh current credentials if possible, and marks a retry.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private fun checkUnauthorizedAccess(client: OwnCloudClient, singleSessionManager: SingleSessionManager, status: Int): Boolean {
|
|
||||||
var credentialsWereRefreshed = false
|
|
||||||
val account = client.account
|
|
||||||
val credentials = account.credentials
|
|
||||||
if (shouldInvalidateAccountCredentials(credentials, account, status)) {
|
|
||||||
invalidateAccountCredentials(account, credentials)
|
|
||||||
|
|
||||||
if (credentials.authTokenCanBeRefreshed()) {
|
|
||||||
try {
|
|
||||||
// This command does the actual refresh
|
|
||||||
Timber.i("Trying to refresh auth token for account $account")
|
|
||||||
account.loadCredentials(context)
|
|
||||||
// if mAccount.getCredentials().length() == 0 --> refresh failed
|
|
||||||
client.credentials = account.credentials
|
|
||||||
credentialsWereRefreshed = true
|
|
||||||
} catch (e: AccountsException) {
|
|
||||||
Timber.e(
|
|
||||||
e, "Error while trying to refresh auth token for %s\ntrace: %s",
|
|
||||||
account.savedAccount.name,
|
|
||||||
ExceptionUtils.getStackTrace(e)
|
|
||||||
)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Timber.e(
|
|
||||||
e, "Error while trying to refresh auth token for %s\ntrace: %s",
|
|
||||||
account.savedAccount.name,
|
|
||||||
ExceptionUtils.getStackTrace(e)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (!credentialsWereRefreshed) {
|
|
||||||
// if credentials are not refreshed, client must be removed
|
|
||||||
// from the OwnCloudClientManager to prevent it is reused once and again
|
|
||||||
Timber.w("Credentials were not refreshed, client will be removed from the Session Manager to prevent using it over and over")
|
|
||||||
singleSessionManager.removeClientFor(account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// else: onExecute will finish with status 401
|
|
||||||
}
|
|
||||||
return credentialsWereRefreshed
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val VALIDATION_RETRY_COUNT = 3
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,255 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2020 ownCloud GmbH.
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.accounts.AccountUtils;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
|
|
||||||
import com.owncloud.android.lib.common.http.HttpClient;
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
|
||||||
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
|
|
||||||
import com.owncloud.android.lib.common.utils.RandomUtils;
|
|
||||||
import okhttp3.Cookie;
|
|
||||||
import okhttp3.HttpUrl;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER;
|
|
||||||
import static com.owncloud.android.lib.common.http.HttpConstants.HTTP_MOVED_PERMANENTLY;
|
|
||||||
|
|
||||||
public class OwnCloudClient extends HttpClient {
|
|
||||||
|
|
||||||
public static final String WEBDAV_FILES_PATH_4_0 = "/remote.php/dav/files/";
|
|
||||||
public static final String STATUS_PATH = "/status.php";
|
|
||||||
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
|
|
||||||
private static final int MAX_RETRY_COUNT = 2;
|
|
||||||
|
|
||||||
private static int sIntanceCounter = 0;
|
|
||||||
private OwnCloudCredentials mCredentials = null;
|
|
||||||
private int mInstanceNumber;
|
|
||||||
private Uri mBaseUri;
|
|
||||||
private OwnCloudAccount mAccount;
|
|
||||||
private final ConnectionValidator mConnectionValidator;
|
|
||||||
private Object mRequestMutex = new Object();
|
|
||||||
|
|
||||||
// If set to true a mutex will be used to prevent parallel execution of the execute() method
|
|
||||||
// if false the execute() method can be called even though the mutex is already aquired.
|
|
||||||
// This is used for the ConnectionValidator, which has to be able to execute OperationsWhile all "normal" operations net
|
|
||||||
// to be set on hold.
|
|
||||||
private final Boolean mSynchronizeRequests;
|
|
||||||
|
|
||||||
private SingleSessionManager mSingleSessionManager = null;
|
|
||||||
|
|
||||||
private boolean mFollowRedirects = false;
|
|
||||||
|
|
||||||
public OwnCloudClient(Uri baseUri,
|
|
||||||
ConnectionValidator connectionValidator,
|
|
||||||
boolean synchronizeRequests,
|
|
||||||
SingleSessionManager singleSessionManager,
|
|
||||||
Context context) {
|
|
||||||
super(context);
|
|
||||||
|
|
||||||
if (baseUri == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL");
|
|
||||||
}
|
|
||||||
mBaseUri = baseUri;
|
|
||||||
mSynchronizeRequests = synchronizeRequests;
|
|
||||||
mSingleSessionManager = singleSessionManager;
|
|
||||||
|
|
||||||
mInstanceNumber = sIntanceCounter++;
|
|
||||||
Timber.d("#" + mInstanceNumber + "Creating OwnCloudClient");
|
|
||||||
|
|
||||||
clearCredentials();
|
|
||||||
clearCookies();
|
|
||||||
mConnectionValidator = connectionValidator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCredentials() {
|
|
||||||
if (!(mCredentials instanceof OwnCloudAnonymousCredentials)) {
|
|
||||||
mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int executeHttpMethod(HttpBaseMethod method) throws Exception {
|
|
||||||
if (mSynchronizeRequests) {
|
|
||||||
synchronized (mRequestMutex) {
|
|
||||||
return saveExecuteHttpMethod(method);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return saveExecuteHttpMethod(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int saveExecuteHttpMethod(HttpBaseMethod method) throws Exception {
|
|
||||||
int repeatCounter = 0;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (mFollowRedirects) {
|
|
||||||
method.setFollowRedirects(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean retry;
|
|
||||||
do {
|
|
||||||
repeatCounter++;
|
|
||||||
retry = false;
|
|
||||||
String requestId = RandomUtils.generateRandomUUID();
|
|
||||||
|
|
||||||
// Header to allow tracing requests in apache and ownCloud logs
|
|
||||||
Timber.d("Executing in request with id %s", requestId);
|
|
||||||
method.setRequestHeader(HttpConstants.OC_X_REQUEST_ID, requestId);
|
|
||||||
method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent());
|
|
||||||
method.setRequestHeader(HttpConstants.ACCEPT_LANGUAGE_HEADER, Locale.getDefault().getLanguage());
|
|
||||||
method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
|
|
||||||
if (mCredentials.getHeaderAuth() != null && !mCredentials.getHeaderAuth().isEmpty()) {
|
|
||||||
method.setRequestHeader(AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
|
|
||||||
}
|
|
||||||
|
|
||||||
status = method.execute(this);
|
|
||||||
|
|
||||||
if (shouldConnectionValidatorBeCalled(method, status)) {
|
|
||||||
retry = mConnectionValidator.validate(this, mSingleSessionManager, getContext()); // retry on success fail on no success
|
|
||||||
} else if (method.getFollowPermanentRedirects() && status == HTTP_MOVED_PERMANENTLY) {
|
|
||||||
retry = true;
|
|
||||||
method.setFollowRedirects(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (retry && repeatCounter < MAX_RETRY_COUNT);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldConnectionValidatorBeCalled(HttpBaseMethod method, int status) {
|
|
||||||
|
|
||||||
return mConnectionValidator != null && (
|
|
||||||
(!(mCredentials instanceof OwnCloudAnonymousCredentials) &&
|
|
||||||
status == HttpConstants.HTTP_UNAUTHORIZED
|
|
||||||
) || (!mFollowRedirects &&
|
|
||||||
!method.getFollowRedirects() &&
|
|
||||||
status == HttpConstants.HTTP_MOVED_TEMPORARILY
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
|
|
||||||
*
|
|
||||||
* @param responseBodyAsStream InputStream with the HTTP response to exhaust.
|
|
||||||
*/
|
|
||||||
public void exhaustResponse(InputStream responseBodyAsStream) {
|
|
||||||
if (responseBodyAsStream != null) {
|
|
||||||
try {
|
|
||||||
responseBodyAsStream.close();
|
|
||||||
|
|
||||||
} catch (IOException io) {
|
|
||||||
Timber.e(io, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getBaseFilesWebDavUri() {
|
|
||||||
return Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getUserFilesWebDavUri() {
|
|
||||||
return (mCredentials instanceof OwnCloudAnonymousCredentials || mAccount == null)
|
|
||||||
? Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0)
|
|
||||||
: Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0 + AccountUtils.getUserId(
|
|
||||||
mAccount.getSavedAccount(), getContext()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getUploadsWebDavUri() {
|
|
||||||
return mCredentials instanceof OwnCloudAnonymousCredentials
|
|
||||||
? Uri.parse(mBaseUri + WEBDAV_UPLOADS_PATH_4_0)
|
|
||||||
: Uri.parse(mBaseUri + WEBDAV_UPLOADS_PATH_4_0 + AccountUtils.getUserId(
|
|
||||||
mAccount.getSavedAccount(), getContext()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getBaseUri() {
|
|
||||||
return mBaseUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the root URI to the ownCloud server.
|
|
||||||
* <p>
|
|
||||||
* Use with care.
|
|
||||||
*
|
|
||||||
* @param uri
|
|
||||||
*/
|
|
||||||
public void setBaseUri(Uri uri) {
|
|
||||||
if (uri == null) {
|
|
||||||
throw new IllegalArgumentException("URI cannot be NULL");
|
|
||||||
}
|
|
||||||
mBaseUri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final OwnCloudCredentials getCredentials() {
|
|
||||||
return mCredentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCredentials(OwnCloudCredentials credentials) {
|
|
||||||
if (credentials != null) {
|
|
||||||
mCredentials = credentials;
|
|
||||||
} else {
|
|
||||||
clearCredentials();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCookiesForBaseUri(List<Cookie> cookies) {
|
|
||||||
getOkHttpClient().cookieJar().saveFromResponse(
|
|
||||||
HttpUrl.parse(mBaseUri.toString()),
|
|
||||||
cookies
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Cookie> getCookiesForBaseUri() {
|
|
||||||
return getOkHttpClient().cookieJar().loadForRequest(
|
|
||||||
HttpUrl.parse(mBaseUri.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnCloudAccount getAccount() {
|
|
||||||
return mAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccount(OwnCloudAccount account) {
|
|
||||||
this.mAccount = account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFollowRedirects(boolean followRedirects) {
|
|
||||||
this.mFollowRedirects = followRedirects;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,225 +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;
|
|
||||||
|
|
||||||
import android.accounts.AuthenticatorException;
|
|
||||||
import android.accounts.OperationCanceledException;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.accounts.AccountUtils;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SingleSessionManager {
|
|
||||||
|
|
||||||
private static SingleSessionManager sDefaultSingleton;
|
|
||||||
private static String sUserAgent;
|
|
||||||
private static ConnectionValidator sConnectionValidator;
|
|
||||||
|
|
||||||
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername = new ConcurrentHashMap<>();
|
|
||||||
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public static SingleSessionManager getDefaultSingleton() {
|
|
||||||
if (sDefaultSingleton == null) {
|
|
||||||
sDefaultSingleton = new SingleSessionManager();
|
|
||||||
}
|
|
||||||
return sDefaultSingleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setConnectionValidator(ConnectionValidator connectionValidator) {
|
|
||||||
sConnectionValidator = connectionValidator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConnectionValidator getConnectionValidator() {
|
|
||||||
return sConnectionValidator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getUserAgent() {
|
|
||||||
return sUserAgent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setUserAgent(String userAgent) {
|
|
||||||
sUserAgent = userAgent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OwnCloudClient createOwnCloudClient(Uri uri,
|
|
||||||
Context context,
|
|
||||||
ConnectionValidator connectionValidator,
|
|
||||||
SingleSessionManager singleSessionManager) {
|
|
||||||
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true, singleSessionManager, context);
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnCloudClient getClientFor(OwnCloudAccount account,
|
|
||||||
Context context) throws OperationCanceledException,
|
|
||||||
AuthenticatorException, IOException {
|
|
||||||
return getClientFor(account, context, getConnectionValidator());
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnCloudClient getClientFor(OwnCloudAccount account,
|
|
||||||
Context context,
|
|
||||||
ConnectionValidator connectionValidator) throws OperationCanceledException,
|
|
||||||
AuthenticatorException, IOException {
|
|
||||||
|
|
||||||
Timber.d("getClientFor starting ");
|
|
||||||
if (account == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot get an OwnCloudClient for a null account");
|
|
||||||
}
|
|
||||||
|
|
||||||
OwnCloudClient client = null;
|
|
||||||
String accountName = account.getName();
|
|
||||||
String sessionName = account.getCredentials() == null ? "" :
|
|
||||||
AccountUtils.buildAccountName(account.getBaseUri(), account.getCredentials().getAuthToken());
|
|
||||||
|
|
||||||
if (accountName != null) {
|
|
||||||
client = mClientsWithKnownUsername.get(accountName);
|
|
||||||
}
|
|
||||||
boolean reusingKnown = false; // just for logs
|
|
||||||
if (client == null) {
|
|
||||||
if (accountName != null) {
|
|
||||||
client = mClientsWithUnknownUsername.remove(sessionName);
|
|
||||||
if (client != null) {
|
|
||||||
Timber.v("reusing client for session %s", sessionName);
|
|
||||||
|
|
||||||
mClientsWithKnownUsername.put(accountName, client);
|
|
||||||
Timber.v("moved client to account %s", accountName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
client = mClientsWithUnknownUsername.get(sessionName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Timber.v("reusing client for account %s", accountName);
|
|
||||||
if (client.getAccount() != null &&
|
|
||||||
client.getAccount().getCredentials() != null &&
|
|
||||||
(client.getAccount().getCredentials().getAuthToken() == null || client.getAccount().getCredentials().getAuthToken().isEmpty())
|
|
||||||
) {
|
|
||||||
Timber.i("Client " + client.getAccount().getName() + " needs to refresh credentials");
|
|
||||||
|
|
||||||
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
|
|
||||||
//injected instance that can be deleted when required
|
|
||||||
client.clearCookies();
|
|
||||||
client.clearCredentials();
|
|
||||||
|
|
||||||
client.setAccount(account);
|
|
||||||
|
|
||||||
account.loadCredentials(context);
|
|
||||||
client.setCredentials(account.getCredentials());
|
|
||||||
|
|
||||||
Timber.i("Client " + account.getName() + " with credentials size" + client.getAccount().getCredentials().getAuthToken().length());
|
|
||||||
}
|
|
||||||
reusingKnown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
// no client to reuse - create a new one
|
|
||||||
client = createOwnCloudClient(
|
|
||||||
account.getBaseUri(),
|
|
||||||
context,
|
|
||||||
connectionValidator,
|
|
||||||
this); // TODO remove dependency on OwnCloudClientFactory
|
|
||||||
|
|
||||||
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
|
|
||||||
//injected instance that can be deleted when required
|
|
||||||
client.clearCookies();
|
|
||||||
client.clearCredentials();
|
|
||||||
|
|
||||||
client.setAccount(account);
|
|
||||||
|
|
||||||
account.loadCredentials(context);
|
|
||||||
client.setCredentials(account.getCredentials());
|
|
||||||
|
|
||||||
if (accountName != null) {
|
|
||||||
mClientsWithKnownUsername.put(accountName, client);
|
|
||||||
Timber.v("new client for account %s", accountName);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
mClientsWithUnknownUsername.put(sessionName, client);
|
|
||||||
Timber.v("new client for session %s", sessionName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!reusingKnown) {
|
|
||||||
Timber.v("reusing client for session %s", sessionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
keepUriUpdated(account, client);
|
|
||||||
}
|
|
||||||
Timber.d("getClientFor finishing ");
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeClientFor(OwnCloudAccount account) {
|
|
||||||
Timber.d("removeClientFor starting ");
|
|
||||||
|
|
||||||
if (account == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OwnCloudClient client;
|
|
||||||
String accountName = account.getName();
|
|
||||||
if (accountName != null) {
|
|
||||||
client = mClientsWithKnownUsername.remove(accountName);
|
|
||||||
if (client != null) {
|
|
||||||
Timber.v("Removed client for account %s", accountName);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Timber.v("No client tracked for account %s", accountName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mClientsWithUnknownUsername.clear();
|
|
||||||
|
|
||||||
Timber.d("removeClientFor finishing ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshCredentialsForAccount(String accountName, OwnCloudCredentials credentials) {
|
|
||||||
OwnCloudClient ownCloudClient = mClientsWithKnownUsername.get(accountName);
|
|
||||||
if (ownCloudClient == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ownCloudClient.setCredentials(credentials);
|
|
||||||
mClientsWithKnownUsername.replace(accountName, ownCloudClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method is just a patch; we need to distinguish accounts in the same host but
|
|
||||||
// different paths; but that requires updating the accountNames for apps upgrading
|
|
||||||
private void keepUriUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) {
|
|
||||||
Uri recentUri = account.getBaseUri();
|
|
||||||
if (!recentUri.equals(reusedClient.getBaseUri())) {
|
|
||||||
reusedClient.setBaseUri(recentUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,224 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2020 ownCloud GmbH.
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
*
|
|
||||||
* 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.accounts;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AccountsException;
|
|
||||||
import android.accounts.AuthenticatorException;
|
|
||||||
import android.accounts.OperationCanceledException;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
|
|
||||||
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
|
|
||||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class AccountUtils {
|
|
||||||
/**
|
|
||||||
* Constructs full url to host and webdav resource basing on host version
|
|
||||||
*
|
|
||||||
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
|
|
||||||
* @param account A stored ownCloud {@link Account}
|
|
||||||
* @return Full URL to WebDAV endpoint in the server corresponding to 'account'.
|
|
||||||
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
|
|
||||||
*/
|
|
||||||
public static String getWebDavUrlForAccount(Context context, Account account)
|
|
||||||
throws AccountNotFoundException {
|
|
||||||
|
|
||||||
return getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_FILES_PATH_4_0
|
|
||||||
+ AccountUtils.getUserId(account, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts url server from the account
|
|
||||||
*
|
|
||||||
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
|
|
||||||
* @param account A stored ownCloud {@link Account}
|
|
||||||
* @return Full URL to the server corresponding to 'account', ending in the base path
|
|
||||||
* common to all API endpoints.
|
|
||||||
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
|
|
||||||
*/
|
|
||||||
public static String getBaseUrlForAccount(Context context, Account account)
|
|
||||||
throws AccountNotFoundException {
|
|
||||||
AccountManager ama = AccountManager.get(context.getApplicationContext());
|
|
||||||
String baseurl = ama.getUserData(account, Constants.KEY_OC_BASE_URL);
|
|
||||||
|
|
||||||
if (baseurl == null) {
|
|
||||||
throw new AccountNotFoundException(account, "Account not found", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return baseurl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the username corresponding to an OC account.
|
|
||||||
*
|
|
||||||
* @param account An OC account
|
|
||||||
* @return Username for the given account, extracted from the account.name
|
|
||||||
*/
|
|
||||||
public static String getUsernameForAccount(Account account) {
|
|
||||||
String username = null;
|
|
||||||
try {
|
|
||||||
username = account.name.substring(0, account.name.lastIndexOf('@'));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e, "Couldn't get a username for the given account");
|
|
||||||
}
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
* @throws AuthenticatorException
|
|
||||||
* @throws OperationCanceledException
|
|
||||||
*/
|
|
||||||
public static OwnCloudCredentials getCredentialsForAccount(Context context, Account account)
|
|
||||||
throws OperationCanceledException, AuthenticatorException, IOException {
|
|
||||||
|
|
||||||
OwnCloudCredentials credentials;
|
|
||||||
AccountManager am = AccountManager.get(context);
|
|
||||||
|
|
||||||
String supportsOAuth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
|
|
||||||
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals(Constants.OAUTH_SUPPORTED_TRUE);
|
|
||||||
|
|
||||||
String username = AccountUtils.getUsernameForAccount(account);
|
|
||||||
|
|
||||||
if (isOauth2) {
|
|
||||||
Timber.i("Trying to retrieve credentials for oAuth account" + account.name);
|
|
||||||
String accessToken = am.blockingGetAuthToken(
|
|
||||||
account,
|
|
||||||
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
|
|
||||||
false);
|
|
||||||
|
|
||||||
credentials = OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken);
|
|
||||||
} else {
|
|
||||||
String password = am.blockingGetAuthToken(
|
|
||||||
account,
|
|
||||||
AccountTypeUtils.getAuthTokenTypePass(account.type),
|
|
||||||
false);
|
|
||||||
|
|
||||||
credentials = OwnCloudCredentialsFactory.newBasicCredentials(
|
|
||||||
username,
|
|
||||||
password
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return credentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user id corresponding to an OC account.
|
|
||||||
*
|
|
||||||
* @param account ownCloud account
|
|
||||||
* @return user id
|
|
||||||
*/
|
|
||||||
public static String getUserId(Account account, Context context) {
|
|
||||||
AccountManager accountMgr = AccountManager.get(context);
|
|
||||||
return accountMgr.getUserData(account, Constants.KEY_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
|
|
||||||
if (serverBaseUrl.getScheme() == null) {
|
|
||||||
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
|
|
||||||
}
|
|
||||||
String accountName = username + "@" + serverBaseUrl.getHost();
|
|
||||||
if (serverBaseUrl.getPort() >= 0) {
|
|
||||||
accountName += ":" + serverBaseUrl.getPort();
|
|
||||||
}
|
|
||||||
return accountName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String buildAccountName(Uri serverBaseUrl, String username) {
|
|
||||||
if (serverBaseUrl.getScheme() == null) {
|
|
||||||
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove http:// or https://
|
|
||||||
String url = serverBaseUrl.toString();
|
|
||||||
if (url.contains("://")) {
|
|
||||||
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return username + "@" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AccountNotFoundException extends AccountsException {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generated - should be refreshed every time the class changes!!
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -1684392454798508693L;
|
|
||||||
|
|
||||||
private Account mFailedAccount;
|
|
||||||
|
|
||||||
public AccountNotFoundException(Account failedAccount, String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
mFailedAccount = failedAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Account getFailedAccount() {
|
|
||||||
return mFailedAccount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Constants {
|
|
||||||
/**
|
|
||||||
* Base url should point to owncloud installation without trailing / ie:
|
|
||||||
* http://server/path or https://owncloud.server
|
|
||||||
*/
|
|
||||||
public static final String KEY_OC_BASE_URL = "oc_base_url";
|
|
||||||
/**
|
|
||||||
* Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO Please review this constants, move them out of the library, the rest of OAuth variables are in data layer
|
|
||||||
public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
|
|
||||||
|
|
||||||
public static final String OAUTH_SUPPORTED_TRUE = "TRUE";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OC account version
|
|
||||||
*/
|
|
||||||
public static final String KEY_OC_ACCOUNT_VERSION = "oc_account_version";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User's id
|
|
||||||
*/
|
|
||||||
public static final String KEY_ID = "oc_id";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User's display name
|
|
||||||
*/
|
|
||||||
public static final String KEY_DISPLAY_NAME = "oc_display_name";
|
|
||||||
|
|
||||||
public static final int ACCOUNT_VERSION = 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/* 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.common.http
|
|
||||||
|
|
||||||
import okhttp3.Cookie
|
|
||||||
import okhttp3.CookieJar
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
|
|
||||||
class CookieJarImpl(
|
|
||||||
private val cookieStore: HashMap<String, List<Cookie>>
|
|
||||||
) : CookieJar {
|
|
||||||
|
|
||||||
fun containsCookieWithName(cookies: List<Cookie>, name: String): Boolean {
|
|
||||||
for (cookie: Cookie in cookies) {
|
|
||||||
if (cookie.name == name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getUpdatedCookies(oldCookies: List<Cookie>, newCookies: List<Cookie>): List<Cookie> {
|
|
||||||
val updatedList = ArrayList<Cookie>(newCookies)
|
|
||||||
for (oldCookie: Cookie in oldCookies) {
|
|
||||||
if (!containsCookieWithName(updatedList, oldCookie.name)) {
|
|
||||||
updatedList.add(oldCookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return updatedList
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
|
||||||
// Avoid duplicated cookies but update
|
|
||||||
val currentCookies: List<Cookie> = cookieStore[url.host] ?: ArrayList()
|
|
||||||
val updatedCookies: List<Cookie> = getUpdatedCookies(currentCookies, cookies)
|
|
||||||
cookieStore[url.host] = updatedCookies
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadForRequest(url: HttpUrl) =
|
|
||||||
cookieStore[url.host] ?: ArrayList()
|
|
||||||
}
|
|
@ -1,31 +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.http
|
|
||||||
|
|
||||||
import okhttp3.Interceptor
|
|
||||||
|
|
||||||
class DummyInterceptor : Interceptor {
|
|
||||||
override fun intercept(chain: Interceptor.Chain) = chain.proceed(chain.request())
|
|
||||||
}
|
|
@ -1,147 +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.http;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.network.AdvancedX509TrustManager;
|
|
||||||
import com.owncloud.android.lib.common.network.NetworkUtils;
|
|
||||||
import okhttp3.Cookie;
|
|
||||||
import okhttp3.CookieJar;
|
|
||||||
import okhttp3.HttpUrl;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Protocol;
|
|
||||||
import okhttp3.TlsVersion;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client used to perform network operations
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class HttpClient {
|
|
||||||
private Context mContext;
|
|
||||||
private HashMap<String, List<Cookie>> mCookieStore = new HashMap<>();
|
|
||||||
private LogInterceptor mLogInterceptor = new LogInterceptor();
|
|
||||||
|
|
||||||
private OkHttpClient mOkHttpClient = null;
|
|
||||||
|
|
||||||
protected HttpClient(Context context) {
|
|
||||||
if (context == null) {
|
|
||||||
Timber.e("Context may not be NULL!");
|
|
||||||
throw new NullPointerException("Context may not be NULL!");
|
|
||||||
}
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OkHttpClient getOkHttpClient() {
|
|
||||||
if (mOkHttpClient == null) {
|
|
||||||
try {
|
|
||||||
final X509TrustManager trustManager = new AdvancedX509TrustManager(
|
|
||||||
NetworkUtils.getKnownServersStore(mContext));
|
|
||||||
|
|
||||||
final SSLContext sslContext = buildSSLContext();
|
|
||||||
sslContext.init(null, new TrustManager[]{trustManager}, null);
|
|
||||||
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
|
||||||
|
|
||||||
// Automatic cookie handling, NOT PERSISTENT
|
|
||||||
final CookieJar cookieJar = new CookieJarImpl(mCookieStore);
|
|
||||||
mOkHttpClient = buildNewOkHttpClient(sslSocketFactory, trustManager, cookieJar);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException nsae) {
|
|
||||||
Timber.e(nsae, "Could not setup SSL system.");
|
|
||||||
throw new RuntimeException("Could not setup okHttp client.", nsae);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e, "Could not setup okHttp client.");
|
|
||||||
throw new RuntimeException("Could not setup okHttp client.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mOkHttpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SSLContext buildSSLContext() throws NoSuchAlgorithmException {
|
|
||||||
try {
|
|
||||||
return SSLContext.getInstance(TlsVersion.TLS_1_3.javaName());
|
|
||||||
} catch (NoSuchAlgorithmException tlsv13Exception) {
|
|
||||||
try {
|
|
||||||
Timber.w("TLSv1.3 is not supported in this device; falling through TLSv1.2");
|
|
||||||
return SSLContext.getInstance(TlsVersion.TLS_1_2.javaName());
|
|
||||||
} catch (NoSuchAlgorithmException tlsv12Exception) {
|
|
||||||
try {
|
|
||||||
Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1");
|
|
||||||
return SSLContext.getInstance(TlsVersion.TLS_1_1.javaName());
|
|
||||||
} catch (NoSuchAlgorithmException tlsv11Exception) {
|
|
||||||
Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0");
|
|
||||||
return SSLContext.getInstance(TlsVersion.TLS_1_0.javaName());
|
|
||||||
// should be available in any device; see reference of supported protocols in
|
|
||||||
// http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OkHttpClient buildNewOkHttpClient(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager,
|
|
||||||
CookieJar cookieJar) {
|
|
||||||
return new OkHttpClient.Builder()
|
|
||||||
.addNetworkInterceptor(getLogInterceptor())
|
|
||||||
.addNetworkInterceptor(DebugInterceptorFactory.INSTANCE.getInterceptor())
|
|
||||||
.protocols(Collections.singletonList(Protocol.HTTP_1_1))
|
|
||||||
.readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
.writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
.connectTimeout(HttpConstants.DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
.followRedirects(false)
|
|
||||||
.sslSocketFactory(sslSocketFactory, trustManager)
|
|
||||||
.hostnameVerifier((asdf, usdf) -> true)
|
|
||||||
.cookieJar(cookieJar)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context getContext() {
|
|
||||||
return mContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogInterceptor getLogInterceptor() {
|
|
||||||
return mLogInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
|
|
||||||
return mCookieStore.get(httpUrl.host());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCookies() {
|
|
||||||
mCookieStore.clear();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +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.http
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_JSON
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_WWW_FORM
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_XML
|
|
||||||
import okhttp3.MediaType
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
object LogBuilder {
|
|
||||||
fun logHttp(
|
|
||||||
networkPetition: NetworkPetition,
|
|
||||||
networkNode: NetworkNode,
|
|
||||||
requestId: String? = "",
|
|
||||||
description: String
|
|
||||||
) = Timber.d("[Network, $networkPetition] [$networkNode] [$requestId] $description")
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class NetworkPetition {
|
|
||||||
REQUEST, RESPONSE;
|
|
||||||
|
|
||||||
override fun toString(): String = super.toString().lowercase(Locale.ROOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class NetworkNode {
|
|
||||||
INFO, HEADER, BODY;
|
|
||||||
|
|
||||||
override fun toString(): String = super.toString().lowercase(Locale.ROOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether a media type is loggable.
|
|
||||||
*
|
|
||||||
* @return true if its type is text, xml, json, or x-www-form-urlencoded.
|
|
||||||
*/
|
|
||||||
fun MediaType?.isLoggable(): Boolean =
|
|
||||||
this?.let { mediaType ->
|
|
||||||
val mediaTypeString = mediaType.toString()
|
|
||||||
(mediaType.type == "text" ||
|
|
||||||
mediaTypeString.contains(CONTENT_TYPE_XML) ||
|
|
||||||
mediaTypeString.contains(CONTENT_TYPE_JSON) ||
|
|
||||||
mediaTypeString.contains(CONTENT_TYPE_WWW_FORM))
|
|
||||||
} ?: false
|
|
@ -1,179 +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.http
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID
|
|
||||||
import com.owncloud.android.lib.common.http.LogBuilder.logHttp
|
|
||||||
import com.owncloud.android.lib.common.http.NetworkNode.BODY
|
|
||||||
import com.owncloud.android.lib.common.http.NetworkNode.HEADER
|
|
||||||
import com.owncloud.android.lib.common.http.NetworkNode.INFO
|
|
||||||
import com.owncloud.android.lib.common.http.NetworkPetition.REQUEST
|
|
||||||
import com.owncloud.android.lib.common.http.NetworkPetition.RESPONSE
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import okhttp3.Response
|
|
||||||
import okhttp3.ResponseBody
|
|
||||||
import okio.Buffer
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
import java.nio.charset.StandardCharsets
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class LogInterceptor : Interceptor {
|
|
||||||
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
|
||||||
|
|
||||||
if (!httpLogsEnabled) {
|
|
||||||
return chain.proceed(chain.request())
|
|
||||||
}
|
|
||||||
|
|
||||||
val request = chain.request().also {
|
|
||||||
val requestId = it.headers[OC_X_REQUEST_ID]
|
|
||||||
logHttp(REQUEST, INFO, requestId, "Method: ${it.method} URL: ${it.url}")
|
|
||||||
logHeaders(requestId, it.headers, REQUEST)
|
|
||||||
logRequestBody(requestId, it.body)
|
|
||||||
}
|
|
||||||
|
|
||||||
val response = chain.proceed(request)
|
|
||||||
|
|
||||||
return response.also {
|
|
||||||
val requestId = it.request.headers[OC_X_REQUEST_ID]
|
|
||||||
logHttp(
|
|
||||||
RESPONSE,
|
|
||||||
INFO,
|
|
||||||
requestId,
|
|
||||||
"Method: ${request.method} URL: ${request.url} Code: ${it.code} Message: ${it.message}"
|
|
||||||
)
|
|
||||||
logHeaders(requestId, it.headers, RESPONSE)
|
|
||||||
logResponseBody(requestId, it.body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun logHeaders(requestId: String?, headers: Headers, networkPetition: NetworkPetition) {
|
|
||||||
headers.forEach { header ->
|
|
||||||
val headerValue: String = if (header.first.equals(AUTHORIZATION_HEADER, true)) {
|
|
||||||
"[redacted]"
|
|
||||||
} else {
|
|
||||||
header.second
|
|
||||||
}
|
|
||||||
logHttp(networkPetition, HEADER, requestId, "${header.first}: $headerValue")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun logRequestBody(requestId: String?, requestBodyParam: RequestBody?) {
|
|
||||||
requestBodyParam?.let { requestBody ->
|
|
||||||
|
|
||||||
if (requestBody.isOneShot()) {
|
|
||||||
logHttp(REQUEST, BODY, requestId, "One shot body -- Omitted")
|
|
||||||
return@let
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestBody.isDuplex()) {
|
|
||||||
logHttp(REQUEST, BODY, requestId, "Duplex body -- Omitted")
|
|
||||||
return@let
|
|
||||||
}
|
|
||||||
|
|
||||||
val buffer = Buffer()
|
|
||||||
requestBody.writeTo(buffer)
|
|
||||||
|
|
||||||
val contentType = requestBody.contentType()
|
|
||||||
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
|
|
||||||
|
|
||||||
logHttp(REQUEST, BODY, requestId, "Length: ${requestBody.contentLength()} byte body")
|
|
||||||
logHttp(REQUEST, BODY, requestId, "Type: ${requestBody.contentType()}")
|
|
||||||
logHttp(REQUEST, BODY, requestId, "--> Body start for request")
|
|
||||||
|
|
||||||
if (contentType.isLoggable()) {
|
|
||||||
if (requestBody.contentLength() < LIMIT_BODY_LOG) {
|
|
||||||
logHttp(REQUEST, BODY, requestId, buffer.readString(charset))
|
|
||||||
} else {
|
|
||||||
logHttp(REQUEST, BODY, requestId, buffer.readString(LIMIT_BODY_LOG, charset))
|
|
||||||
}
|
|
||||||
logHttp(
|
|
||||||
REQUEST,
|
|
||||||
BODY,
|
|
||||||
requestId,
|
|
||||||
"<-- Body end for request -- Omitted: ${max(0, requestBody.contentLength() - LIMIT_BODY_LOG)} bytes"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
logHttp(
|
|
||||||
REQUEST,
|
|
||||||
BODY,
|
|
||||||
requestId,
|
|
||||||
"<-- Body end for request -- Binary -- Omitted: ${requestBody.contentLength()} bytes"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
} ?: logHttp(REQUEST, BODY, requestId, "Empty body")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun logResponseBody(requestId: String?, responseBodyParam: ResponseBody?) {
|
|
||||||
responseBodyParam?.let { responseBody ->
|
|
||||||
|
|
||||||
val contentType = responseBody.contentType()
|
|
||||||
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
|
|
||||||
|
|
||||||
logHttp(RESPONSE, BODY, requestId, "Length: ${responseBody.contentLength()} byte body")
|
|
||||||
logHttp(RESPONSE, BODY, requestId, "Type: ${responseBody.contentType()}")
|
|
||||||
logHttp(RESPONSE, BODY, requestId, "--> Body start for response")
|
|
||||||
|
|
||||||
val source = responseBody.source()
|
|
||||||
source.request(LIMIT_BODY_LOG)
|
|
||||||
val buffer = source.buffer
|
|
||||||
|
|
||||||
if (contentType.isLoggable()) {
|
|
||||||
|
|
||||||
if (responseBody.contentLength() < LIMIT_BODY_LOG) {
|
|
||||||
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(charset))
|
|
||||||
} else {
|
|
||||||
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(LIMIT_BODY_LOG, charset))
|
|
||||||
}
|
|
||||||
logHttp(
|
|
||||||
RESPONSE,
|
|
||||||
BODY,
|
|
||||||
requestId,
|
|
||||||
"<-- Body end for response -- Omitted: ${
|
|
||||||
max(
|
|
||||||
0,
|
|
||||||
responseBody.contentLength() - LIMIT_BODY_LOG
|
|
||||||
)
|
|
||||||
} bytes"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
logHttp(
|
|
||||||
RESPONSE,
|
|
||||||
BODY,
|
|
||||||
requestId,
|
|
||||||
"<-- Body end for response -- Binary -- Omitted: ${responseBody.contentLength()} bytes"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: logHttp(RESPONSE, BODY, requestId, "Empty body")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var httpLogsEnabled: Boolean = false
|
|
||||||
private const val LIMIT_BODY_LOG: Long = 1024
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +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.http;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class TLSSocketFactory extends SSLSocketFactory {
|
|
||||||
private SSLSocketFactory mInternalSSLSocketFactory;
|
|
||||||
|
|
||||||
public TLSSocketFactory(SSLSocketFactory delegate) {
|
|
||||||
mInternalSSLSocketFactory = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getDefaultCipherSuites() {
|
|
||||||
return mInternalSSLSocketFactory.getDefaultCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedCipherSuites() {
|
|
||||||
return mInternalSSLSocketFactory.getSupportedCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
|
||||||
return enableTLSOnSocket(mInternalSSLSocketFactory.createSocket(s, host, port, autoClose));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port) throws IOException {
|
|
||||||
return enableTLSOnSocket(mInternalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
|
||||||
return enableTLSOnSocket(mInternalSSLSocketFactory.createSocket(host, port, localHost, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
||||||
return enableTLSOnSocket(mInternalSSLSocketFactory.createSocket(host, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws
|
|
||||||
IOException {
|
|
||||||
return enableTLSOnSocket(mInternalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Socket enableTLSOnSocket(Socket socket) {
|
|
||||||
if((socket instanceof SSLSocket)) {
|
|
||||||
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2", "TLSv1.3"});
|
|
||||||
}
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
/* 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.http.methods
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.http.HttpClient
|
|
||||||
import okhttp3.Call
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.net.MalformedURLException
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
abstract class HttpBaseMethod constructor(url: URL) {
|
|
||||||
var httpUrl: HttpUrl = url.toHttpUrlOrNull() ?: throw MalformedURLException()
|
|
||||||
var request: Request
|
|
||||||
var followPermanentRedirects = false
|
|
||||||
abstract var response: Response
|
|
||||||
var call: Call? = null
|
|
||||||
|
|
||||||
var followRedirects: Boolean = true
|
|
||||||
var retryOnConnectionFailure: Boolean = true
|
|
||||||
var connectionTimeoutVal: Long? = null
|
|
||||||
var connectionTimeoutUnit: TimeUnit? = null
|
|
||||||
var readTimeoutVal: Long? = null
|
|
||||||
private set
|
|
||||||
var readTimeoutUnit: TimeUnit? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
|
||||||
request = Request.Builder()
|
|
||||||
.url(httpUrl)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
open fun execute(httpClient: HttpClient): Int {
|
|
||||||
val okHttpClient = httpClient.okHttpClient.newBuilder().apply {
|
|
||||||
retryOnConnectionFailure(retryOnConnectionFailure)
|
|
||||||
followRedirects(followRedirects)
|
|
||||||
readTimeoutUnit?.let { unit ->
|
|
||||||
readTimeoutVal?.let { readTimeout(it, unit) }
|
|
||||||
}
|
|
||||||
connectionTimeoutUnit?.let { unit ->
|
|
||||||
connectionTimeoutVal?.let { connectTimeout(it, unit) }
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
return onExecute(okHttpClient)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun setUrl(url: HttpUrl) {
|
|
||||||
request = request.newBuilder()
|
|
||||||
.url(url)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************
|
|
||||||
*** Requests ***
|
|
||||||
****************/
|
|
||||||
|
|
||||||
fun getRequestHeader(name: String): String? {
|
|
||||||
return request.header(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRequestHeadersAsHashMap(): HashMap<String, String?> {
|
|
||||||
val headers: HashMap<String, String?> = HashMap()
|
|
||||||
val superHeaders: Set<String> = request.headers.names()
|
|
||||||
superHeaders.forEach {
|
|
||||||
headers[it] = getRequestHeader(it)
|
|
||||||
}
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun addRequestHeader(name: String, value: String) {
|
|
||||||
request = request.newBuilder()
|
|
||||||
.addHeader(name, value)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a header and replace it if already exists with that name
|
|
||||||
*
|
|
||||||
* @param name header name
|
|
||||||
* @param value header value
|
|
||||||
*/
|
|
||||||
open fun setRequestHeader(name: String, value: String) {
|
|
||||||
request = request.newBuilder()
|
|
||||||
.header(name, value)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************
|
|
||||||
*** Response ***
|
|
||||||
****************/
|
|
||||||
val statusCode: Int
|
|
||||||
get() = response.code
|
|
||||||
|
|
||||||
val statusMessage: String
|
|
||||||
get() = response.message
|
|
||||||
|
|
||||||
// Headers
|
|
||||||
open fun getResponseHeaders(): Headers? {
|
|
||||||
return response.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun getResponseHeader(headerName: String): String? {
|
|
||||||
return response.header(headerName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Body
|
|
||||||
fun getResponseBodyAsString(): String? = response.body?.string()
|
|
||||||
|
|
||||||
open fun getResponseBodyAsStream(): InputStream? {
|
|
||||||
return response.body?.byteStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the final url after following the last redirect.
|
|
||||||
*/
|
|
||||||
open fun getFinalUrl() = response.request.url
|
|
||||||
|
|
||||||
/*************************
|
|
||||||
*** Connection Params ***
|
|
||||||
*************************/
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
// Setter
|
|
||||||
//////////////////////////////
|
|
||||||
// Connection parameters
|
|
||||||
|
|
||||||
|
|
||||||
open fun setReadTimeout(readTimeout: Long, timeUnit: TimeUnit) {
|
|
||||||
readTimeoutVal = readTimeout
|
|
||||||
readTimeoutUnit = timeUnit
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun setConnectionTimeout(
|
|
||||||
connectionTimeout: Long,
|
|
||||||
timeUnit: TimeUnit
|
|
||||||
) {
|
|
||||||
connectionTimeoutVal = connectionTimeout
|
|
||||||
connectionTimeoutUnit = timeUnit
|
|
||||||
}
|
|
||||||
|
|
||||||
/************
|
|
||||||
*** Call ***
|
|
||||||
************/
|
|
||||||
open fun abort() {
|
|
||||||
call?.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
open val isAborted: Boolean
|
|
||||||
get() = call?.isCanceled() ?: false
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
// For override
|
|
||||||
//////////////////////////////
|
|
||||||
@Throws(Exception::class)
|
|
||||||
protected abstract fun onExecute(okHttpClient: OkHttpClient): Int
|
|
||||||
}
|
|
@ -1,47 +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.http.methods.nonwebdav
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OkHttp put calls wrapper
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
class PutMethod(
|
|
||||||
url: URL,
|
|
||||||
private val putRequestBody: RequestBody
|
|
||||||
) : HttpMethod(url) {
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun onExecute(okHttpClient: OkHttpClient): Int {
|
|
||||||
request = request.newBuilder()
|
|
||||||
.put(putRequestBody)
|
|
||||||
.build()
|
|
||||||
return super.onExecute(okHttpClient)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +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.http.methods.webdav
|
|
||||||
|
|
||||||
import at.bitfire.dav4jvm.Dav4jvm.log
|
|
||||||
import at.bitfire.dav4jvm.DavOCResource
|
|
||||||
import at.bitfire.dav4jvm.exception.HttpException
|
|
||||||
import at.bitfire.dav4jvm.exception.RedirectException
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Protocol
|
|
||||||
import okhttp3.Response
|
|
||||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper to perform WebDAV (dav4android) calls
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
abstract class DavMethod protected constructor(url: URL) : HttpBaseMethod(url) {
|
|
||||||
override lateinit var response: Response
|
|
||||||
private var davResource: DavOCResource? = null
|
|
||||||
|
|
||||||
override fun abort() {
|
|
||||||
davResource?.cancelCall()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract fun onDavExecute(davResource: DavOCResource): Int
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun onExecute(okHttpClient: OkHttpClient): Int {
|
|
||||||
return try {
|
|
||||||
davResource = DavOCResource(
|
|
||||||
okHttpClient.newBuilder().followRedirects(false).build(),
|
|
||||||
httpUrl,
|
|
||||||
log
|
|
||||||
)
|
|
||||||
|
|
||||||
onDavExecute(davResource!!)
|
|
||||||
} catch (httpException: HttpException) {
|
|
||||||
// Modify responses with information gathered from exceptions
|
|
||||||
if (httpException is RedirectException) {
|
|
||||||
response = Response.Builder()
|
|
||||||
.header(
|
|
||||||
HttpConstants.LOCATION_HEADER, httpException.redirectLocation
|
|
||||||
)
|
|
||||||
.code(httpException.code)
|
|
||||||
.request(request)
|
|
||||||
.message(httpException.message ?: "")
|
|
||||||
.protocol(Protocol.HTTP_1_1)
|
|
||||||
.build()
|
|
||||||
} else {
|
|
||||||
// The check below should be included in okhttp library, method ResponseBody.create(
|
|
||||||
// TODO check most recent versions of okhttp to see if this is already fixed and try to update if so
|
|
||||||
if (response.body?.contentType() != null) {
|
|
||||||
val responseBody = (httpException.responseBody ?: "").toResponseBody(response.body?.contentType())
|
|
||||||
response = response.newBuilder()
|
|
||||||
.body(responseBody)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
httpException.code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
// Getter
|
|
||||||
//////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
override val isAborted: Boolean
|
|
||||||
get() = davResource?.isCallAborted() ?: false
|
|
||||||
|
|
||||||
}
|
|
@ -1,60 +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.http.methods.webdav
|
|
||||||
|
|
||||||
import at.bitfire.dav4jvm.Property
|
|
||||||
import at.bitfire.dav4jvm.PropertyUtils.getQuotaPropset
|
|
||||||
import at.bitfire.dav4jvm.property.CreationDate
|
|
||||||
import at.bitfire.dav4jvm.property.DisplayName
|
|
||||||
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.ResourceType
|
|
||||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes
|
|
||||||
|
|
||||||
object DavUtils {
|
|
||||||
@JvmStatic val allPropSet: Array<Property.Name>
|
|
||||||
get() = arrayOf(
|
|
||||||
DisplayName.NAME,
|
|
||||||
GetContentType.NAME,
|
|
||||||
ResourceType.NAME,
|
|
||||||
GetContentLength.NAME,
|
|
||||||
GetLastModified.NAME,
|
|
||||||
CreationDate.NAME,
|
|
||||||
GetETag.NAME,
|
|
||||||
OCPermissions.NAME,
|
|
||||||
OCId.NAME,
|
|
||||||
OCSize.NAME,
|
|
||||||
OCPrivatelink.NAME,
|
|
||||||
OCShareTypes.NAME,
|
|
||||||
)
|
|
||||||
|
|
||||||
val quotaPropSet: Array<Property.Name>
|
|
||||||
get() = getQuotaPropset()
|
|
||||||
}
|
|
@ -1,73 +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.http.methods.webdav
|
|
||||||
|
|
||||||
import at.bitfire.dav4jvm.DavOCResource
|
|
||||||
import at.bitfire.dav4jvm.Property
|
|
||||||
import at.bitfire.dav4jvm.Response
|
|
||||||
import at.bitfire.dav4jvm.Response.HrefRelation
|
|
||||||
import at.bitfire.dav4jvm.exception.DavException
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Propfind calls wrapper
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
class PropfindMethod(
|
|
||||||
url: URL,
|
|
||||||
private val depth: Int,
|
|
||||||
private val propertiesToRequest: Array<Property.Name>
|
|
||||||
) : DavMethod(url) {
|
|
||||||
|
|
||||||
// response
|
|
||||||
val members: MutableList<Response>
|
|
||||||
var root: Response?
|
|
||||||
private set
|
|
||||||
|
|
||||||
@Throws(IOException::class, DavException::class)
|
|
||||||
public override fun onDavExecute(davResource: DavOCResource): Int {
|
|
||||||
davResource.propfind(
|
|
||||||
depth = depth,
|
|
||||||
reqProp = propertiesToRequest,
|
|
||||||
listOfHeaders = super.getRequestHeadersAsHashMap(),
|
|
||||||
callback = { response: Response, hrefRelation: HrefRelation ->
|
|
||||||
when (hrefRelation) {
|
|
||||||
HrefRelation.MEMBER -> members.add(response)
|
|
||||||
HrefRelation.SELF -> this.root = response
|
|
||||||
HrefRelation.OTHER -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, rawCallback = { callBackResponse: okhttp3.Response ->
|
|
||||||
response = callBackResponse
|
|
||||||
})
|
|
||||||
return statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
members = arrayListOf()
|
|
||||||
this.root = null
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/* 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.http.methods.webdav.properties
|
|
||||||
|
|
||||||
import at.bitfire.dav4jvm.Property
|
|
||||||
import at.bitfire.dav4jvm.PropertyFactory
|
|
||||||
import at.bitfire.dav4jvm.XmlUtils
|
|
||||||
import org.xmlpull.v1.XmlPullParser
|
|
||||||
import java.util.LinkedList
|
|
||||||
|
|
||||||
abstract class ShareTypeListProperty : Property {
|
|
||||||
|
|
||||||
val shareTypes = LinkedList<String>()
|
|
||||||
|
|
||||||
override fun toString() = "share types =[" + shareTypes.joinToString(", ") + "]"
|
|
||||||
|
|
||||||
abstract class Factory : PropertyFactory {
|
|
||||||
|
|
||||||
fun create(parser: XmlPullParser, list: ShareTypeListProperty): ShareTypeListProperty {
|
|
||||||
XmlUtils.readTextPropertyList(parser, Property.Name(XmlUtils.NS_OWNCLOUD, "share-type"), list.shareTypes)
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
/* 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,97 +0,0 @@
|
|||||||
/* 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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2017 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.operations;
|
|
||||||
|
|
||||||
import android.util.Xml;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
import org.xmlpull.v1.XmlPullParserFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parser for server exceptions
|
|
||||||
*
|
|
||||||
* @author davidgonzalez
|
|
||||||
*/
|
|
||||||
public class ErrorMessageParser {
|
|
||||||
// No namespaces
|
|
||||||
private static final String ns = null;
|
|
||||||
|
|
||||||
// Nodes for XML Parser
|
|
||||||
private static final String NODE_ERROR = "d:error";
|
|
||||||
private static final String NODE_MESSAGE = "s:message";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse exception response
|
|
||||||
*
|
|
||||||
* @param is
|
|
||||||
* @return errorMessage for an exception
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public String parseXMLResponse(InputStream is) throws XmlPullParserException,
|
|
||||||
IOException {
|
|
||||||
String errorMessage = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
// XMLPullParser
|
|
||||||
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
|
|
||||||
factory.setNamespaceAware(true);
|
|
||||||
|
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
|
||||||
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
|
|
||||||
parser.setInput(is, null);
|
|
||||||
parser.nextTag();
|
|
||||||
errorMessage = readError(parser);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse OCS node
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @return reason for exception
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private String readError(XmlPullParser parser) throws XmlPullParserException, IOException {
|
|
||||||
String errorMessage = "";
|
|
||||||
parser.require(XmlPullParser.START_TAG, ns, NODE_ERROR);
|
|
||||||
while (parser.next() != XmlPullParser.END_TAG) {
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = parser.getName();
|
|
||||||
// read NODE_MESSAGE
|
|
||||||
if (name.equalsIgnoreCase(NODE_MESSAGE)) {
|
|
||||||
errorMessage = readText(parser);
|
|
||||||
} else {
|
|
||||||
skip(parser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip tags in parser procedure
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
int depth = 1;
|
|
||||||
while (depth != 0) {
|
|
||||||
switch (parser.next()) {
|
|
||||||
case XmlPullParser.END_TAG:
|
|
||||||
depth--;
|
|
||||||
break;
|
|
||||||
case XmlPullParser.START_TAG:
|
|
||||||
depth++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the text from a node
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @return Text of the node
|
|
||||||
* @throws IOException
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
*/
|
|
||||||
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
|
||||||
String result = "";
|
|
||||||
if (parser.next() == XmlPullParser.TEXT) {
|
|
||||||
result = parser.getText();
|
|
||||||
parser.nextTag();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +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.common.operations;
|
|
||||||
|
|
||||||
import android.util.Xml;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
import org.xmlpull.v1.XmlPullParserFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parser for Invalid Character server exception
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
public class InvalidCharacterExceptionParser {
|
|
||||||
|
|
||||||
private static final String EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath";
|
|
||||||
private static final String EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
|
|
||||||
|
|
||||||
// No namespaces
|
|
||||||
private static final String ns = null;
|
|
||||||
|
|
||||||
// Nodes for XML Parser
|
|
||||||
private static final String NODE_ERROR = "d:error";
|
|
||||||
private static final String NODE_EXCEPTION = "s:exception";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse is as an Invalid Path Exception
|
|
||||||
*
|
|
||||||
* @param is
|
|
||||||
* @return if The exception is an Invalid Char Exception
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public boolean parseXMLResponse(InputStream is) throws XmlPullParserException,
|
|
||||||
IOException {
|
|
||||||
boolean result = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// XMLPullParser
|
|
||||||
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
|
|
||||||
factory.setNamespaceAware(true);
|
|
||||||
|
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
|
||||||
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
|
|
||||||
parser.setInput(is, null);
|
|
||||||
parser.nextTag();
|
|
||||||
result = readError(parser);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse OCS node
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @return List of ShareRemoteFiles
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private boolean readError(XmlPullParser parser) throws XmlPullParserException, IOException {
|
|
||||||
String exception = "";
|
|
||||||
parser.require(XmlPullParser.START_TAG, ns, NODE_ERROR);
|
|
||||||
while (parser.next() != XmlPullParser.END_TAG) {
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = parser.getName();
|
|
||||||
// read NODE_EXCEPTION
|
|
||||||
if (name.equalsIgnoreCase(NODE_EXCEPTION)) {
|
|
||||||
exception = readText(parser);
|
|
||||||
} else {
|
|
||||||
skip(parser);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return exception.equalsIgnoreCase(EXCEPTION_STRING) ||
|
|
||||||
exception.equalsIgnoreCase(EXCEPTION_UPLOAD_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip tags in parser procedure
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
int depth = 1;
|
|
||||||
while (depth != 0) {
|
|
||||||
switch (parser.next()) {
|
|
||||||
case XmlPullParser.END_TAG:
|
|
||||||
depth--;
|
|
||||||
break;
|
|
||||||
case XmlPullParser.START_TAG:
|
|
||||||
depth++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the text from a node
|
|
||||||
*
|
|
||||||
* @param parser
|
|
||||||
* @return Text of the node
|
|
||||||
* @throws IOException
|
|
||||||
* @throws XmlPullParserException
|
|
||||||
*/
|
|
||||||
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
|
||||||
String result = "";
|
|
||||||
if (parser.next() == XmlPullParser.TEXT) {
|
|
||||||
result = parser.getText();
|
|
||||||
parser.nextTag();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +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.utils
|
|
||||||
|
|
||||||
fun Any.isOneOf(vararg values: Any): Boolean {
|
|
||||||
return this in values
|
|
||||||
}
|
|
@ -1,52 +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
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
// Response retrieved by OCS Rest API, used to obtain capabilities, shares and user info among others.
|
|
||||||
// More info: https://doc.owncloud.com/server/developer_manual/core/apis/ocs-capabilities.html
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class CommonOcsResponse<T>(
|
|
||||||
val ocs: OCSResponse<T>
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class OCSResponse<T>(
|
|
||||||
val meta: MetaData,
|
|
||||||
val data: T?
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class MetaData(
|
|
||||||
val status: String,
|
|
||||||
@Json(name = "statuscode")
|
|
||||||
val statusCode: Int,
|
|
||||||
val message: String?,
|
|
||||||
@Json(name = "itemsperpage")
|
|
||||||
val itemsPerPage: String?,
|
|
||||||
@Json(name = "totalitems")
|
|
||||||
val totalItems: String?
|
|
||||||
)
|
|
@ -1,108 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.appregistry
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
|
|
||||||
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.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class CreateRemoteFileWithAppProviderOperation(
|
|
||||||
private val createFileWithAppProviderEndpoint: String,
|
|
||||||
private val parentContainerId: String,
|
|
||||||
private val filename: String,
|
|
||||||
) : RemoteOperation<String>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
|
|
||||||
return try {
|
|
||||||
|
|
||||||
val createFileWithAppProviderRequestBody = CreateFileWithAppProviderParams(parentContainerId, filename)
|
|
||||||
.toRequestBody()
|
|
||||||
|
|
||||||
val stringUrl = client.baseUri.toString() + WebdavUtils.encodePath(createFileWithAppProviderEndpoint)
|
|
||||||
|
|
||||||
val postMethod = PostMethod(URL(stringUrl), createFileWithAppProviderRequestBody).apply {
|
|
||||||
setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
}
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(postMethod)
|
|
||||||
Timber.d("Create file $filename with app provider in folder with ID $parentContainerId - $status${if (!isSuccess(status)) "(FAIL)" else ""}")
|
|
||||||
|
|
||||||
if (isSuccess(status)) RemoteOperationResult<String>(ResultCode.OK).apply {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val adapter: JsonAdapter<CreateFileWithAppProviderResponse> = moshi.adapter(CreateFileWithAppProviderResponse::class.java)
|
|
||||||
|
|
||||||
data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.fileId }
|
|
||||||
}
|
|
||||||
else RemoteOperationResult<String>(postMethod).apply { data = "" }
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
val result = RemoteOperationResult<String>(e)
|
|
||||||
Timber.e(e, "Create file $filename with app provider in folder with ID $parentContainerId failed")
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
data class CreateFileWithAppProviderParams(
|
|
||||||
val parentContainerId: String,
|
|
||||||
val filename: String,
|
|
||||||
) {
|
|
||||||
fun toRequestBody(): RequestBody =
|
|
||||||
FormBody.Builder()
|
|
||||||
.add(PARAM_PARENT_CONTAINER_ID, parentContainerId)
|
|
||||||
.add(PARAM_FILENAME, filename)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PARAM_PARENT_CONTAINER_ID = "parent_container_id"
|
|
||||||
const val PARAM_FILENAME = "filename"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class CreateFileWithAppProviderResponse(
|
|
||||||
@Json(name = "file_id")
|
|
||||||
val fileId: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TIMEOUT: Long = 5_000
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 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.appregistry
|
|
||||||
|
|
||||||
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.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
|
|
||||||
import com.owncloud.android.lib.resources.appregistry.responses.AppRegistryResponse
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class GetRemoteAppRegistryOperation(private val appUrl: String?) : RemoteOperation<AppRegistryResponse>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<AppRegistryResponse> {
|
|
||||||
var result: RemoteOperationResult<AppRegistryResponse>
|
|
||||||
|
|
||||||
try {
|
|
||||||
val uriBuilder = client.baseUri.buildUpon().apply {
|
|
||||||
appendEncodedPath(appUrl)
|
|
||||||
}
|
|
||||||
val getMethod = GetMethod(URL(uriBuilder.build().toString()))
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
|
|
||||||
val response = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (status == HttpConstants.HTTP_OK) {
|
|
||||||
Timber.d("Successful response $response")
|
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
val moshi: Moshi = Moshi.Builder().build()
|
|
||||||
val adapter: JsonAdapter<AppRegistryResponse> = moshi.adapter(AppRegistryResponse::class.java)
|
|
||||||
val appRegistryResponse: AppRegistryResponse = response?.let { adapter.fromJson(it) } ?: AppRegistryResponse(value = emptyList())
|
|
||||||
|
|
||||||
result = RemoteOperationResult(OK)
|
|
||||||
result.data = appRegistryResponse
|
|
||||||
|
|
||||||
Timber.d("Get AppRegistry completed and parsed to ${result.data}")
|
|
||||||
} else {
|
|
||||||
result = RemoteOperationResult(getMethod)
|
|
||||||
Timber.e("Failed response while getting app registry from the server status code: $status; response message: $response")
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
result = RemoteOperationResult(e)
|
|
||||||
Timber.e(e, "Exception while getting app registry")
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.appregistry
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
|
|
||||||
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.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class GetUrlToOpenInWebRemoteOperation(
|
|
||||||
private val openWithWebEndpoint: String,
|
|
||||||
private val fileId: String,
|
|
||||||
private val appName: String,
|
|
||||||
) : RemoteOperation<String>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
|
|
||||||
return try {
|
|
||||||
|
|
||||||
val openInWebRequestBody = OpenInWebParams(fileId, appName).toRequestBody()
|
|
||||||
|
|
||||||
val stringUrl =
|
|
||||||
client.baseUri.toString() + WebdavUtils.encodePath(openWithWebEndpoint)
|
|
||||||
|
|
||||||
val postMethod = PostMethod(URL(stringUrl), openInWebRequestBody).apply {
|
|
||||||
setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
}
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(postMethod)
|
|
||||||
Timber.d("Open in web for file: $fileId - $status${if (!isSuccess(status)) "(FAIL)" else ""}")
|
|
||||||
|
|
||||||
if (isSuccess(status)) RemoteOperationResult<String>(ResultCode.OK).apply {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val adapter: JsonAdapter<OpenInWebResponse> = moshi.adapter(OpenInWebResponse::class.java)
|
|
||||||
|
|
||||||
data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.uri }
|
|
||||||
}
|
|
||||||
else RemoteOperationResult<String>(postMethod).apply { data = "" }
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
val result = RemoteOperationResult<String>(e)
|
|
||||||
Timber.e(e, "Open in web for file: $fileId failed")
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
data class OpenInWebParams(
|
|
||||||
val fileId: String,
|
|
||||||
val appName: String,
|
|
||||||
) {
|
|
||||||
fun toRequestBody(): RequestBody =
|
|
||||||
FormBody.Builder()
|
|
||||||
.add(PARAM_FILE_ID, fileId)
|
|
||||||
.add(PARAM_APP_NAME, appName)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PARAM_FILE_ID = "file_id"
|
|
||||||
const val PARAM_APP_NAME = "app_name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class OpenInWebResponse(val uri: String)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Maximum time to wait for a response from the server in milliseconds.
|
|
||||||
*/
|
|
||||||
private const val TIMEOUT = 5_000L
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 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.appregistry.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class AppRegistryResponse(
|
|
||||||
@Json(name = "mime-types")
|
|
||||||
val value: List<AppRegistryMimeTypeResponse>
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class AppRegistryMimeTypeResponse(
|
|
||||||
@Json(name = "mime_type") val mimeType: String,
|
|
||||||
val ext: String? = null,
|
|
||||||
@Json(name = "app_providers")
|
|
||||||
val appProviders: List<AppRegistryProviderResponse>,
|
|
||||||
val name: String? = null,
|
|
||||||
val icon: String? = null,
|
|
||||||
val description: String? = null,
|
|
||||||
@Json(name = "allow_creation")
|
|
||||||
val allowCreation: Boolean? = null,
|
|
||||||
@Json(name = "default_application")
|
|
||||||
val defaultApplication: String? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class AppRegistryProviderResponse(
|
|
||||||
val name: String,
|
|
||||||
val icon: String,
|
|
||||||
)
|
|
@ -1,54 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.appregistry.services
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.appregistry.CreateRemoteFileWithAppProviderOperation
|
|
||||||
import com.owncloud.android.lib.resources.appregistry.GetRemoteAppRegistryOperation
|
|
||||||
import com.owncloud.android.lib.resources.appregistry.GetUrlToOpenInWebRemoteOperation
|
|
||||||
import com.owncloud.android.lib.resources.appregistry.responses.AppRegistryResponse
|
|
||||||
|
|
||||||
class OCAppRegistryService(override val client: OwnCloudClient) : AppRegistryService {
|
|
||||||
override fun getAppRegistry(appUrl: String?): RemoteOperationResult<AppRegistryResponse> =
|
|
||||||
GetRemoteAppRegistryOperation(appUrl).execute(client)
|
|
||||||
|
|
||||||
override fun getUrlToOpenInWeb(openWebEndpoint: String, fileId: String, appName: String): RemoteOperationResult<String> =
|
|
||||||
GetUrlToOpenInWebRemoteOperation(
|
|
||||||
openWithWebEndpoint = openWebEndpoint,
|
|
||||||
fileId = fileId,
|
|
||||||
appName = appName
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun createFileWithAppProvider(
|
|
||||||
createFileWithAppProviderEndpoint: String,
|
|
||||||
parentContainerId: String,
|
|
||||||
filename: String
|
|
||||||
): RemoteOperationResult<String> =
|
|
||||||
CreateRemoteFileWithAppProviderOperation(
|
|
||||||
createFileWithAppProviderEndpoint = createFileWithAppProviderEndpoint,
|
|
||||||
parentContainerId = parentContainerId,
|
|
||||||
filename = filename,
|
|
||||||
).execute(client)
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.DavUtils.allPropSet
|
|
||||||
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.operations.RemoteOperationResult.ResultCode
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operation to check the existence of a path in a remote server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Abel García de Prada
|
|
||||||
* @author Juan Carlos Garrote Gascón
|
|
||||||
*
|
|
||||||
* @param remotePath Path to append to the URL owned by the client instance.
|
|
||||||
* @param isUserLoggedIn When `true`, the username won't be added at the end of the PROPFIND url since is not
|
|
||||||
* needed to check user credentials
|
|
||||||
*/
|
|
||||||
class CheckPathExistenceRemoteOperation(
|
|
||||||
val remotePath: String? = "",
|
|
||||||
val isUserLoggedIn: Boolean,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : RemoteOperation<Boolean>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Boolean> {
|
|
||||||
val baseStringUrl = spaceWebDavUrl ?: if (isUserLoggedIn) client.userFilesWebDavUri.toString() else client.baseFilesWebDavUri.toString()
|
|
||||||
val stringUrl = if (isUserLoggedIn) baseStringUrl + WebdavUtils.encodePath(remotePath) else baseStringUrl
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val propFindMethod = PropfindMethod(URL(stringUrl), 0, allPropSet).apply {
|
|
||||||
setReadTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS)
|
|
||||||
setConnectionTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS)
|
|
||||||
}
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(propFindMethod)
|
|
||||||
/* PROPFIND method
|
|
||||||
* 404 NOT FOUND: path doesn't exist,
|
|
||||||
* 207 MULTI_STATUS: path exists.
|
|
||||||
*/
|
|
||||||
Timber.d(
|
|
||||||
"Existence check for $stringUrl finished with HTTP status $status${if (!isSuccess(status)) "(FAIL)" else ""}"
|
|
||||||
)
|
|
||||||
if (isSuccess(status)) RemoteOperationResult<Boolean>(ResultCode.OK).apply { data = true }
|
|
||||||
else RemoteOperationResult<Boolean>(propFindMethod).apply { data = false }
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
val result = RemoteOperationResult<Boolean>(e)
|
|
||||||
Timber.e(
|
|
||||||
e,
|
|
||||||
"Existence check for $stringUrl : ${result.logMessage}"
|
|
||||||
)
|
|
||||||
result.data = false
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Maximum time to wait for a response from the server in milliseconds.
|
|
||||||
*/
|
|
||||||
private const val TIMEOUT = 10000
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.
|
|
||||||
* @author Juan Carlos Garrote Gascón
|
|
||||||
* @author Manuel Plazas Palacio
|
|
||||||
*
|
|
||||||
* @param sourceRemotePath Remote path of the file/folder to copy.
|
|
||||||
* @param targetRemotePath Remote path desired for the file/folder to copy it.
|
|
||||||
*/
|
|
||||||
class CopyRemoteFileOperation(
|
|
||||||
private val sourceRemotePath: String,
|
|
||||||
private val targetRemotePath: String,
|
|
||||||
private val sourceSpaceWebDavUrl: String? = null,
|
|
||||||
private val targetSpaceWebDavUrl: String? = null,
|
|
||||||
private val forceOverride: Boolean = false,
|
|
||||||
) : 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 == sourceRemotePath && sourceSpaceWebDavUrl == targetSpaceWebDavUrl) {
|
|
||||||
// nothing to do!
|
|
||||||
return RemoteOperationResult(ResultCode.OK)
|
|
||||||
}
|
|
||||||
if (targetRemotePath.startsWith(sourceRemotePath) && sourceSpaceWebDavUrl == targetSpaceWebDavUrl) {
|
|
||||||
return RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// perform remote operation
|
|
||||||
var result: RemoteOperationResult<String>
|
|
||||||
try {
|
|
||||||
val copyMethod = CopyMethod(
|
|
||||||
url = URL((sourceSpaceWebDavUrl ?: client.userFilesWebDavUri.toString()) + WebdavUtils.encodePath(sourceRemotePath)),
|
|
||||||
destinationUrl = (targetSpaceWebDavUrl ?: client.userFilesWebDavUri.toString()) + WebdavUtils.encodePath(targetRemotePath),
|
|
||||||
forceOverride = forceOverride,
|
|
||||||
).apply {
|
|
||||||
addRequestHeaders(this)
|
|
||||||
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 $sourceRemotePath to $targetRemotePath: ${result.logMessage}")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
result = RemoteOperationResult(e)
|
|
||||||
Timber.e(e, "Copy $sourceRemotePath to $targetRemotePath: ${result.logMessage}")
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addRequestHeaders(copyMethod: CopyMethod) {
|
|
||||||
//Adding this because the library has an error with override
|
|
||||||
if (copyMethod.forceOverride) {
|
|
||||||
copyMethod.setRequestHeader(OVERWRITE, TRUE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
private const val OVERWRITE = "overwrite"
|
|
||||||
private const val TRUE = "T"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +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.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,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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.toString()
|
|
||||||
} else {
|
|
||||||
spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
val mkCol = MkColMethod(
|
|
||||||
URL(webDavUri + 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,185 +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.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.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,
|
|
||||||
private val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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 webDavUri = spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
val getMethod = GetMethod(URL(webDavUri + 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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/* 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.DavUtils
|
|
||||||
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod
|
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operation to get the base url, which might differ in case of a redirect.
|
|
||||||
*
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
*/
|
|
||||||
|
|
||||||
class GetBaseUrlRemoteOperation : RemoteOperation<String?>() {
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<String?> {
|
|
||||||
return try {
|
|
||||||
val stringUrl = client.baseFilesWebDavUri.toString()
|
|
||||||
|
|
||||||
val propFindMethod = PropfindMethod(URL(stringUrl), 0, DavUtils.allPropSet).apply {
|
|
||||||
setReadTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
||||||
setConnectionTimeout(TIMEOUT, TimeUnit.SECONDS)
|
|
||||||
}
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(propFindMethod)
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
RemoteOperationResult<String?>(RemoteOperationResult.ResultCode.OK).apply {
|
|
||||||
data = propFindMethod.getFinalUrl().toString()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RemoteOperationResult<String?>(propFindMethod).apply {
|
|
||||||
data = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Could not get actuall (or redirected) base URL from base url (/).")
|
|
||||||
RemoteOperationResult<String?>(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Maximum time to wait for a response from the server in milliseconds.
|
|
||||||
*/
|
|
||||||
private const val TIMEOUT = 10_000L
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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 and space.
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
* @author Juan Carlos Garrote Gascón
|
|
||||||
* @author Manuel Plazas Palacio
|
|
||||||
*
|
|
||||||
* @param sourceRemotePath Remote path of the file/folder to copy.
|
|
||||||
* @param targetRemotePath Remote path desired for the file/folder to copy it.
|
|
||||||
*/
|
|
||||||
open class MoveRemoteFileOperation(
|
|
||||||
private val sourceRemotePath: String,
|
|
||||||
private val targetRemotePath: String,
|
|
||||||
private val spaceWebDavUrl: String? = null,
|
|
||||||
private val forceOverride: Boolean = false,
|
|
||||||
) : 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((spaceWebDavUrl ?: srcWebDavUri.toString()) + WebdavUtils.encodePath(sourceRemotePath)),
|
|
||||||
destinationUrl = (spaceWebDavUrl ?: client.userFilesWebDavUri.toString()) + WebdavUtils.encodePath(targetRemotePath),
|
|
||||||
forceOverride = forceOverride,
|
|
||||||
).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) {
|
|
||||||
//Adding this because the library has an error with override
|
|
||||||
if (moveMethod.forceOverride) {
|
|
||||||
moveMethod.setRequestHeader(OVERWRITE, TRUE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
private const val OVERWRITE = "overwrite"
|
|
||||||
private const val TRUE = "T"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +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.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,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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 = getFinalWebDavUrl(),
|
|
||||||
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)) {
|
|
||||||
val remoteFile = RemoteFile.getRemoteFileFromDav(
|
|
||||||
davResource = propFind.root!!,
|
|
||||||
userId = AccountUtils.getUserId(mAccount, mContext),
|
|
||||||
userName = mAccount.name,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
)
|
|
||||||
|
|
||||||
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 getFinalWebDavUrl(): URL {
|
|
||||||
val baseWebDavUrl = spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
|
|
||||||
return URL(baseWebDavUrl + WebdavUtils.encodePath(remotePath))
|
|
||||||
}
|
|
||||||
|
|
||||||
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,118 +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 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,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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(
|
|
||||||
getFinalWebDavUrl(),
|
|
||||||
DavConstants.DEPTH_1,
|
|
||||||
DavUtils.allPropSet
|
|
||||||
)
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(propfindMethod)
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
val mFolderAndFiles = ArrayList<RemoteFile>()
|
|
||||||
|
|
||||||
val remoteFolder = RemoteFile.getRemoteFileFromDav(
|
|
||||||
davResource = propfindMethod.root!!,
|
|
||||||
userId = AccountUtils.getUserId(mAccount, mContext),
|
|
||||||
userName = mAccount.name,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
)
|
|
||||||
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,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
)
|
|
||||||
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 getFinalWebDavUrl(): URL {
|
|
||||||
val baseWebDavUrl = spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
|
|
||||||
return URL(baseWebDavUrl + WebdavUtils.encodePath(remotePath))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int): Boolean = status.isOneOf(HTTP_OK, HTTP_MULTI_STATUS)
|
|
||||||
}
|
|
@ -1,194 +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 android.os.Parcelable
|
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import at.bitfire.dav4jvm.PropStat
|
|
||||||
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 com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes
|
|
||||||
import com.owncloud.android.lib.common.utils.isOneOf
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareType
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareType.Companion.fromValue
|
|
||||||
import kotlinx.parcelize.Parcelize
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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,
|
|
||||||
spaceWebDavUrl: String? = null
|
|
||||||
): RemoteFile {
|
|
||||||
val remotePath = getRemotePathFromUrl(davResource.href, userId, spaceWebDavUrl)
|
|
||||||
val remoteFile = RemoteFile(remotePath = remotePath, owner = userName)
|
|
||||||
val properties = getPropertiesEvenIfPostProcessing(davResource)
|
|
||||||
|
|
||||||
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 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 legacy:
|
|
||||||
* /remote.php/dav/files/username/Documents/text.txt => /Documents/text.txt
|
|
||||||
*
|
|
||||||
* Example spaces:
|
|
||||||
* /dav/spaces/8871f4f3-fc6f-4a66-8bed-62f175f76f38$05bca744-d89f-4e9c-a990-25a0d7f03fe9/Documents/text.txt => /Documents/text.txt
|
|
||||||
*
|
|
||||||
* @param url remote file url
|
|
||||||
* @param userId file owner
|
|
||||||
* @param spaceWebDavUrl custom web dav url for space
|
|
||||||
* @return remote relative path of the file
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
fun getRemotePathFromUrl(
|
|
||||||
url: HttpUrl,
|
|
||||||
userId: String,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): String {
|
|
||||||
val davFilesPath = spaceWebDavUrl ?: (OwnCloudClient.WEBDAV_FILES_PATH_4_0 + userId)
|
|
||||||
val absoluteDavPath = if (spaceWebDavUrl != null) Uri.decode(url.toString()) else Uri.decode(url.encodedPath)
|
|
||||||
val pathToOc = absoluteDavPath.split(davFilesPath).first()
|
|
||||||
return absoluteDavPath.replace(pathToOc + davFilesPath, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPropertiesEvenIfPostProcessing(response: Response): List<Property> {
|
|
||||||
return if (response.isSuccess())
|
|
||||||
response.propstat.filter { propStat -> propStat.isSuccessOrPostProcessing() }.map { it.properties }.flatten()
|
|
||||||
else
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PropStat.isSuccessOrPostProcessing() = (status.code / 100 == 2 || status.code == HttpConstants.HTTP_TOO_EARLY)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +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.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,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : RemoteOperation<Unit>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
|
||||||
var result: RemoteOperationResult<Unit>
|
|
||||||
try {
|
|
||||||
val srcWebDavUri = getSrcWebDavUriForClient(client)
|
|
||||||
val deleteMethod = DeleteMethod(
|
|
||||||
URL(srcWebDavUri + 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): String = spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status.isOneOf(HTTP_OK, HTTP_NO_CONTENT)
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
/* 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,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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((spaceWebDavUrl ?: client.userFilesWebDavUri.toString()) + WebdavUtils.encodePath(oldRemotePath)),
|
|
||||||
destinationUrl = (spaceWebDavUrl ?: 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, true)
|
|
||||||
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,68 +0,0 @@
|
|||||||
/* 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.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 com.owncloud.android.lib.common.utils.isOneOf
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class UploadFileFromContentUriOperation(
|
|
||||||
private val uploadPath: String,
|
|
||||||
private val lastModified: String,
|
|
||||||
private val requestBody: ContentUriRequestBody
|
|
||||||
) : RemoteOperation<Unit>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
|
||||||
val putMethod = PutMethod(URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(uploadPath)), requestBody).apply {
|
|
||||||
retryOnConnectionFailure = false
|
|
||||||
addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, requestBody.contentLength().toString())
|
|
||||||
addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, lastModified)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(putMethod)
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
RemoteOperationResult<Unit>(RemoteOperationResult.ResultCode.OK).apply { data = Unit }
|
|
||||||
} else {
|
|
||||||
RemoteOperationResult<Unit>(putMethod)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
val result = RemoteOperationResult<Unit>(e)
|
|
||||||
Timber.e(e, "Upload from content uri failed : ${result.logMessage}")
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSuccess(status: Int): Boolean {
|
|
||||||
return status.isOneOf(HttpConstants.HTTP_OK, HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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
|
|
||||||
* @author Juan Carlos Garrote Gascón
|
|
||||||
*/
|
|
||||||
open class UploadFileFromFileSystemOperation(
|
|
||||||
val localPath: String,
|
|
||||||
val remotePath: String,
|
|
||||||
val mimeType: String,
|
|
||||||
val lastModifiedTimestamp: String,
|
|
||||||
val requiredEtag: String?,
|
|
||||||
val spaceWebDavUrl: String? = null,
|
|
||||||
) : 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) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val baseStringUrl = spaceWebDavUrl ?: client.userFilesWebDavUri.toString()
|
|
||||||
putMethod = PutMethod(URL(baseStringUrl + 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,122 +0,0 @@
|
|||||||
/* 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,58 +0,0 @@
|
|||||||
/* 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.chunks
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
class MoveRemoteChunksFileOperation(
|
|
||||||
sourceRemotePath: String,
|
|
||||||
targetRemotePath: String,
|
|
||||||
private val fileLastModificationTimestamp: String,
|
|
||||||
private val fileLength: Long
|
|
||||||
) : MoveRemoteFileOperation(
|
|
||||||
sourceRemotePath = sourceRemotePath,
|
|
||||||
targetRemotePath = targetRemotePath,
|
|
||||||
) {
|
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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
|
|
||||||
|
|
||||||
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,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<Boolean>
|
|
||||||
|
|
||||||
fun copyFile(
|
|
||||||
sourceRemotePath: String,
|
|
||||||
targetRemotePath: String,
|
|
||||||
sourceSpaceWebDavUrl: String?,
|
|
||||||
targetSpaceWebDavUrl: String?,
|
|
||||||
replace: Boolean,
|
|
||||||
): RemoteOperationResult<String?>
|
|
||||||
|
|
||||||
fun createFolder(
|
|
||||||
remotePath: String,
|
|
||||||
createFullPath: Boolean,
|
|
||||||
isChunkFolder: Boolean = false,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<Unit>
|
|
||||||
|
|
||||||
fun downloadFile(
|
|
||||||
remotePath: String,
|
|
||||||
localTempPath: String
|
|
||||||
): RemoteOperationResult<Unit>
|
|
||||||
|
|
||||||
fun moveFile(
|
|
||||||
sourceRemotePath: String,
|
|
||||||
targetRemotePath: String,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
replace: Boolean,
|
|
||||||
): RemoteOperationResult<Unit>
|
|
||||||
|
|
||||||
fun readFile(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<RemoteFile>
|
|
||||||
|
|
||||||
fun refreshFolder(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<ArrayList<RemoteFile>>
|
|
||||||
|
|
||||||
fun removeFile(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<Unit>
|
|
||||||
|
|
||||||
fun renameFile(
|
|
||||||
oldName: String,
|
|
||||||
oldRemotePath: String,
|
|
||||||
newName: String,
|
|
||||||
isFolder: Boolean,
|
|
||||||
spaceWebDavUrl: String? = null,
|
|
||||||
): RemoteOperationResult<Unit>
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/* 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)
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2023 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.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.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,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<Boolean> =
|
|
||||||
CheckPathExistenceRemoteOperation(
|
|
||||||
remotePath = path,
|
|
||||||
isUserLoggedIn = isUserLogged,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun copyFile(
|
|
||||||
sourceRemotePath: String,
|
|
||||||
targetRemotePath: String,
|
|
||||||
sourceSpaceWebDavUrl: String?,
|
|
||||||
targetSpaceWebDavUrl: String?,
|
|
||||||
replace: Boolean,
|
|
||||||
): RemoteOperationResult<String?> =
|
|
||||||
CopyRemoteFileOperation(
|
|
||||||
sourceRemotePath = sourceRemotePath,
|
|
||||||
targetRemotePath = targetRemotePath,
|
|
||||||
sourceSpaceWebDavUrl = sourceSpaceWebDavUrl,
|
|
||||||
targetSpaceWebDavUrl = targetSpaceWebDavUrl,
|
|
||||||
forceOverride = replace,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun createFolder(
|
|
||||||
remotePath: String,
|
|
||||||
createFullPath: Boolean,
|
|
||||||
isChunkFolder: Boolean,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<Unit> =
|
|
||||||
CreateRemoteFolderOperation(
|
|
||||||
remotePath = remotePath,
|
|
||||||
createFullPath = createFullPath,
|
|
||||||
isChunksFolder = isChunkFolder,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).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,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
replace: Boolean,
|
|
||||||
): RemoteOperationResult<Unit> =
|
|
||||||
MoveRemoteFileOperation(
|
|
||||||
sourceRemotePath = sourceRemotePath,
|
|
||||||
targetRemotePath = targetRemotePath,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
forceOverride = replace,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun readFile(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<RemoteFile> =
|
|
||||||
ReadRemoteFileOperation(
|
|
||||||
remotePath = remotePath,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun refreshFolder(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<ArrayList<RemoteFile>> =
|
|
||||||
ReadRemoteFolderOperation(
|
|
||||||
remotePath = remotePath,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun removeFile(
|
|
||||||
remotePath: String,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<Unit> =
|
|
||||||
RemoveRemoteFileOperation(
|
|
||||||
remotePath = remotePath,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun renameFile(
|
|
||||||
oldName: String,
|
|
||||||
oldRemotePath: String,
|
|
||||||
newName: String,
|
|
||||||
isFolder: Boolean,
|
|
||||||
spaceWebDavUrl: String?,
|
|
||||||
): RemoteOperationResult<Unit> =
|
|
||||||
RenameRemoteFileOperation(
|
|
||||||
oldName = oldName,
|
|
||||||
oldRemotePath = oldRemotePath,
|
|
||||||
newName = newName,
|
|
||||||
isFolder = isFolder,
|
|
||||||
spaceWebDavUrl = spaceWebDavUrl,
|
|
||||||
).execute(client)
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth
|
|
||||||
|
|
||||||
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.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get OIDC Discovery
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*/
|
|
||||||
class GetOIDCDiscoveryRemoteOperation : RemoteOperation<OIDCDiscoveryResponse>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<OIDCDiscoveryResponse> {
|
|
||||||
try {
|
|
||||||
val uriBuilder = client.baseUri.buildUpon().apply {
|
|
||||||
appendPath(WELL_KNOWN_PATH) // avoid starting "/" in this method
|
|
||||||
appendPath(OPENID_CONFIGURATION_RESOURCE)
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(uriBuilder.toString())).apply {
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
getMethod.followRedirects = true
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
|
|
||||||
val responseBody = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (status == HttpConstants.HTTP_OK && responseBody != null) {
|
|
||||||
Timber.d("Successful response $responseBody")
|
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
val moshi: Moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter: JsonAdapter<OIDCDiscoveryResponse> = moshi.adapter(OIDCDiscoveryResponse::class.java)
|
|
||||||
val oidcDiscoveryResponse: OIDCDiscoveryResponse? = jsonAdapter.fromJson(responseBody)
|
|
||||||
Timber.d("Get OIDC Discovery completed and parsed to [$oidcDiscoveryResponse]")
|
|
||||||
|
|
||||||
return RemoteOperationResult<OIDCDiscoveryResponse>(RemoteOperationResult.ResultCode.OK).apply {
|
|
||||||
data = oidcDiscoveryResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Timber.e("Failed response while getting OIDC server discovery from the server status code: $status; response message: $responseBody")
|
|
||||||
|
|
||||||
return RemoteOperationResult<OIDCDiscoveryResponse>(getMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting OIDC server discovery")
|
|
||||||
|
|
||||||
return RemoteOperationResult<OIDCDiscoveryResponse>(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val WELL_KNOWN_PATH = ".well-known"
|
|
||||||
private const val OPENID_CONFIGURATION_RESOURCE = "openid-configuration"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.ClientRegistrationParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.ClientRegistrationResponse
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class RegisterClientRemoteOperation(
|
|
||||||
private val clientRegistrationParams: ClientRegistrationParams
|
|
||||||
) : RemoteOperation<ClientRegistrationResponse>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ClientRegistrationResponse> {
|
|
||||||
try {
|
|
||||||
val requestBody = clientRegistrationParams.toRequestBody()
|
|
||||||
|
|
||||||
val postMethod = PostMethod(
|
|
||||||
url = URL(clientRegistrationParams.registrationEndpoint),
|
|
||||||
postRequestBody = requestBody
|
|
||||||
)
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(postMethod)
|
|
||||||
|
|
||||||
val responseBody = postMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (status == HttpConstants.HTTP_CREATED && responseBody != null) {
|
|
||||||
Timber.d("Successful response $responseBody")
|
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
val moshi: Moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter: JsonAdapter<ClientRegistrationResponse> =
|
|
||||||
moshi.adapter(ClientRegistrationResponse::class.java)
|
|
||||||
val clientRegistrationResponse: ClientRegistrationResponse? = jsonAdapter.fromJson(responseBody)
|
|
||||||
Timber.d("Client registered and parsed to $clientRegistrationResponse")
|
|
||||||
|
|
||||||
return RemoteOperationResult<ClientRegistrationResponse>(RemoteOperationResult.ResultCode.OK).apply {
|
|
||||||
data = clientRegistrationResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Timber.e("Failed response while registering a new client. Status code: $status; response message: $responseBody")
|
|
||||||
return RemoteOperationResult<ClientRegistrationResponse>(postMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while registering a new client.")
|
|
||||||
return RemoteOperationResult<ClientRegistrationResponse>(e)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_OK
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.TokenRequestParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform token request
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*/
|
|
||||||
class TokenRequestRemoteOperation(
|
|
||||||
private val tokenRequestParams: TokenRequestParams
|
|
||||||
) : RemoteOperation<TokenResponse>() {
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<TokenResponse> {
|
|
||||||
try {
|
|
||||||
val requestBody = tokenRequestParams.toRequestBody()
|
|
||||||
|
|
||||||
val postMethod = PostMethod(URL(tokenRequestParams.tokenEndpoint), requestBody)
|
|
||||||
|
|
||||||
postMethod.addRequestHeader(AUTHORIZATION_HEADER, tokenRequestParams.clientAuth)
|
|
||||||
|
|
||||||
val status = client.executeHttpMethod(postMethod)
|
|
||||||
|
|
||||||
val responseBody = postMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (status == HTTP_OK && responseBody != null) {
|
|
||||||
Timber.d("Successful response $responseBody")
|
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
val moshi: Moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter: JsonAdapter<TokenResponse> = moshi.adapter(TokenResponse::class.java)
|
|
||||||
val tokenResponse: TokenResponse? = jsonAdapter.fromJson(responseBody)
|
|
||||||
Timber.d("Get tokens completed and parsed to $tokenResponse")
|
|
||||||
|
|
||||||
return RemoteOperationResult<TokenResponse>(RemoteOperationResult.ResultCode.OK).apply {
|
|
||||||
data = tokenResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Timber.e("Failed response while getting tokens from the server status code: $status; response message: $responseBody")
|
|
||||||
return RemoteOperationResult<TokenResponse>(postMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting tokens")
|
|
||||||
return RemoteOperationResult<TokenResponse>(e)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth.params
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_JSON
|
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
data class ClientRegistrationParams(
|
|
||||||
val registrationEndpoint: String,
|
|
||||||
val clientName: String,
|
|
||||||
val redirectUris: List<String>,
|
|
||||||
val tokenEndpointAuthMethod: String,
|
|
||||||
val applicationType: String
|
|
||||||
) {
|
|
||||||
fun toRequestBody(): RequestBody =
|
|
||||||
JSONObject().apply {
|
|
||||||
put(PARAM_APPLICATION_TYPE, applicationType)
|
|
||||||
put(PARAM_CLIENT_NAME, clientName)
|
|
||||||
put(PARAM_REDIRECT_URIS, JSONArray(redirectUris))
|
|
||||||
put(PARAM_TOKEN_ENDPOINT_AUTH_METHOD, tokenEndpointAuthMethod)
|
|
||||||
}.toString().toRequestBody(CONTENT_TYPE_JSON.toMediaType())
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PARAM_APPLICATION_TYPE = "application_type"
|
|
||||||
private const val PARAM_CLIENT_NAME = "client_name"
|
|
||||||
private const val PARAM_TOKEN_ENDPOINT_AUTH_METHOD = "token_endpoint_auth_method"
|
|
||||||
private const val PARAM_REDIRECT_URIS = "redirect_uris"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +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.oauth.params
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
|
|
||||||
sealed class TokenRequestParams(
|
|
||||||
val tokenEndpoint: String,
|
|
||||||
val clientAuth: String,
|
|
||||||
val grantType: String
|
|
||||||
) {
|
|
||||||
abstract fun toRequestBody(): RequestBody
|
|
||||||
|
|
||||||
class Authorization(
|
|
||||||
tokenEndpoint: String,
|
|
||||||
clientAuth: String,
|
|
||||||
grantType: String,
|
|
||||||
val authorizationCode: String,
|
|
||||||
val redirectUri: String,
|
|
||||||
val codeVerifier: String,
|
|
||||||
) : TokenRequestParams(tokenEndpoint, clientAuth, grantType) {
|
|
||||||
|
|
||||||
override fun toRequestBody(): RequestBody =
|
|
||||||
FormBody.Builder()
|
|
||||||
.add(HttpConstants.OAUTH_HEADER_AUTHORIZATION_CODE, authorizationCode)
|
|
||||||
.add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
|
|
||||||
.add(HttpConstants.OAUTH_HEADER_REDIRECT_URI, redirectUri)
|
|
||||||
.add(HttpConstants.OAUTH_HEADER_CODE_VERIFIER, codeVerifier)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
class RefreshToken(
|
|
||||||
tokenEndpoint: String,
|
|
||||||
clientAuth: String,
|
|
||||||
grantType: String,
|
|
||||||
val refreshToken: String? = null
|
|
||||||
) : TokenRequestParams(tokenEndpoint, clientAuth, grantType) {
|
|
||||||
|
|
||||||
override fun toRequestBody(): RequestBody =
|
|
||||||
FormBody.Builder().apply {
|
|
||||||
add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
|
|
||||||
if (!refreshToken.isNullOrBlank()) {
|
|
||||||
add(HttpConstants.OAUTH_HEADER_REFRESH_TOKEN, refreshToken)
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ClientRegistrationResponse(
|
|
||||||
@Json(name = "client_id")
|
|
||||||
val clientId: String,
|
|
||||||
@Json(name = "client_secret")
|
|
||||||
val clientSecret: String?,
|
|
||||||
@Json(name = "client_id_issued_at")
|
|
||||||
val clientIdIssuedAt: Int?,
|
|
||||||
@Json(name = "client_secret_expires_at")
|
|
||||||
val clientSecretExpiration: Int,
|
|
||||||
)
|
|
@ -1,43 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Abel García de Prada
|
|
||||||
*
|
|
||||||
* 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.oauth.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class OIDCDiscoveryResponse(
|
|
||||||
val authorization_endpoint: String,
|
|
||||||
val check_session_iframe: String?,
|
|
||||||
val end_session_endpoint: String?,
|
|
||||||
val issuer: String,
|
|
||||||
val registration_endpoint: String?,
|
|
||||||
val response_types_supported: List<String>,
|
|
||||||
val scopes_supported: List<String>?,
|
|
||||||
val token_endpoint: String,
|
|
||||||
val token_endpoint_auth_methods_supported: List<String>?,
|
|
||||||
val userinfo_endpoint: String?,
|
|
||||||
)
|
|
@ -1,45 +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.oauth.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class TokenResponse(
|
|
||||||
@Json(name = "access_token")
|
|
||||||
val accessToken: String,
|
|
||||||
@Json(name = "expires_in")
|
|
||||||
val expiresIn: Int,
|
|
||||||
@Json(name = "refresh_token")
|
|
||||||
val refreshToken: String?,
|
|
||||||
@Json(name = "token_type")
|
|
||||||
val tokenType: String,
|
|
||||||
@Json(name = "user_id")
|
|
||||||
val userId: String?,
|
|
||||||
val scope: String?,
|
|
||||||
@Json(name = "additional_parameters")
|
|
||||||
val additionalParameters: Map<String, String>?
|
|
||||||
)
|
|
@ -1,47 +0,0 @@
|
|||||||
/* 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.oauth.services
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.ClientRegistrationParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.TokenRequestParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.ClientRegistrationResponse
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
|
|
||||||
|
|
||||||
interface OIDCService {
|
|
||||||
|
|
||||||
fun getOIDCServerDiscovery(ownCloudClient: OwnCloudClient): RemoteOperationResult<OIDCDiscoveryResponse>
|
|
||||||
|
|
||||||
fun performTokenRequest(
|
|
||||||
ownCloudClient: OwnCloudClient,
|
|
||||||
tokenRequest: TokenRequestParams
|
|
||||||
): RemoteOperationResult<TokenResponse>
|
|
||||||
|
|
||||||
fun registerClientWithRegistrationEndpoint(
|
|
||||||
ownCloudClient: OwnCloudClient,
|
|
||||||
clientRegistrationParams: ClientRegistrationParams
|
|
||||||
): RemoteOperationResult<ClientRegistrationResponse>
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/* 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.oauth.services.implementation
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.oauth.GetOIDCDiscoveryRemoteOperation
|
|
||||||
import com.owncloud.android.lib.resources.oauth.RegisterClientRemoteOperation
|
|
||||||
import com.owncloud.android.lib.resources.oauth.TokenRequestRemoteOperation
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.ClientRegistrationParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.params.TokenRequestParams
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.ClientRegistrationResponse
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
|
|
||||||
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
|
|
||||||
import com.owncloud.android.lib.resources.oauth.services.OIDCService
|
|
||||||
|
|
||||||
class OCOIDCService : OIDCService {
|
|
||||||
|
|
||||||
override fun getOIDCServerDiscovery(
|
|
||||||
ownCloudClient: OwnCloudClient
|
|
||||||
): RemoteOperationResult<OIDCDiscoveryResponse> =
|
|
||||||
GetOIDCDiscoveryRemoteOperation().execute(ownCloudClient)
|
|
||||||
|
|
||||||
override fun performTokenRequest(
|
|
||||||
ownCloudClient: OwnCloudClient,
|
|
||||||
tokenRequest: TokenRequestParams
|
|
||||||
): RemoteOperationResult<TokenResponse> =
|
|
||||||
TokenRequestRemoteOperation(tokenRequest).execute(ownCloudClient)
|
|
||||||
|
|
||||||
override fun registerClientWithRegistrationEndpoint(
|
|
||||||
ownCloudClient: OwnCloudClient,
|
|
||||||
clientRegistrationParams: ClientRegistrationParams
|
|
||||||
): RemoteOperationResult<ClientRegistrationResponse> =
|
|
||||||
RegisterClientRemoteOperation(clientRegistrationParams).execute(ownCloudClient)
|
|
||||||
|
|
||||||
}
|
|
@ -1,211 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.CommonOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.INIT_EXPIRATION_DATE_IN_MILLIS
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareItem
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.net.URL
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new share. This allows sharing with a user or group or as a link.
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remoteFilePath Full path of the file/folder being shared. Mandatory argument
|
|
||||||
* @param shareType 0 = user, 1 = group, 3 = Public link. Mandatory argument
|
|
||||||
* @param shareWith User/group ID with who the file should be shared. This is mandatory for shareType
|
|
||||||
* of 0 or 1
|
|
||||||
* @param permissions 1 - Read only Default for public shares
|
|
||||||
* 2 - Update
|
|
||||||
* 4 - Create
|
|
||||||
* 8 - Delete
|
|
||||||
* 16- Re-share
|
|
||||||
* 31- All above Default for private shares
|
|
||||||
* For user or group shares.
|
|
||||||
* To obtain combinations, add the desired values together.
|
|
||||||
* For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27.
|
|
||||||
*/
|
|
||||||
class CreateRemoteShareOperation(
|
|
||||||
private val remoteFilePath: String,
|
|
||||||
private val shareType: ShareType,
|
|
||||||
private val shareWith: String,
|
|
||||||
private val permissions: Int
|
|
||||||
) : RemoteOperation<ShareResponse>() {
|
|
||||||
|
|
||||||
var name = "" // Name to set for the public link
|
|
||||||
|
|
||||||
var password: String = "" // Password to set for the public link
|
|
||||||
|
|
||||||
var expirationDateInMillis: Long = INIT_EXPIRATION_DATE_IN_MILLIS // Expiration date to set for the public link
|
|
||||||
|
|
||||||
var retrieveShareDetails = false // To retrieve more info about the just created share
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String): ShareResponse {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val commonOcsType: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareItem::class.java)
|
|
||||||
val adapter: JsonAdapter<CommonOcsResponse<ShareItem>> = moshi.adapter(commonOcsType)
|
|
||||||
val remoteShare = adapter.fromJson(response)?.ocs?.data?.toRemoteShare()
|
|
||||||
return ShareResponse(remoteShare?.let { listOf(it) } ?: listOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: PostMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<ShareResponse> {
|
|
||||||
Timber.e("Failed response while while creating new remote share operation ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareResponse> {
|
|
||||||
val result = RemoteOperationResult<ShareResponse>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = parseResponse(response!!)
|
|
||||||
Timber.d("*** Creating new remote share operation completed ")
|
|
||||||
|
|
||||||
val emptyShare = result.data.shares.first()
|
|
||||||
|
|
||||||
return if (retrieveShareDetails) {
|
|
||||||
// retrieve more info - PUT only returns the index of the new share
|
|
||||||
GetRemoteShareOperation(emptyShare.id).execute(client)
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFormBody(): FormBody {
|
|
||||||
val formBodyBuilder = FormBody.Builder()
|
|
||||||
.add(PARAM_PATH, remoteFilePath)
|
|
||||||
.add(PARAM_SHARE_TYPE, shareType.value.toString())
|
|
||||||
.add(PARAM_SHARE_WITH, shareWith)
|
|
||||||
|
|
||||||
if (name.isNotEmpty()) {
|
|
||||||
formBodyBuilder.add(PARAM_NAME, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expirationDateInMillis > INIT_EXPIRATION_DATE_IN_MILLIS) {
|
|
||||||
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault())
|
|
||||||
val expirationDate = Calendar.getInstance()
|
|
||||||
expirationDate.timeInMillis = expirationDateInMillis
|
|
||||||
val formattedExpirationDate = dateFormat.format(expirationDate.time)
|
|
||||||
formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password.isNotEmpty()) {
|
|
||||||
formBodyBuilder.add(PARAM_PASSWORD, password)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RemoteShare.DEFAULT_PERMISSION != permissions) {
|
|
||||||
formBodyBuilder.add(PARAM_PERMISSIONS, permissions.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
return formBodyBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareResponse> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val postMethod = PostMethod(URL(requestUri.toString()), createFormBody()).apply {
|
|
||||||
setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8)
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(postMethod)
|
|
||||||
val response = postMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(postMethod, response, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while creating new remote share operation ")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
//OCS Route
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares"
|
|
||||||
|
|
||||||
//Arguments - names
|
|
||||||
|
|
||||||
private const val PARAM_NAME = "name"
|
|
||||||
private const val PARAM_EXPIRATION_DATE = "expireDate"
|
|
||||||
private const val PARAM_PATH = "path"
|
|
||||||
private const val PARAM_SHARE_TYPE = "shareType"
|
|
||||||
private const val PARAM_SHARE_WITH = "shareWith"
|
|
||||||
private const val PARAM_PASSWORD = "password"
|
|
||||||
private const val PARAM_PERMISSIONS = "permissions"
|
|
||||||
|
|
||||||
//Arguments - constant values
|
|
||||||
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.CommonOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareItem
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class GetRemoteShareOperation(private val remoteId: String) : RemoteOperation<ShareResponse>() {
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendEncodedPath(remoteId)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String): ShareResponse? {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val listOfShareItemType: Type = Types.newParameterizedType(List::class.java, ShareItem::class.java)
|
|
||||||
val commonOcsType: Type = Types.newParameterizedType(CommonOcsResponse::class.java, listOfShareItemType)
|
|
||||||
val adapter: JsonAdapter<CommonOcsResponse<List<ShareItem>>> = moshi.adapter(commonOcsType)
|
|
||||||
return adapter.fromJson(response)?.ocs?.data?.let { listOfShareItems ->
|
|
||||||
ShareResponse(listOfShareItems.map { shareItem ->
|
|
||||||
shareItem.toRemoteShare()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: GetMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<ShareResponse> {
|
|
||||||
Timber.e("Failed response while while getting remote shares ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareResponse> {
|
|
||||||
val result = RemoteOperationResult<ShareResponse>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = parseResponse(response!!)
|
|
||||||
Timber.d("*** Get Users or groups completed ")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareResponse> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(requestUri.toString())).apply {
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
val response = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (!isSuccess(status)) {
|
|
||||||
onResultUnsuccessful(getMethod, response, status)
|
|
||||||
} else {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting remote shares")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
//OCS Route
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
*
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
|
||||||
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.OK
|
|
||||||
import com.owncloud.android.lib.resources.CommonOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareeOcsResponse
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by masensio on 08/10/2015.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Retrieves a list of sharees (possible targets of a share) from the ownCloud server.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Currently only handles users and groups. Users in other OC servers (federation) should be added later.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Depends on SHAREE API. {@See https://github.com/owncloud/documentation/issues/1626}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Syntax:
|
|
||||||
* Entry point: ocs/v2.php/apps/files_sharing/api/v1/sharees
|
|
||||||
* HTTP method: GET
|
|
||||||
* url argument: itemType - string, required
|
|
||||||
* url argument: format - string, optional
|
|
||||||
* url argument: search - string, optional
|
|
||||||
* url arguments: perPage - int, optional
|
|
||||||
* url arguments: page - int, optional
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Status codes:
|
|
||||||
* 100 - successful
|
|
||||||
*
|
|
||||||
* @author Christian Schabesberger
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
class GetRemoteShareesOperation
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param searchString string for searching users, optional
|
|
||||||
* @param page page index in the list of results; beginning in 1
|
|
||||||
* @param perPage maximum number of results in a single page
|
|
||||||
*/
|
|
||||||
(private val searchString: String, private val page: Int, private val perPage: Int) :
|
|
||||||
RemoteOperation<ShareeOcsResponse>() {
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE)
|
|
||||||
.appendQueryParameter(PARAM_SEARCH, searchString)
|
|
||||||
.appendQueryParameter(PARAM_PAGE, page.toString())
|
|
||||||
.appendQueryParameter(PARAM_PER_PAGE, perPage.toString())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String?): ShareeOcsResponse? {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val type: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareeOcsResponse::class.java)
|
|
||||||
val adapter: JsonAdapter<CommonOcsResponse<ShareeOcsResponse>> = moshi.adapter(type)
|
|
||||||
return response?.let { adapter.fromJson(it)?.ocs?.data }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: GetMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<ShareeOcsResponse> {
|
|
||||||
Timber.e("Failed response while getting users/groups from the server ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareeOcsResponse> {
|
|
||||||
val result = RemoteOperationResult<ShareeOcsResponse>(OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = parseResponse(response)
|
|
||||||
Timber.d("*** Get Users or groups completed ")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareeOcsResponse> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(requestUri.toString()))
|
|
||||||
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
val response = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(getMethod, response, status)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting users/groups")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
// OCS Routes
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/sharees" // from OC 8.2
|
|
||||||
|
|
||||||
// Arguments - names
|
|
||||||
private const val PARAM_ITEM_TYPE = "itemType"
|
|
||||||
private const val PARAM_SEARCH = "search"
|
|
||||||
private const val PARAM_PAGE = "page" // default = 1
|
|
||||||
private const val PARAM_PER_PAGE = "perPage" // default = 200
|
|
||||||
|
|
||||||
// Arguments - constant values
|
|
||||||
private const val VALUE_ITEM_TYPE = "file" // to get the server search for users / groups
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,153 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.CommonOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareItem
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide a list shares for a specific file.
|
|
||||||
* The input is the full path of the desired file.
|
|
||||||
* The output is a list of everyone who has the file shared with them.
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remoteFilePath Path to file or folder
|
|
||||||
* @param reshares If set to false (default), only shares owned by the current user are
|
|
||||||
* returned.
|
|
||||||
* If set to true, shares owned by any user from the given file are returned.
|
|
||||||
* @param subfiles If set to false (default), lists only the folder being shared
|
|
||||||
* If set to true, all shared files within the folder are returned.
|
|
||||||
*/
|
|
||||||
class GetRemoteSharesForFileOperation(
|
|
||||||
private val remoteFilePath: String,
|
|
||||||
private val reshares: Boolean,
|
|
||||||
private val subfiles: Boolean
|
|
||||||
) : RemoteOperation<ShareResponse>() {
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.appendQueryParameter(PARAM_PATH, remoteFilePath)
|
|
||||||
.appendQueryParameter(PARAM_RESHARES, reshares.toString())
|
|
||||||
.appendQueryParameter(PARAM_SUBFILES, subfiles.toString())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String): ShareResponse? {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val listOfShareItemType: Type = Types.newParameterizedType(List::class.java, ShareItem::class.java)
|
|
||||||
val commonOcsType: Type = Types.newParameterizedType(CommonOcsResponse::class.java, listOfShareItemType)
|
|
||||||
val adapter: JsonAdapter<CommonOcsResponse<List<ShareItem>>> = moshi.adapter(commonOcsType)
|
|
||||||
return adapter.fromJson(response)?.ocs?.data?.let { listOfShareItems ->
|
|
||||||
ShareResponse(listOfShareItems.map { shareItem ->
|
|
||||||
shareItem.toRemoteShare()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: GetMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<ShareResponse> {
|
|
||||||
Timber.e("Failed response while while getting remote shares for file operation ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareResponse> {
|
|
||||||
val result = RemoteOperationResult<ShareResponse>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = parseResponse(response!!)
|
|
||||||
Timber.d("*** Getting remote shares for file completed ")
|
|
||||||
Timber.d("Got ${result.data.shares.size} shares")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareResponse> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(requestUri.toString())).apply {
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
val response = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(getMethod, response, status)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting remote shares for file operation")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
//OCS Route
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares"
|
|
||||||
|
|
||||||
//Arguments - names
|
|
||||||
private const val PARAM_PATH = "path"
|
|
||||||
private const val PARAM_RESHARES = "reshares"
|
|
||||||
private const val PARAM_SUBFILES = "subfiles"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +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.shares
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ItemType
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the data of a Share from the Share API
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
*/
|
|
||||||
data class RemoteShare(
|
|
||||||
var id: String = "0",
|
|
||||||
var shareWith: String = "",
|
|
||||||
var path: String = "",
|
|
||||||
var token: String = "",
|
|
||||||
var itemType: String = "",
|
|
||||||
var sharedWithDisplayName: String = "",
|
|
||||||
var sharedWithAdditionalInfo: String = "",
|
|
||||||
var name: String = "",
|
|
||||||
var shareLink: String = "",
|
|
||||||
var shareType: ShareType? = ShareType.UNKNOWN,
|
|
||||||
var permissions: Int = DEFAULT_PERMISSION,
|
|
||||||
var sharedDate: Long = INIT_SHARED_DATE,
|
|
||||||
var expirationDate: Long = INIT_EXPIRATION_DATE_IN_MILLIS,
|
|
||||||
var isFolder: Boolean = (itemType == ItemType.FOLDER.fileValue)
|
|
||||||
) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val DEFAULT_PERMISSION = -1
|
|
||||||
const val READ_PERMISSION_FLAG = 1
|
|
||||||
const val UPDATE_PERMISSION_FLAG = 2
|
|
||||||
const val CREATE_PERMISSION_FLAG = 4
|
|
||||||
const val DELETE_PERMISSION_FLAG = 8
|
|
||||||
const val SHARE_PERMISSION_FLAG = 16
|
|
||||||
const val MAXIMUM_PERMISSIONS_FOR_FILE = READ_PERMISSION_FLAG +
|
|
||||||
UPDATE_PERMISSION_FLAG +
|
|
||||||
SHARE_PERMISSION_FLAG
|
|
||||||
const val MAXIMUM_PERMISSIONS_FOR_FOLDER = MAXIMUM_PERMISSIONS_FOR_FILE +
|
|
||||||
CREATE_PERMISSION_FLAG +
|
|
||||||
DELETE_PERMISSION_FLAG
|
|
||||||
const val FEDERATED_PERMISSIONS_FOR_FILE = READ_PERMISSION_FLAG +
|
|
||||||
UPDATE_PERMISSION_FLAG +
|
|
||||||
SHARE_PERMISSION_FLAG
|
|
||||||
const val FEDERATED_PERMISSIONS_FOR_FOLDER = READ_PERMISSION_FLAG +
|
|
||||||
UPDATE_PERMISSION_FLAG +
|
|
||||||
CREATE_PERMISSION_FLAG +
|
|
||||||
DELETE_PERMISSION_FLAG +
|
|
||||||
SHARE_PERMISSION_FLAG
|
|
||||||
|
|
||||||
const val INIT_EXPIRATION_DATE_IN_MILLIS: Long = 0
|
|
||||||
const val INIT_SHARED_DATE: Long = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* // TODO This type is already included in the domain but we still need it here since the parsing takes place in this library for the moment
|
|
||||||
*
|
|
||||||
* Enum for Share Type, with values:
|
|
||||||
* -1 - Unknown
|
|
||||||
* 0 - Shared by user
|
|
||||||
* 1 - Shared by group
|
|
||||||
* 3 - Shared by public link
|
|
||||||
* 4 - Shared by e-mail
|
|
||||||
* 5 - Shared by contact
|
|
||||||
* 6 - Federated
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum class ShareType constructor(val value: Int) {
|
|
||||||
UNKNOWN(-1),
|
|
||||||
USER(0),
|
|
||||||
GROUP(1),
|
|
||||||
PUBLIC_LINK(3),
|
|
||||||
EMAIL(4),
|
|
||||||
CONTACT(5),
|
|
||||||
FEDERATED(6);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun fromValue(value: Int) = values().firstOrNull { it.value == value }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a share
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
*
|
|
||||||
* @param remoteShareId Share ID
|
|
||||||
*/
|
|
||||||
class RemoveRemoteShareOperation(private val remoteShareId: String) : RemoteOperation<Unit>() {
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendEncodedPath(remoteShareId)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: DeleteMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<Unit> {
|
|
||||||
Timber.e("Failed response while removing share ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<Unit> {
|
|
||||||
val result = RemoteOperationResult<Unit>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
Timber.d("*** Unshare link completed ")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val deleteMethod = DeleteMethod(URL(requestUri.toString())).apply {
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(deleteMethod)
|
|
||||||
val response = deleteMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(deleteMethod, response, status)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while unshare link")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// OCS Route
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,230 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares
|
|
||||||
|
|
||||||
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.HttpConstants.PARAM_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants.VALUE_FORMAT
|
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.PutMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.CommonOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.DEFAULT_PERMISSION
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareItem
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.net.URL
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates parameters of an existing Share resource, known its remote ID.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Allow updating several parameters, triggering a request to the server per parameter.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author David González Verdugo
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
*/
|
|
||||||
class UpdateRemoteShareOperation
|
|
||||||
/**
|
|
||||||
* Constructor. No update is initialized by default, need to be applied with setters below.
|
|
||||||
*/
|
|
||||||
(
|
|
||||||
/**
|
|
||||||
* @param remoteId Identifier of the share to update.
|
|
||||||
*/
|
|
||||||
private val remoteId: String
|
|
||||||
|
|
||||||
) : RemoteOperation<ShareResponse>() {
|
|
||||||
/**
|
|
||||||
* Name to update in Share resource. Ignored by servers previous to version 10.0.0
|
|
||||||
*
|
|
||||||
* Empty string clears the current name.
|
|
||||||
* Null results in no update applied to the name.
|
|
||||||
*/
|
|
||||||
var name: String? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Password to update in Share resource.
|
|
||||||
*
|
|
||||||
* Empty string clears the current password.
|
|
||||||
* Null results in no update applied to the password.
|
|
||||||
*/
|
|
||||||
var password: String? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expiration date to update in Share resource.
|
|
||||||
*
|
|
||||||
* A negative value clears the current expiration date.
|
|
||||||
* Zero value (start-of-epoch) results in no update done on
|
|
||||||
* the expiration date.
|
|
||||||
*/
|
|
||||||
var expirationDateInMillis: Long = INITIAL_EXPIRATION_DATE_IN_MILLIS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Permissions to update in Share resource.
|
|
||||||
*
|
|
||||||
* Values <= 0 result in no update applied to the permissions.
|
|
||||||
*/
|
|
||||||
var permissions: Int = DEFAULT_PERMISSION
|
|
||||||
|
|
||||||
var retrieveShareDetails = false // To retrieve more info about the just updated share
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
|
||||||
.appendEncodedPath(remoteId)
|
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String): ShareResponse {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val commonOcsType: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareItem::class.java)
|
|
||||||
val adapter: JsonAdapter<CommonOcsResponse<ShareItem>> = moshi.adapter(commonOcsType)
|
|
||||||
val remoteShare = adapter.fromJson(response)?.ocs?.data?.toRemoteShare()
|
|
||||||
return ShareResponse(remoteShare?.let { listOf(it) } ?: listOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: PutMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<ShareResponse> {
|
|
||||||
Timber.e("Failed response while while updating remote shares ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareResponse> {
|
|
||||||
val result = RemoteOperationResult<ShareResponse>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = parseResponse(response!!)
|
|
||||||
Timber.d("*** Retrieve the index of the new share completed ")
|
|
||||||
val emptyShare = result.data.shares.first()
|
|
||||||
|
|
||||||
return if (retrieveShareDetails) {
|
|
||||||
// retrieve more info - PUT only returns the index of the new share
|
|
||||||
GetRemoteShareOperation(emptyShare.id).execute(client)
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createFormBodyBuilder(): FormBody.Builder {
|
|
||||||
val formBodyBuilder = FormBody.Builder()
|
|
||||||
|
|
||||||
// Parameters to update
|
|
||||||
if (name != null) {
|
|
||||||
formBodyBuilder.add(PARAM_NAME, name.orEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password != null) {
|
|
||||||
formBodyBuilder.add(PARAM_PASSWORD, password.orEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expirationDateInMillis < INITIAL_EXPIRATION_DATE_IN_MILLIS) {
|
|
||||||
// clear expiration date
|
|
||||||
formBodyBuilder.add(PARAM_EXPIRATION_DATE, "")
|
|
||||||
|
|
||||||
} else if (expirationDateInMillis > INITIAL_EXPIRATION_DATE_IN_MILLIS) {
|
|
||||||
// set expiration date
|
|
||||||
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault())
|
|
||||||
val expirationDate = Calendar.getInstance()
|
|
||||||
expirationDate.timeInMillis = expirationDateInMillis
|
|
||||||
val formattedExpirationDate = dateFormat.format(expirationDate.time)
|
|
||||||
formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate)
|
|
||||||
} // else, ignore - no update
|
|
||||||
|
|
||||||
// IMPORTANT: permissions parameter needs to be updated after mPublicUpload parameter,
|
|
||||||
// otherwise they would be set always as 1 (READ) in the server when mPublicUpload was updated
|
|
||||||
if (permissions > DEFAULT_PERMISSION) {
|
|
||||||
// set permissions
|
|
||||||
formBodyBuilder.add(PARAM_PERMISSIONS, permissions.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
return formBodyBuilder
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareResponse> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val formBodyBuilder = createFormBodyBuilder()
|
|
||||||
|
|
||||||
val putMethod = PutMethod(URL(requestUri.toString()), formBodyBuilder.build()).apply {
|
|
||||||
setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8)
|
|
||||||
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(putMethod)
|
|
||||||
val response = putMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(putMethod, response, status)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while updating remote share")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
//OCS Route
|
|
||||||
private const val OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/shares"
|
|
||||||
|
|
||||||
//Arguments - names
|
|
||||||
private const val PARAM_NAME = "name"
|
|
||||||
private const val PARAM_PASSWORD = "password"
|
|
||||||
private const val PARAM_EXPIRATION_DATE = "expireDate"
|
|
||||||
private const val PARAM_PERMISSIONS = "permissions"
|
|
||||||
|
|
||||||
//Arguments - constant values
|
|
||||||
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd"
|
|
||||||
private const val INITIAL_EXPIRATION_DATE_IN_MILLIS: Long = 0
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* @author Fernando Sanz Velasco
|
|
||||||
* 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.shares.responses
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.network.WebdavUtils
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.DEFAULT_PERMISSION
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.INIT_EXPIRATION_DATE_IN_MILLIS
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoteShare.Companion.INIT_SHARED_DATE
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareType
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ShareItem(
|
|
||||||
val id: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "share_with")
|
|
||||||
val shareWith: String? = null,
|
|
||||||
|
|
||||||
val path: String? = null,
|
|
||||||
val token: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "item_type")
|
|
||||||
val itemType: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "share_with_displayname")
|
|
||||||
val sharedWithDisplayName: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "share_with_additional_info")
|
|
||||||
val sharedWithAdditionalInfo: String? = null,
|
|
||||||
|
|
||||||
val name: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "url")
|
|
||||||
val shareLink: String? = null,
|
|
||||||
|
|
||||||
@Json(name = "share_type")
|
|
||||||
val shareType: Int? = null,
|
|
||||||
|
|
||||||
val permissions: Int? = null,
|
|
||||||
|
|
||||||
@Json(name = "stime")
|
|
||||||
val sharedDate: Long? = null,
|
|
||||||
|
|
||||||
@Json(name = "expiration")
|
|
||||||
val expirationDate: String? = null,
|
|
||||||
) {
|
|
||||||
fun toRemoteShare() = RemoteShare(
|
|
||||||
id = id ?: "0",
|
|
||||||
shareWith = shareWith.orEmpty(),
|
|
||||||
path = if (itemType == ItemType.FOLDER.fileValue) path.plus(File.separator) else path.orEmpty(),
|
|
||||||
token = token.orEmpty(),
|
|
||||||
itemType = itemType.orEmpty(),
|
|
||||||
sharedWithDisplayName = sharedWithDisplayName.orEmpty(),
|
|
||||||
sharedWithAdditionalInfo = sharedWithAdditionalInfo.orEmpty(),
|
|
||||||
name = name.orEmpty(),
|
|
||||||
shareLink = shareLink.orEmpty(),
|
|
||||||
shareType = ShareType.values().firstOrNull { it.value == shareType } ?: ShareType.UNKNOWN,
|
|
||||||
permissions = permissions ?: DEFAULT_PERMISSION,
|
|
||||||
sharedDate = sharedDate ?: INIT_SHARED_DATE,
|
|
||||||
expirationDate = expirationDate?.let {
|
|
||||||
WebdavUtils.parseResponseDate(it)?.time
|
|
||||||
} ?: INIT_EXPIRATION_DATE_IN_MILLIS,
|
|
||||||
isFolder = itemType?.equals(ItemType.FOLDER.fileValue) ?: false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class ItemType(val fileValue: String) { FILE("file"), FOLDER("folder") }
|
|
@ -1,72 +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.shares.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This was modeled according to the documentation:
|
|
||||||
* https://doc.owncloud.com/server/developer_manual/core/apis/ocs-recipient-api.html#get-shares-recipients
|
|
||||||
*/
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ShareeOcsResponse(
|
|
||||||
val exact: ExactSharees?,
|
|
||||||
val groups: List<ShareeItem>,
|
|
||||||
val remotes: List<ShareeItem>,
|
|
||||||
val users: List<ShareeItem>
|
|
||||||
) {
|
|
||||||
fun getFlatRepresentationWithoutExact() = ArrayList<ShareeItem>().apply {
|
|
||||||
addAll(users)
|
|
||||||
addAll(remotes)
|
|
||||||
addAll(groups)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ExactSharees(
|
|
||||||
val groups: List<ShareeItem>,
|
|
||||||
val remotes: List<ShareeItem>,
|
|
||||||
val users: List<ShareeItem>
|
|
||||||
) {
|
|
||||||
fun getFlatRepresentation() = ArrayList<ShareeItem>().apply {
|
|
||||||
addAll(users)
|
|
||||||
addAll(remotes)
|
|
||||||
addAll(groups)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ShareeItem(
|
|
||||||
val label: String,
|
|
||||||
val value: ShareeValue
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class ShareeValue(
|
|
||||||
val shareType: Int,
|
|
||||||
val shareWith: String,
|
|
||||||
@Json(name = "shareWithAdditionalInfo")
|
|
||||||
val additionalInfo: String?
|
|
||||||
)
|
|
@ -1,60 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2022 ownCloud GmbH.
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*
|
|
||||||
* 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.shares.services
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.Service
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareType
|
|
||||||
|
|
||||||
interface ShareService : Service {
|
|
||||||
fun getShares(
|
|
||||||
remoteFilePath: String,
|
|
||||||
reshares: Boolean,
|
|
||||||
subfiles: Boolean
|
|
||||||
): RemoteOperationResult<ShareResponse>
|
|
||||||
|
|
||||||
fun insertShare(
|
|
||||||
remoteFilePath: String,
|
|
||||||
shareType: ShareType,
|
|
||||||
shareWith: String,
|
|
||||||
permissions: Int,
|
|
||||||
name: String,
|
|
||||||
password: String,
|
|
||||||
expirationDate: Long,
|
|
||||||
): RemoteOperationResult<ShareResponse>
|
|
||||||
|
|
||||||
fun updateShare(
|
|
||||||
remoteId: String,
|
|
||||||
name: String,
|
|
||||||
password: String?,
|
|
||||||
expirationDate: Long,
|
|
||||||
permissions: Int,
|
|
||||||
): RemoteOperationResult<ShareResponse>
|
|
||||||
|
|
||||||
fun deleteShare(remoteId: String): RemoteOperationResult<Unit>
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2022 ownCloud GmbH.
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
*
|
|
||||||
* 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.shares.services.implementation
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation
|
|
||||||
import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation
|
|
||||||
import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.ShareType
|
|
||||||
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation
|
|
||||||
import com.owncloud.android.lib.resources.shares.services.ShareService
|
|
||||||
|
|
||||||
class OCShareService(override val client: OwnCloudClient) : ShareService {
|
|
||||||
override fun getShares(
|
|
||||||
remoteFilePath: String,
|
|
||||||
reshares: Boolean,
|
|
||||||
subfiles: Boolean
|
|
||||||
): RemoteOperationResult<ShareResponse> = GetRemoteSharesForFileOperation(
|
|
||||||
remoteFilePath,
|
|
||||||
reshares,
|
|
||||||
subfiles
|
|
||||||
).execute(client)
|
|
||||||
|
|
||||||
override fun insertShare(
|
|
||||||
remoteFilePath: String,
|
|
||||||
shareType: ShareType,
|
|
||||||
shareWith: String,
|
|
||||||
permissions: Int,
|
|
||||||
name: String,
|
|
||||||
password: String,
|
|
||||||
expirationDate: Long,
|
|
||||||
): RemoteOperationResult<ShareResponse> =
|
|
||||||
CreateRemoteShareOperation(
|
|
||||||
remoteFilePath,
|
|
||||||
shareType,
|
|
||||||
shareWith,
|
|
||||||
permissions
|
|
||||||
).apply {
|
|
||||||
this.name = name
|
|
||||||
this.password = password
|
|
||||||
this.expirationDateInMillis = expirationDate
|
|
||||||
this.retrieveShareDetails = true
|
|
||||||
}.execute(client)
|
|
||||||
|
|
||||||
override fun updateShare(
|
|
||||||
remoteId: String,
|
|
||||||
name: String,
|
|
||||||
password: String?,
|
|
||||||
expirationDate: Long,
|
|
||||||
permissions: Int,
|
|
||||||
): RemoteOperationResult<ShareResponse> =
|
|
||||||
UpdateRemoteShareOperation(
|
|
||||||
remoteId
|
|
||||||
).apply {
|
|
||||||
this.name = name
|
|
||||||
this.password = password
|
|
||||||
this.expirationDateInMillis = expirationDate
|
|
||||||
this.permissions = permissions
|
|
||||||
this.retrieveShareDetails = true
|
|
||||||
}.execute(client)
|
|
||||||
|
|
||||||
override fun deleteShare(remoteId: String): RemoteOperationResult<Unit> =
|
|
||||||
RemoveRemoteShareOperation(
|
|
||||||
remoteId
|
|
||||||
).execute(client)
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
|
||||||
* Copyright (C) 2022 ownCloud GmbH.
|
|
||||||
*
|
|
||||||
* @author David González Verdugo
|
|
||||||
* 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.shares.services.implementation
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation
|
|
||||||
import com.owncloud.android.lib.resources.shares.responses.ShareeOcsResponse
|
|
||||||
import com.owncloud.android.lib.resources.shares.services.ShareeService
|
|
||||||
|
|
||||||
class OCShareeService(override val client: OwnCloudClient) :
|
|
||||||
ShareeService {
|
|
||||||
override fun getSharees(
|
|
||||||
searchString: String,
|
|
||||||
page: Int,
|
|
||||||
perPage: Int
|
|
||||||
): RemoteOperationResult<ShareeOcsResponse> =
|
|
||||||
GetRemoteShareesOperation(
|
|
||||||
searchString,
|
|
||||||
page,
|
|
||||||
perPage
|
|
||||||
).execute(client)
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/* 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.spaces
|
|
||||||
|
|
||||||
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.GetMethod
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.spaces.responses.SpaceResponse
|
|
||||||
import com.owncloud.android.lib.resources.spaces.responses.SpacesResponseWrapper
|
|
||||||
import com.squareup.moshi.JsonAdapter
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class GetRemoteSpacesOperation : RemoteOperation<List<SpaceResponse>>() {
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<List<SpaceResponse>> {
|
|
||||||
val requestUri = buildRequestUri(client.baseUri)
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(requestUri.toString()))
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val status = client.executeHttpMethod(getMethod)
|
|
||||||
val response = getMethod.getResponseBodyAsString()
|
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
onRequestSuccessful(response)
|
|
||||||
} else {
|
|
||||||
onResultUnsuccessful(getMethod, response, status)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "Exception while getting remote shares")
|
|
||||||
RemoteOperationResult(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildRequestUri(baseUri: Uri) =
|
|
||||||
baseUri.buildUpon()
|
|
||||||
.appendEncodedPath(GRAPH_API_PATH)
|
|
||||||
.appendEncodedPath(ENDPOINT_SPACES_LIST)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private fun parseResponse(response: String): List<SpaceResponse> {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val adapter: JsonAdapter<SpacesResponseWrapper> = moshi.adapter(SpacesResponseWrapper::class.java)
|
|
||||||
return adapter.fromJson(response)?.value ?: listOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onResultUnsuccessful(
|
|
||||||
method: GetMethod,
|
|
||||||
response: String?,
|
|
||||||
status: Int
|
|
||||||
): RemoteOperationResult<List<SpaceResponse>> {
|
|
||||||
Timber.e("Failed response while getting spaces for user")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
return RemoteOperationResult(method)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRequestSuccessful(response: String?): RemoteOperationResult<List<SpaceResponse>> {
|
|
||||||
val result = RemoteOperationResult<List<SpaceResponse>>(RemoteOperationResult.ResultCode.OK)
|
|
||||||
Timber.d("Successful response: $response")
|
|
||||||
result.data = response?.let { parseResponse(it) } ?: listOf()
|
|
||||||
Timber.d("*** Fetch of spaces completed and parsed to ${result.data}")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val GRAPH_API_PATH = "graph/v1.0"
|
|
||||||
private const val ENDPOINT_SPACES_LIST = "me/drives"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
/* 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.spaces.responses
|
|
||||||
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class SpacesResponseWrapper(
|
|
||||||
val value: List<SpaceResponse>
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class SpaceResponse(
|
|
||||||
val description: String?,
|
|
||||||
val driveAlias: String,
|
|
||||||
val driveType: String,
|
|
||||||
val id: String,
|
|
||||||
val lastModifiedDateTime: String?,
|
|
||||||
val name: String,
|
|
||||||
val owner: OwnerResponse?,
|
|
||||||
val quota: QuotaResponse?,
|
|
||||||
val root: RootResponse,
|
|
||||||
val special: List<SpecialResponse>?,
|
|
||||||
val webUrl: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class OwnerResponse(
|
|
||||||
val user: UserResponse
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class QuotaResponse(
|
|
||||||
val remaining: Long?,
|
|
||||||
val state: String?,
|
|
||||||
val total: Long,
|
|
||||||
val used: Long?,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class RootResponse(
|
|
||||||
val eTag: String?,
|
|
||||||
val id: String,
|
|
||||||
val webDavUrl: String,
|
|
||||||
val deleted: DeleteResponse?,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class SpecialResponse(
|
|
||||||
val eTag: String,
|
|
||||||
val file: FileResponse,
|
|
||||||
val id: String,
|
|
||||||
val lastModifiedDateTime: String,
|
|
||||||
val name: String,
|
|
||||||
val size: Int,
|
|
||||||
val specialFolder: SpecialFolderResponse,
|
|
||||||
val webDavUrl: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class UserResponse(
|
|
||||||
val id: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class FileResponse(
|
|
||||||
val mimeType: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class DeleteResponse(
|
|
||||||
val state: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class SpecialFolderResponse(
|
|
||||||
val name: String
|
|
||||||
)
|
|
@ -1,34 +0,0 @@
|
|||||||
/* 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.spaces.services
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.spaces.GetRemoteSpacesOperation
|
|
||||||
import com.owncloud.android.lib.resources.spaces.responses.SpaceResponse
|
|
||||||
|
|
||||||
class OCSpacesService(override val client: OwnCloudClient) : SpacesService {
|
|
||||||
override fun getSpaces(): RemoteOperationResult<List<SpaceResponse>> {
|
|
||||||
return GetRemoteSpacesOperation().execute(client)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
/* 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.spaces.services
|
|
||||||
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
|
||||||
import com.owncloud.android.lib.resources.Service
|
|
||||||
import com.owncloud.android.lib.resources.spaces.responses.SpaceResponse
|
|
||||||
|
|
||||||
interface SpacesService : Service {
|
|
||||||
fun getSpaces(): RemoteOperationResult<List<SpaceResponse>>
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user