1
0
mirror of https://github.com/owncloud/android-library.git synced 2026-08-13 09:23:00 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mendhak
2016-01-30 08:34:24 +00:00
54 changed files with 4276 additions and 493 deletions
@@ -49,13 +49,15 @@ import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
public class OwnCloudClient extends HttpClient {
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
public static final int MAX_REDIRECTIONS_COUNT = 3;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
@@ -67,6 +69,8 @@ public class OwnCloudClient extends HttpClient {
private int mInstanceNumber = 0;
private Uri mBaseUri;
private OwnCloudVersion mVersion = null;
/**
* Constructor
@@ -168,13 +172,13 @@ public class OwnCloudClient extends HttpClient {
*
* The timeouts are both in milliseconds; 0 means 'infinite';
* < 0 means 'do not change the default'
*
*
* @param method HTTP method request.
* @param readTimeout Timeout to set for data reception
* @param connectionTimeout Timeout to set for connection establishment
*/
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout)
throws HttpException, IOException {
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException {
int oldSoTimeout = getParams().getSoTimeout();
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
try {
@@ -191,55 +195,53 @@ public class OwnCloudClient extends HttpClient {
getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
}
}
@Override
public int executeMethod(HttpMethod method) throws IOException, HttpException {
try { // just to log
boolean customRedirectionNeeded = false;
try {
method.setFollowRedirects(mFollowRedirects);
} catch (Exception e) {
/*
if (mFollowRedirects)
Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName()
+ " method, custom redirection will be used if needed");
*/
customRedirectionNeeded = mFollowRedirects;
}
/**
* Requests the received method.
*
* Executes the method through the inherited HttpClient.executedMethod(method).
*
* @param method HTTP method request.
*/
@Override
public int executeMethod(HttpMethod method) throws IOException {
try {
// Update User Agent
HttpParams params = method.getParams();
String userAgent = OwnCloudClientManagerFactory.getUserAgent();
params.setParameter(HttpMethodParams.USER_AGENT, userAgent);
Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
// logCookiesAtRequest(method.getRequestHeaders(), "before");
// logCookiesAtState("before");
int status = super.executeMethod(method);
if (customRedirectionNeeded) {
status = patchRedirection(status, method);
}
method.setFollowRedirects(false);
int status = super.executeMethod(method);
if (mFollowRedirects) {
status = followRedirection(method).getLastStatus();
}
// logCookiesAtRequest(method.getRequestHeaders(), "after");
// logCookiesAtState("after");
// logSetCookiesAtResponse(method.getResponseHeaders());
return status;
return status;
} catch (IOException e) {
Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
throw e;
//Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
throw e;
}
}
private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException {
public RedirectionPath followRedirection(HttpMethod method) throws IOException {
int redirectionsCount = 0;
int status = method.getStatusCode();
RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
( status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
@@ -254,18 +256,20 @@ public class OwnCloudClient extends HttpClient {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location.getValue());
String locationStr = location.getValue();
result.addLocation(locationStr);
// Release the connection to avoid reach the max number of connections per host
// due to it will be set a different url
exhaustResponse(method.getResponseBodyAsStream());
method.releaseConnection();
method.setURI(new URI(location.getValue(), true));
method.setURI(new URI(locationStr, true));
Header destination = method.getRequestHeader("Destination");
if (destination == null) {
destination = method.getRequestHeader("destination");
}
if (destination != null) {
String locationStr = location.getValue();
int suffixIndex = locationStr.lastIndexOf(
(mCredentials instanceof OwnCloudBearerCredentials) ?
AccountUtils.ODAV_PATH :
@@ -281,6 +285,7 @@ public class OwnCloudClient extends HttpClient {
method.setRequestHeader(destination);
}
status = super.executeMethod(method);
result.addStatus(status);
redirectionsCount++;
} else {
@@ -288,7 +293,7 @@ public class OwnCloudClient extends HttpClient {
status = HttpStatus.SC_NOT_FOUND;
}
}
return status;
return result;
}
/**
@@ -356,7 +361,10 @@ public class OwnCloudClient extends HttpClient {
mFollowRedirects = followRedirects;
}
public boolean getFollowRedirects() {
return mFollowRedirects;
}
private void logCookiesAtRequest(Header[] headers, String when) {
int counter = 0;
for (int i=0; i<headers.length; i++) {
@@ -436,4 +444,11 @@ public class OwnCloudClient extends HttpClient {
}
public void setOwnCloudVersion(OwnCloudVersion version){
mVersion = version;
}
public OwnCloudVersion getOwnCloudVersion(){
return mVersion;
}
}
@@ -82,8 +82,9 @@ public class OwnCloudClientFactory {
boolean isSamlSso =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
if (isOauth2) {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
@@ -100,11 +101,10 @@ public class OwnCloudClientFactory {
false);
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
String password = am.blockingGetAuthToken(
account,
@@ -136,7 +136,8 @@ public class OwnCloudClientFactory {
boolean isSamlSso =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
@@ -166,12 +167,11 @@ public class OwnCloudClientFactory {
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) throw new AuthenticatorException("WTF!");
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
//String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(),
// false);
@@ -36,8 +36,8 @@ public class OwnCloudCredentialsFactory {
return new OwnCloudBearerCredentials(authToken);
}
public static OwnCloudCredentials newSamlSsoCredentials(String sessionCookie) {
return new OwnCloudSamlSsoCredentials(sessionCookie);
public static OwnCloudCredentials newSamlSsoCredentials(String username, String sessionCookie) {
return new OwnCloudSamlSsoCredentials(username, sessionCookie);
}
public static final OwnCloudCredentials getAnonymousCredentials() {
@@ -30,9 +30,11 @@ import android.net.Uri;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
private String mUsername;
private String mSessionCookie;
public OwnCloudSamlSsoCredentials(String sessionCookie) {
public OwnCloudSamlSsoCredentials(String username, String sessionCookie) {
mUsername = username != null ? username : "";
mSessionCookie = sessionCookie != null ? sessionCookie : "";
}
@@ -63,8 +65,8 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
@Override
public String getUsername() {
// its unknown
return null;
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override
@@ -167,7 +167,9 @@ public class AccountUtils {
boolean isSamlSso = am.getUserData(
account,
AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
@@ -182,10 +184,9 @@ public class AccountUtils {
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
String password = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
@@ -199,7 +200,7 @@ public class AccountUtils {
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
@@ -209,7 +210,21 @@ public class AccountUtils {
}
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);
}
String accountName = username + "@" + url;
return accountName;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
@@ -336,12 +351,18 @@ public class AccountUtils {
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
/**
* Flag signaling if the ownCloud server supports Share API"
*/
* @deprecated
*/
public static final String KEY_SUPPORTS_SHARE_API = "oc_supports_share_api";
/**
* OC accout cookies
* OC account cookies
*/
public static final String KEY_COOKIES = "oc_account_cookies";
}
/**
* OC account version
*/
public static final String KEY_OC_ACCOUNT_VERSION = "oc_account_version";
}
}
@@ -0,0 +1,127 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
*
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import org.apache.http.HttpStatus;
import java.util.Arrays;
/**
* Aggregate saving the list of URLs followed in a sequence of redirections during the exceution of a
* {@link com.owncloud.android.lib.common.operations.RemoteOperation}, and the status codes corresponding to all
* of them.
*
* The last status code saved corresponds to the first response not being a redirection, unless the sequence exceeds
* the maximum length of redirections allowed by the {@link com.owncloud.android.lib.common.OwnCloudClient} instance
* that ran the operation.
*
* If no redirection was followed, the last (and first) status code contained corresponds to the original URL in the
* request.
*/
public class RedirectionPath {
private int[] mStatuses = null;
private int mLastStatus = -1;
private String[] mLocations = null;
private int mLastLocation = -1;
private int maxRedirections;
/**
* Public constructor.
*
* @param status Status code resulting of executing a request on the original URL.
* @param maxRedirections Maximum number of redirections that will be contained.
* @throws IllegalArgumentException If 'maxRedirections' is < 0
*/
public RedirectionPath(int status, int maxRedirections) {
if (maxRedirections < 0) {
throw new IllegalArgumentException("maxRedirections MUST BE zero or greater");
}
mStatuses = new int[maxRedirections + 1];
Arrays.fill(mStatuses, -1);
mStatuses[++mLastStatus] = status;
}
/**
* Adds a new location URL to the list of followed redirections.
*
* @param location URL extracted from a 'Location' header in a redirection.
*/
public void addLocation(String location) {
if (mLocations == null) {
mLocations = new String[mStatuses.length - 1];
}
if (mLastLocation < mLocations.length - 1) {
mLocations[++mLastLocation] = location;
}
}
/**
* Adds a new status code to the list of status corresponding to followed redirections.
*
* @param status Status code from the response of another followed redirection.
*/
public void addStatus(int status) {
if (mLastStatus < mStatuses.length - 1) {
mStatuses[++mLastStatus] = status;
}
}
/**
* @return Last status code saved.
*/
public int getLastStatus() {
return mStatuses[mLastStatus];
}
/**
* @return Last location followed corresponding to a permanent redirection (status code 301).
*/
public String getLastPermanentLocation() {
for (int i = mLastStatus; i >= 0; i--) {
if (mStatuses[i] == HttpStatus.SC_MOVED_PERMANENTLY && i <= mLastLocation) {
return mLocations[i];
}
}
return null;
}
/**
* @return Count of locations.
*/
public int getRedirectionsCount() {
return mLastLocation + 1;
}
}
@@ -24,6 +24,7 @@
package com.owncloud.android.lib.common.network;
import java.math.BigDecimal;
import java.util.Date;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
@@ -37,6 +38,9 @@ import android.net.Uri;
import com.owncloud.android.lib.common.utils.Log_OC;
public class WebdavEntry {
private static final String TAG = WebdavEntry.class.getSimpleName();
public static final String NAMESPACE_OC = "http://owncloud.org/ns";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
@@ -49,7 +53,7 @@ public class WebdavEntry {
private String mName, mPath, mUri, mContentType, mEtag, mPermissions, mRemoteId;
private long mContentLength, mCreateTimestamp, mModifiedTimestamp, mSize;
private long mQuotaUsedBytes, mQuotaAvailableBytes;
private BigDecimal mQuotaUsedBytes, mQuotaAvailableBytes;
public WebdavEntry(MultiStatusResponse ms, String splitElement) {
resetData();
@@ -125,20 +129,37 @@ public class WebdavEntry {
prop = propSet.get(DavPropertyName.GETETAG);
if (prop != null) {
mEtag = (String) prop.getValue();
mEtag = mEtag.substring(1, mEtag.length()-1);
mEtag = WebdavUtils.parseEtag(mEtag);
}
// {DAV:}quota-used-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_USED_BYTES));
if (prop != null) {
mQuotaUsedBytes = Long.parseLong((String) prop.getValue());
String quotaUsedBytesSt = (String) prop.getValue();
try {
mQuotaUsedBytes = new BigDecimal(quotaUsedBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaUsedBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaUsedBytes - NullPointerException");
}
Log_OC.d(TAG , "QUOTA_USED_BYTES " + quotaUsedBytesSt );
}
// {DAV:}quota-available-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_AVAILABLE_BYTES));
if (prop != null) {
mQuotaAvailableBytes = Long.parseLong((String) prop.getValue());
String quotaAvailableBytesSt = (String) prop.getValue();
try {
mQuotaAvailableBytes = new BigDecimal(quotaAvailableBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaAvailableBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaAvailableBytes");
}
Log_OC.d(TAG , "QUOTA_AVAILABLE_BYTES " + quotaAvailableBytesSt );
}
// OC permissions property <oc:permissions>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_PERMISSIONS, Namespace.getNamespace(NAMESPACE_OC)
@@ -222,11 +243,11 @@ public class WebdavEntry {
return mSize;
}
public long quotaUsedBytes() {
public BigDecimal quotaUsedBytes() {
return mQuotaUsedBytes;
}
public long quotaAvailableBytes() {
public BigDecimal quotaAvailableBytes() {
return mQuotaAvailableBytes;
}
@@ -234,7 +255,7 @@ public class WebdavEntry {
mName = mUri = mContentType = mPermissions = null; mRemoteId = null;
mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
mSize = 0;
mQuotaUsedBytes = 0;
mQuotaAvailableBytes = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
}
}
@@ -32,6 +32,8 @@ import java.util.Locale;
import android.net.Uri;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.xml.Namespace;
@@ -131,4 +133,47 @@ public class WebdavUtils {
return propSet;
}
/**
*
* @param rawEtag
* @return
*/
public static String parseEtag(String rawEtag) {
if (rawEtag == null || rawEtag.length() == 0) {
return "";
}
if (rawEtag.endsWith("-gzip")) {
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
}
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
}
return rawEtag;
}
/**
*
* @param method
* @return
*/
public static String getEtagFromResponse(HttpMethod method) {
Header eTag = method.getResponseHeader("OC-ETag");
if (eTag == null) {
eTag = method.getResponseHeader("oc-etag");
}
if (eTag == null) {
eTag = method.getResponseHeader("ETag");
}
if (eTag == null) {
eTag = method.getResponseHeader("etag");
}
String result = "";
if (eTag != null) {
result = parseEtag(eTag.getValue());
}
return result;
}
}
@@ -0,0 +1,146 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}
@@ -24,8 +24,6 @@
package com.owncloud.android.lib.common.operations;
import java.io.IOException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
@@ -42,6 +40,8 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
/**
* Operation which execution involves one or several interactions with an ownCloud server.
@@ -24,15 +24,21 @@
package com.owncloud.android.lib.common.operations;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountsException;
import javax.net.ssl.SSLException;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.Header;
@@ -41,60 +47,55 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.json.JSONException;
import android.accounts.Account;
import android.accounts.AccountsException;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.SSLException;
/**
* The result of a remote operation required to an ownCloud server.
*
* <p/>
* Provides a common classification of remote operation results for all the
* application.
*
*
* @author David A. Velasco
*/
public class RemoteOperationResult implements Serializable {
/** Generated - should be refreshed every time the class changes!! */;
private static final long serialVersionUID = -9003837206000993465L;
private static final String TAG = "RemoteOperationResult";
public enum ResultCode {
private static final long serialVersionUID = 1129130415603799707L;
private static final String TAG = RemoteOperationResult.class.getSimpleName();
public enum ResultCode {
OK,
OK_SSL,
OK_NO_SSL,
UNHANDLED_HTTP_CODE,
UNAUTHORIZED,
FILE_NOT_FOUND,
INSTANCE_NOT_CONFIGURED,
UNKNOWN_ERROR,
WRONG_CONNECTION,
TIMEOUT,
INCORRECT_ADDRESS,
HOST_NOT_AVAILABLE,
NO_NETWORK_CONNECTION,
UNAUTHORIZED,
FILE_NOT_FOUND,
INSTANCE_NOT_CONFIGURED,
UNKNOWN_ERROR,
WRONG_CONNECTION,
TIMEOUT,
INCORRECT_ADDRESS,
HOST_NOT_AVAILABLE,
NO_NETWORK_CONNECTION,
SSL_ERROR,
SSL_RECOVERABLE_PEER_UNVERIFIED,
BAD_OC_VERSION,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
INVALID_OVERWRITE,
CONFLICT,
CONFLICT,
OAUTH2_ERROR,
SYNC_CONFLICT,
LOCAL_STORAGE_FULL,
LOCAL_STORAGE_NOT_MOVED,
LOCAL_STORAGE_NOT_COPIED,
LOCAL_STORAGE_FULL,
LOCAL_STORAGE_NOT_MOVED,
LOCAL_STORAGE_NOT_COPIED,
OAUTH2_ERROR_ACCESS_DENIED,
QUOTA_EXCEEDED,
ACCOUNT_NOT_FOUND,
ACCOUNT_EXCEPTION,
ACCOUNT_NOT_NEW,
QUOTA_EXCEEDED,
ACCOUNT_NOT_FOUND,
ACCOUNT_EXCEPTION,
ACCOUNT_NOT_NEW,
ACCOUNT_NOT_THE_SAME,
INVALID_CHARACTER_IN_NAME,
SHARE_NOT_FOUND,
@@ -102,8 +103,12 @@ public class RemoteOperationResult implements Serializable {
FORBIDDEN,
SHARE_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
INVALID_MOVE_INTO_DESCENDANT,
PARTIAL_MOVE_DONE
INVALID_MOVE_INTO_DESCENDANT,
INVALID_COPY_INTO_DESCENDANT,
PARTIAL_MOVE_DONE,
PARTIAL_COPY_DONE,
SHARE_WRONG_PARAMETER,
WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER
}
private boolean mSuccess = false;
@@ -112,12 +117,15 @@ public class RemoteOperationResult implements Serializable {
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private String mAuthenticate;
private String mLastPermanentLocation = null;
private ArrayList<Object> mData;
public RemoteOperationResult(ResultCode code) {
mCode = code;
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL || code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
code == ResultCode.OK_NO_SSL ||
code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mData = null;
}
@@ -147,31 +155,63 @@ public class RemoteOperationResult implements Serializable {
break;
case HttpStatus.SC_FORBIDDEN:
mCode = ResultCode.FORBIDDEN;
break;
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode);
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
public RemoteOperationResult(boolean success, int httpCode, Header[] headers) {
this(success, httpCode);
if (headers != null) {
Header current;
for (int i=0; i<headers.length; i++) {
for (int i = 0; i < headers.length; i++) {
current = headers[i];
if ("location".equals(current.getName().toLowerCase())) {
mRedirectedLocation = current.getValue();
continue;
}
if ("www-authenticate".equals(current.getName().toLowerCase())) {
mAuthenticate = current.getValue();
continue;
mAuthenticate = current.getValue();
continue;
}
}
}
}
}
public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) {
mSuccess = success;
mHttpCode = httpCode;
if (success) {
mCode = ResultCode.OK;
} else if (httpCode > 0) {
switch (httpCode) {
case HttpStatus.SC_BAD_REQUEST:
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
try {
if (xmlParser.parseXMLResponse(is))
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
} catch (Exception e) {
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
public RemoteOperationResult(Exception e) {
mException = e;
@@ -196,10 +236,10 @@ public class RemoteOperationResult implements Serializable {
} else if (e instanceof AccountNotFoundException) {
mCode = ResultCode.ACCOUNT_NOT_FOUND;
} else if (e instanceof AccountsException) {
mCode = ResultCode.ACCOUNT_EXCEPTION;
} else if (e instanceof SSLException || e instanceof RuntimeException) {
CertificateCombinedException se = getCertificateCombinedException(e);
if (se != null) {
@@ -221,14 +261,14 @@ public class RemoteOperationResult implements Serializable {
}
public void setData(ArrayList<Object> files){
mData = files;
public void setData(ArrayList<Object> files) {
mData = files;
}
public ArrayList<Object> getData(){
return mData;
}
public ArrayList<Object> getData() {
return mData;
}
public boolean isSuccess() {
return mSuccess;
}
@@ -253,9 +293,9 @@ public class RemoteOperationResult implements Serializable {
return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
public boolean isRedirectToNonSecureConnection() {
return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION;
}
public boolean isRedirectToNonSecureConnection() {
return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION;
}
private CertificateCombinedException getCertificateCombinedException(Exception e) {
CertificateCombinedException result = null;
@@ -264,7 +304,8 @@ public class RemoteOperationResult implements Serializable {
}
Throwable cause = mException.getCause();
Throwable previousCause = null;
while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
while (cause != null && cause != previousCause &&
!(cause instanceof CertificateCombinedException)) {
previousCause = cause;
cause = cause.getCause();
}
@@ -314,15 +355,17 @@ public class RemoteOperationResult implements Serializable {
return "Unrecovered transport exception";
} else if (mException instanceof AccountNotFoundException) {
Account failedAccount = ((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" + (failedAccount != null ? failedAccount.name : "NULL") + ")";
Account failedAccount =
((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" +
(failedAccount != null ? failedAccount.name : "NULL") + ")";
} else if (mException instanceof AccountsException) {
return "Exception while using account";
} else if (mException instanceof JSONException) {
return "JSON exception";
return "JSON exception";
} else {
return "Unexpected exception";
}
@@ -348,13 +391,19 @@ public class RemoteOperationResult implements Serializable {
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
return "Authenticated with a different account than the one updating";
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
return "The file name contains an forbidden character";
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
return "Local file does not exist";
}
return "Operation finished with HTTP status code " + mHttpCode + " (" + (isSuccess() ? "success" : "fail") + ")";
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
return "Local file does not exist";
} else if (mCode == ResultCode.SYNC_CONFLICT) {
return "Synchronization conflict";
}
return "Operation finished with HTTP status code " + mHttpCode + " (" +
(isSuccess() ? "success" : "fail") + ")";
}
@@ -373,24 +422,32 @@ public class RemoteOperationResult implements Serializable {
public String getRedirectedLocation() {
return mRedirectedLocation;
}
public boolean isIdPRedirection() {
return (mRedirectedLocation != null &&
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
/**
* Checks if is a non https connection
*
* @return boolean true/false
*/
public boolean isNonSecureRedirection() {
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
/**
* Checks if is a non https connection
*
* @return boolean true/false
*/
public boolean isNonSecureRedirection() {
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
public String getAuthenticateHeader() {
return mAuthenticate;
return mAuthenticate;
}
public String getLastPermanentLocation() {
return mLastPermanentLocation;
}
public void setLastPermanentLocation(String lastPermanentLocation) {
mLastPermanentLocation = lastPermanentLocation;
}
}
@@ -32,8 +32,7 @@ public class Log_OC {
}
public static void i(String TAG, String message){
// Write the log message to the file
Log.i(TAG, message);
appendLog(TAG+" : "+ message);
}
@@ -61,7 +60,7 @@ public class Log_OC {
}
public static void w(String TAG, String message) {
Log.w(TAG,message);
Log.w(TAG, message);
appendLog(TAG+" : "+ message);
}
@@ -100,8 +99,16 @@ public class Log_OC {
}
} catch (IOException e) {
e.printStackTrace();
}
e.printStackTrace();
} finally {
if(mBuf != null) {
try {
mBuf.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
/**
@@ -160,10 +167,15 @@ public class Log_OC {
mBuf.newLine();
mBuf.write(text);
mBuf.newLine();
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check if current log file size is bigger than the max file size defined
if (mLogFile.length() > MAX_FILE_SIZE) {
@@ -24,19 +24,21 @@
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Random;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.utils.Log_OC;
@@ -44,14 +46,21 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
public static final long CHUNK_SIZE = 1024000;
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
private static final String OC_CHUNK_SIZE_HEADER = "OC-Chunk-Size";
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType) {
super(storagePath, remotePath, mimeType);
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType){
super(storagePath, remotePath, mimeType);
}
public ChunkedUploadRemoteFileOperation(
String storagePath, String remotePath, String mimeType, String requiredEtag
){
super(storagePath, remotePath, mimeType, requiredEtag);
}
@Override
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException {
protected int uploadFile(OwnCloudClient client) throws IOException {
int status = -1;
FileChannel channel = null;
@@ -61,25 +70,60 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
//((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(getDataTransferListeners());
synchronized (mDataTransferListeners) {
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
((ProgressiveDataTransferer)mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
long offset = 0;
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) +
"-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
long totalLength = file.length();
long chunkCount = (long) Math.ceil((double)totalLength / CHUNK_SIZE);
String chunkSizeStr = String.valueOf(CHUNK_SIZE);
String totalLengthStr = String.valueOf(file.length());
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
if (chunkIndex == chunkCount - 1) {
chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength);
}
if (mPutMethod != null) {
mPutMethod.releaseConnection(); // let the connection available for other methods
mPutMethod.releaseConnection(); // let the connection available
// for other methods
}
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr);
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr);
((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset);
mPutMethod.setRequestEntity(mEntity);
if (mCancellationRequested.get()) {
mPutMethod.abort();
// next method will throw an exception
}
status = client.executeMethod(mPutMethod);
if (status == 400) {
InvalidCharacterExceptionParser xmlParser =
new InvalidCharacterExceptionParser();
InputStream is = new ByteArrayInputStream(
mPutMethod.getResponseBodyAsString().getBytes());
try {
mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);
} catch (Exception e) {
mForbiddenCharsInServer = false;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
}
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
", chunk index " + chunkIndex + ", count " + chunkCount +
", HTTP result status " + status);
if (!isSuccess(status))
break;
}
@@ -0,0 +1,215 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.Status;
import org.apache.jackrabbit.webdav.client.methods.CopyMethod;
import java.io.IOException;
/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
* <p/>
* Allows renaming the moving file/folder at the same time.
*
* @author David A. Velasco
*/
public class CopyRemoteFileOperation extends RemoteOperation {
private static final String TAG = CopyRemoteFileOperation.class.getSimpleName();
private static final int COPY_READ_TIMEOUT = 600000;
private static final int COPY_CONNECTION_TIMEOUT = 5000;
private String mSrcRemotePath;
private String mTargetRemotePath;
private boolean mOverwrite;
/**
* Constructor.
* <p/>
* TODO Paths should finish in "/" in the case of folders. ?
*
* @param srcRemotePath Remote path of the file/folder to move.
* @param targetRemotePath Remove path desired for the file/folder after moving it.
*/
public CopyRemoteFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite
) {
mSrcRemotePath = srcRemotePath;
mTargetRemotePath = targetRemotePath;
mOverwrite = overwrite;
}
/**
* Performs the rename operation.
*
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
return new RemoteOperationResult(ResultCode.OK);
}
if (mTargetRemotePath.startsWith(mSrcRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT);
}
/// perform remote operation
CopyMethod copyMethod = null;
RemoteOperationResult result = null;
try {
copyMethod = new CopyMethod(
client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite
);
int status = client.executeMethod(copyMethod, COPY_READ_TIMEOUT, COPY_CONNECTION_TIMEOUT);
/// process response
if (status == HttpStatus.SC_MULTI_STATUS) {
result = processPartialError(copyMethod);
} else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) {
result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
/// for other errors that could be explicitly handled, check first:
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else if (status == 400) {
result = new RemoteOperationResult(copyMethod.succeeded(),
copyMethod.getResponseBodyAsString(), status);
} else {
result = new RemoteOperationResult(
isSuccess(status), // copy.succeeded()? trustful?
status,
copyMethod.getResponseHeaders()
);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
}
Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
} finally {
if (copyMethod != null)
copyMethod.releaseConnection();
}
return result;
}
/**
* Analyzes a multistatus response from the OC server to generate an appropriate result.
* <p/>
* In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some
* children are copied, some other aren't.
* <p/>
* According to the WebDAV specification, a multistatus response SHOULD NOT include partial
* successes (201, 204) nor for descendants of already failed children (424) in the response
* entity. But SHOULD NOT != MUST NOT, so take carefully.
*
* @param copyMethod Copy operation just finished with a multistatus response
* @return A result for the {@link com.owncloud.android.lib.resources.files.CopyRemoteFileOperation} caller
* @throws java.io.IOException If the response body could not be parsed
* @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining
* the response XML document fails
*/
private RemoteOperationResult processPartialError(CopyMethod copyMethod)
throws IOException, DavException {
// Adding a list of failed descendants to the result could be interesting; or maybe not.
// For the moment, let's take the easy way.
/// check that some error really occurred
MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses();
Status[] status;
boolean failFound = false;
for (int i = 0; i < responses.length && !failFound; i++) {
status = responses[i].getStatus();
failFound = (
status != null &&
status.length > 0 &&
status[0].getStatusCode() > 299
);
}
RemoteOperationResult result;
if (failFound) {
result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE);
} else {
result = new RemoteOperationResult(
true,
HttpStatus.SC_MULTI_STATUS,
copyMethod.getResponseHeaders()
);
}
return result;
}
protected boolean isSuccess(int status) {
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
}
}
@@ -24,7 +24,6 @@
package com.owncloud.android.lib.resources.files;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
@@ -33,7 +32,7 @@ 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.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
@@ -58,7 +57,8 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
* Constructor
*
* @param remotePath Full path to the new directory to create in the remote server.
* @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet.
* @param createFullPath 'True' means that all the ancestor folders should be created
* if don't exist yet.
*/
public CreateRemoteFolderOperation(String remotePath, boolean createFullPath) {
mRemotePath = remotePath;
@@ -73,7 +73,10 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath);
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
result = createFolder(client);
if (!result.isSuccess() && mCreateFullPath &&
@@ -98,9 +101,17 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
try {
mkcol = new MkColMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
int status = client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
result = new RemoteOperationResult(mkcol.succeeded(), status, mkcol.getResponseHeaders());
Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
client.exhaustResponse(mkcol.getResponseBodyAsStream());
if ( status == 400 ) {
result = new RemoteOperationResult(mkcol.succeeded(),
mkcol.getResponseBodyAsString(), status);
Log_OC.d(TAG, mkcol.getResponseBodyAsString());
} else {
result = new RemoteOperationResult(mkcol.succeeded(), status,
mkcol.getResponseHeaders());
Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
}
client.exhaustResponse(mkcol.getResponseBodyAsStream());
} catch (Exception e) {
result = new RemoteOperationResult(e);
@@ -61,6 +61,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private long mModificationTimestamp = 0;
private String mEtag = "";
private GetMethod mGet;
private String mRemotePath;
@@ -140,12 +141,24 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
if (transferred == totalToTransfer) { // Check if the file is completed
savedFile = true;
Header modificationTime = mGet.getResponseHeader("Last-Modified");
if (modificationTime == null) {
modificationTime = mGet.getResponseHeader("last-modified");
}
if (modificationTime != null) {
Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
mModificationTimestamp = (d != null) ? d.getTime() : 0;
}
} else {
Log_OC.e(TAG, "Could not read modification time from response downloading " + mRemotePath);
}
mEtag = WebdavUtils.getEtagFromResponse(mGet);
if (mEtag.length() == 0) {
Log_OC.e(TAG, "Could not read eTag from response downloading " + mRemotePath);
}
} else {
client.exhaustResponse(mGet.getResponseBodyAsStream());
// TODO some kind of error control!
}
} else {
@@ -190,4 +203,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
return mModificationTimestamp;
}
public String getEtag() {
return mEtag;
}
}
@@ -28,9 +28,9 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.HeadMethod;
import android.content.Context;
import android.net.ConnectivityManager;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -49,35 +49,50 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
private static final String TAG = ExistenceCheckRemoteOperation.class.getSimpleName();
private String mPath;
private Context mContext;
private boolean mSuccessIfAbsent;
/** Sequence of redirections followed. Available only after executing the operation */
private RedirectionPath mRedirectionPath = null;
// TODO move to {@link RemoteOperation}, that needs a nice refactoring
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param context Android application context.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
*/
public ExistenceCheckRemoteOperation(String remotePath, Context context, boolean successIfAbsent) {
public ExistenceCheckRemoteOperation(String remotePath, boolean successIfAbsent) {
mPath = (remotePath != null) ? remotePath : "";
mContext = context;
mSuccessIfAbsent = successIfAbsent;
}
@Override
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param context Android application context.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
* @deprecated
*/
public ExistenceCheckRemoteOperation(String remotePath, Context context, boolean successIfAbsent) {
this(remotePath, successIfAbsent);
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
if (!isOnline()) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
}
RemoteOperationResult result = null;
HeadMethod head = null;
boolean previousFollowRedirects = client.getFollowRedirects();
try {
head = new HeadMethod(client.getWebdavUri() + WebdavUtils.encodePath(mPath));
client.setFollowRedirects(false);
int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
if (previousFollowRedirects) {
mRedirectionPath = client.followRedirection(head);
status = mRedirectionPath.getLastStatus();
}
client.exhaustResponse(head.getResponseBodyAsStream());
boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) ||
(status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
@@ -97,16 +112,25 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
} finally {
if (head != null)
head.releaseConnection();
client.setFollowRedirects(previousFollowRedirects);
}
return result;
}
private boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm != null && cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnectedOrConnecting();
/**
* Gets the sequence of redirections followed during the execution of the operation.
*
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
*/
public RedirectionPath getRedirectionPath() {
return mRedirectionPath;
}
/**
* @return 'True' if the operation was executed and at least one redirection was followed.
*/
public boolean wasRedirected() {
return (mRedirectionPath != null && mRedirectionPath.getRedirectionsCount() > 0);
}
}
@@ -27,9 +27,12 @@ package com.owncloud.android.lib.resources.files;
import java.io.File;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
public class FileUtils {
private static final String TAG = FileUtils.class.getSimpleName();
public static final String PATH_SEPARATOR = "/";
@@ -40,39 +43,44 @@ public class FileUtils {
}
/**
* Validate the fileName to detect if contains any forbidden character: / , \ , < , > , : , " , | , ? , *
* Validate the fileName to detect if contains any forbidden character: / , \ , < , > ,
* : , " , | , ? , *
* @param fileName
* @param versionSupportsForbiddenChars
* @return
*/
public static boolean isValidName(String fileName) {
public static boolean isValidName(String fileName, boolean versionSupportsForbiddenChars) {
boolean result = true;
Log_OC.d("FileUtils", "fileName =======" + fileName);
if (fileName.contains(PATH_SEPARATOR) ||
Log_OC.d(TAG, "fileName =======" + fileName);
if ( (versionSupportsForbiddenChars && fileName.contains(PATH_SEPARATOR)) ||
(!versionSupportsForbiddenChars && ( fileName.contains(PATH_SEPARATOR) ||
fileName.contains("\\") || fileName.contains("<") || fileName.contains(">") ||
fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") ||
fileName.contains("?") || fileName.contains("*")) {
fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") ||
fileName.contains("?") || fileName.contains("*") ) ) ) {
result = false;
}
return result;
}
/**
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | , ? , *
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | ,
* ? , *
* @param path
* @return
*/
public static boolean isValidPath(String path) {
public static boolean isValidPath(String path, boolean versionSupportsForbidenChars) {
boolean result = true;
Log_OC.d("FileUtils", "path ....... " + path);
if (path.contains("\\") || path.contains("<") || path.contains(">") ||
Log_OC.d(TAG, "path ....... " + path);
if (!versionSupportsForbidenChars &&
(path.contains("\\") || path.contains("<") || path.contains(">") ||
path.contains(":") || path.contains("\"") || path.contains("|") ||
path.contains("?") || path.contains("*")) {
path.contains("?") || path.contains("*") ) ){
result = false;
}
return result;
}
}
@@ -39,6 +39,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
@@ -87,9 +88,13 @@ public class MoveRemoteFileOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath)) {
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
@@ -128,15 +133,17 @@ public class MoveRemoteFileOperation extends RemoteOperation {
/// for other errors that could be explicitly handled, check first:
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else {
result = new RemoteOperationResult(
isSuccess(status), // move.succeeded()? trustful?
status,
move.getResponseHeaders()
);
client.exhaustResponse(move.getResponseBodyAsStream());
}
} else if (status == 400) {
result = new RemoteOperationResult(move.succeeded(),
move.getResponseBodyAsString(), status);
} else {
result = new RemoteOperationResult(
isSuccess(status), // move.succeeded()? trustful?
status,
move.getResponseHeaders()
);
client.exhaustResponse(move.getResponseBodyAsStream());
}
Log.i(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage());
@@ -25,6 +25,7 @@
package com.owncloud.android.lib.resources.files;
import java.io.Serializable;
import java.math.BigDecimal;
import android.os.Parcel;
import android.os.Parcelable;
@@ -51,8 +52,8 @@ public class RemoteFile implements Parcelable, Serializable {
private String mPermissions;
private String mRemoteId;
private long mSize;
private long mQuotaUsedBytes;
private long mQuotaAvailableBytes;
private BigDecimal mQuotaUsedBytes;
private BigDecimal mQuotaAvailableBytes;
/**
* Getters and Setters
@@ -130,11 +131,11 @@ public class RemoteFile implements Parcelable, Serializable {
mSize = size;
}
public void setQuotaUsedBytes (long quotaUsedBytes) {
public void setQuotaUsedBytes (BigDecimal quotaUsedBytes) {
mQuotaUsedBytes = quotaUsedBytes;
}
public void setQuotaAvailableBytes (long quotaAvailableBytes) {
public void setQuotaAvailableBytes (BigDecimal quotaAvailableBytes) {
mQuotaAvailableBytes = quotaAvailableBytes;
}
@@ -184,8 +185,8 @@ public class RemoteFile implements Parcelable, Serializable {
mPermissions = null;
mRemoteId = null;
mSize = 0;
mQuotaUsedBytes = 0;
mQuotaAvailableBytes = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
}
/**
@@ -223,8 +224,8 @@ public class RemoteFile implements Parcelable, Serializable {
mPermissions= source.readString();
mRemoteId = source.readString();
mSize = source.readLong();
mQuotaUsedBytes = source.readLong();
mQuotaAvailableBytes = source.readLong();
mQuotaUsedBytes = (BigDecimal) source.readSerializable();
mQuotaAvailableBytes = (BigDecimal) source.readSerializable();
}
@Override
@@ -243,8 +244,8 @@ public class RemoteFile implements Parcelable, Serializable {
dest.writeString(mPermissions);
dest.writeString(mRemoteId);
dest.writeLong(mSize);
dest.writeLong(mQuotaUsedBytes);
dest.writeLong(mQuotaAvailableBytes);
dest.writeSerializable(mQuotaUsedBytes);
dest.writeSerializable(mQuotaAvailableBytes);
}
}
@@ -34,6 +34,7 @@ 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.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
@@ -88,42 +89,52 @@ public class RenameRemoteFileOperation extends RemoteOperation {
RemoteOperationResult result = null;
LocalMoveMethod move = null;
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath);
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult(ResultCode.OK);
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult(ResultCode.OK);
}
// check if a file with the new name already exists
if (client.existsFile(mNewRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
}
move = new LocalMoveMethod( client.getWebdavUri() +
WebdavUtils.encodePath(mOldRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mNewRemotePath));
int status = client.executeMethod(move, RENAME_READ_TIMEOUT,
RENAME_CONNECTION_TIMEOUT);
if (status == 400) {
result = new RemoteOperationResult(move.succeeded(),
move.getResponseBodyAsString(), status);
Log_OC.d(TAG, move.getResponseBodyAsString());
} else {
client.exhaustResponse(move.getResponseBodyAsStream());//exhaust response,
// although not interesting
result = new RemoteOperationResult(move.succeeded(), status,
move.getResponseHeaders());
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " +
result.getLogMessage(), e);
} finally {
if (move != null)
move.releaseConnection();
}
// check if a file with the new name already exists
if (client.existsFile(mNewRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
}
move = new LocalMoveMethod( client.getWebdavUri() +
WebdavUtils.encodePath(mOldRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mNewRemotePath));
int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
move.getResponseBodyAsString(); // exhaust response, although not interesting
result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders());
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " +
result.getLogMessage(), e);
} finally {
if (move != null)
move.releaseConnection();
}
} else {
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
@@ -24,13 +24,14 @@
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.http.HttpStatus;
@@ -40,9 +41,11 @@ import com.owncloud.android.lib.common.network.FileRequestEntity;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
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.utils.Log_OC;
/**
* Remote operation performing the upload of a remote file to the ownCloud server.
@@ -53,13 +56,19 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
public class UploadRemoteFileOperation extends RemoteOperation {
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
protected static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
protected static final String IF_MATCH_HEADER = "If-Match";
protected String mLocalPath;
protected String mRemotePath;
protected String mMimeType;
protected PutMethod mPutMethod = null;
protected boolean mForbiddenCharsInServer = false;
protected String mRequiredEtag = null;
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
protected RequestEntity mEntity = null;
@@ -67,7 +76,12 @@ public class UploadRemoteFileOperation extends RemoteOperation {
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType) {
mLocalPath = localPath;
mRemotePath = remotePath;
mMimeType = mimeType;
mMimeType = mimeType;
}
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType, String requiredEtag) {
this(localPath, remotePath, mimeType);
mRequiredEtag = requiredEtag;
}
@Override
@@ -75,25 +89,28 @@ public class UploadRemoteFileOperation extends RemoteOperation {
RemoteOperationResult result = null;
try {
// / perform the upload
synchronized (mCancellationRequested) {
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
if (mCancellationRequested.get()) {
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
result = new RemoteOperationResult(new OperationCancelledException());
} else {
// perform the upload
int status = uploadFile(client);
if (mForbiddenCharsInServer){
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
} else {
mPutMethod = new PutMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mRemotePath));
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
}
}
int status = uploadFile(client);
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
if (mPutMethod != null && mPutMethod.isAborted()) {
result = new RemoteOperationResult(new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
}
@@ -106,8 +123,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {
status == HttpStatus.SC_NO_CONTENT));
}
protected int uploadFile(OwnCloudClient client) throws HttpException, IOException,
OperationCancelledException {
protected int uploadFile(OwnCloudClient client) throws IOException {
int status = -1;
try {
File f = new File(mLocalPath);
@@ -116,8 +132,26 @@ public class UploadRemoteFileOperation extends RemoteOperation {
((ProgressiveDataTransferer)mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(f.length()));
mPutMethod.setRequestEntity(mEntity);
status = client.executeMethod(mPutMethod);
if (status == 400) {
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
InputStream is = new ByteArrayInputStream(
mPutMethod.getResponseBodyAsString().getBytes());
try {
mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);
} catch (Exception e) {
mForbiddenCharsInServer = false;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
}
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
} finally {
@@ -1,4 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,24 +26,16 @@
package com.owncloud.android.lib.resources.shares;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.http.HttpStatus;
import com.owncloud.android.lib.common.OwnCloudClient;
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.Log_OC;
/**
* Creates a new share. This allows sharing with a user or group or as a link.
*
* @author masensio
*
*/
public class CreateRemoteShareOperation extends RemoteOperation {
@@ -54,20 +48,20 @@ public class CreateRemoteShareOperation extends RemoteOperation {
private static final String PARAM_PASSWORD = "password";
private static final String PARAM_PERMISSIONS = "permissions";
private ArrayList<OCShare> mShares; // List of shares for result, one share in this case
private String mRemoteFilePath;
private ShareType mShareType;
private String mShareWith;
private boolean mPublicUpload;
private String mPassword;
private int mPermissions;
private boolean mGetShareDetails;
/**
* 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 shareWith User/group ID with who the file should be shared. This is mandatory for shareType
* of 0 or 1
* @param publicUpload If false (default) public cannot upload to a public shared folder.
* If true public can upload to a shared folder. Only available for public link shares
* @param password Password to protect a public link share. Only available for public link shares
@@ -81,8 +75,14 @@ public class CreateRemoteShareOperation extends RemoteOperation {
* To obtain combinations, add the desired values together.
* For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27.
*/
public CreateRemoteShareOperation(String remoteFilePath, ShareType shareType, String shareWith, boolean publicUpload,
String password, int permissions) {
public CreateRemoteShareOperation(
String remoteFilePath,
ShareType shareType,
String shareWith,
boolean publicUpload,
String password,
int permissions
) {
mRemoteFilePath = remoteFilePath;
mShareType = shareType;
@@ -90,6 +90,15 @@ public class CreateRemoteShareOperation extends RemoteOperation {
mPublicUpload = publicUpload;
mPassword = password;
mPermissions = permissions;
mGetShareDetails = false; // defaults to false for backwards compatibility
}
public boolean isGettingShareDetails () {
return mGetShareDetails;
}
public void setGetShareDetails(boolean set) {
mGetShareDetails = set;
}
@Override
@@ -102,7 +111,6 @@ public class CreateRemoteShareOperation extends RemoteOperation {
try {
// Post Method
post = new PostMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH);
//Log_OC.d(TAG, "URL ------> " + client.getBaseUri() + ShareUtils.SHARING_API_PATH);
post.setRequestHeader( "Content-Type",
"application/x-www-form-urlencoded; charset=utf-8"); // necessary for special characters
@@ -110,11 +118,15 @@ public class CreateRemoteShareOperation extends RemoteOperation {
post.addParameter(PARAM_PATH, mRemoteFilePath);
post.addParameter(PARAM_SHARE_TYPE, Integer.toString(mShareType.getValue()));
post.addParameter(PARAM_SHARE_WITH, mShareWith);
post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(mPublicUpload));
if (mPublicUpload) {
post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(true));
}
if (mPassword != null && mPassword.length() > 0) {
post.addParameter(PARAM_PASSWORD, mPassword);
}
post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions));
if (OCShare.DEFAULT_PERMISSION != mPermissions) {
post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions));
}
post.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
@@ -123,31 +135,21 @@ public class CreateRemoteShareOperation extends RemoteOperation {
if(isSuccess(status)) {
String response = post.getResponseBodyAsString();
result = new RemoteOperationResult(ResultCode.OK);
// Parse xml response --> obtain the response in ShareFiles ArrayList
// convert String into InputStream
InputStream is = new ByteArrayInputStream(response.getBytes());
ShareXMLParser xmlParser = new ShareXMLParser();
mShares = xmlParser.parseXMLResponse(is);
if (xmlParser.isSuccess()) {
if (mShares != null) {
Log_OC.d(TAG, "Created " + mShares.size() + " share(s)");
result = new RemoteOperationResult(ResultCode.OK);
ArrayList<Object> sharesObjects = new ArrayList<Object>();
for (OCShare share: mShares) {
sharesObjects.add(share);
}
result.setData(sharesObjects);
}
} else if (xmlParser.isFileNotFound()){
result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND);
} else if (xmlParser.isFailure()) {
result = new RemoteOperationResult(ResultCode.SHARE_FORBIDDEN);
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOneOrMoreSharesRequired(true);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
} else {
result = new RemoteOperationResult(false, status, post.getResponseHeaders());
if (result.isSuccess() && mGetShareDetails) {
// retrieve more info - POST only returns the index of the new share
OCShare emptyShare = (OCShare) result.getData().get(0);
GetRemoteShareOperation getInfo = new GetRemoteShareOperation(
emptyShare.getRemoteId()
);
result = getInfo.execute(client);
}
} else {
@@ -0,0 +1,100 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpStatus;
/**
* Get the data about a Share resource, known its remote ID.
*/
public class GetRemoteShareOperation extends RemoteOperation {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
private long mRemoteId;
public GetRemoteShareOperation(long remoteId) {
mRemoteId = remoteId;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
// Get Method
GetMethod get = null;
// Get the response
try{
get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH + "/" + Long.toString(mRemoteId));
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOneOrMoreSharesRequired(true);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
} else {
result = new RemoteOperationResult(false, status, get.getResponseHeaders());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while getting remote shares ", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
}
}
@@ -0,0 +1,199 @@
/* ownCloud Android Library is available under MIT license
*
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpStatus;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* 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
*/
public class GetRemoteShareesOperation extends RemoteOperation{
private static final String TAG = GetRemoteShareesOperation.class.getSimpleName();
// OCS Routes
private static final String OCS_ROUTE = "ocs/v2.php/apps/files_sharing/api/v1/sharees"; // from OC 8.2
// Arguments - names
private static final String PARAM_FORMAT = "format";
private static final String PARAM_ITEM_TYPE = "itemType";
private static final String PARAM_SEARCH = "search";
private static final String PARAM_PAGE = "page"; // default = 1
private static final String PARAM_PER_PAGE = "perPage"; // default = 200
// Arguments - constant values
private static final String VALUE_FORMAT = "json";
private static final String VALUE_ITEM_TYPE = "search"; // to get the server search for users / groups
// JSON Node names
private static final String NODE_OCS = "ocs";
private static final String NODE_DATA = "data";
private static final String NODE_EXACT = "exact";
private static final String NODE_USERS = "users";
private static final String NODE_GROUPS = "groups";
public static final String NODE_VALUE = "value";
public static final String PROPERTY_LABEL = "label";
public static final String PROPERTY_SHARE_TYPE = "shareType";
public static final String PROPERTY_SHARE_WITH = "shareWith";
// Result types
public static final Byte USER_TYPE = 0;
public static final Byte GROUP_TYPE = 1;
private String mSearchString;
private int mPage;
private int mPerPage;
/**
* 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
*/
public GetRemoteShareesOperation(String searchString, int page, int perPage) {
mSearchString = searchString;
mPage = page;
mPerPage = perPage;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status;
GetMethod get = null;
try{
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(OCS_ROUTE);
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT);
uriBuilder.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE);
uriBuilder.appendQueryParameter(PARAM_SEARCH, mSearchString);
uriBuilder.appendQueryParameter(PARAM_PAGE, String.valueOf(mPage));
uriBuilder.appendQueryParameter(PARAM_PER_PAGE, String.valueOf(mPerPage));
// Get Method
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
Log_OC.d(TAG, "Successful response: " + response);
// Parse the response
JSONObject respJSON = new JSONObject(response);
JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
JSONObject respExact = respData.getJSONObject(NODE_EXACT);
JSONArray respExactUsers = respExact.getJSONArray(NODE_USERS);
JSONArray respExactGroups = respExact.getJSONArray(NODE_GROUPS);
JSONArray respPartialUsers = respData.getJSONArray(NODE_USERS);
JSONArray respPartialGroups = respData.getJSONArray(NODE_GROUPS);
JSONArray[] jsonResults = {
respExactUsers,
respExactGroups,
respPartialUsers,
respPartialGroups
};
ArrayList<Object> data = new ArrayList<Object>(); // For result data
for (int i=0; i<4; i++) {
for(int j=0; j< jsonResults[i].length(); j++){
JSONObject jsonResult = jsonResults[i].getJSONObject(j);
data.add(jsonResult);
Log_OC.d(TAG, "*** Added item: " + jsonResult.getString(PROPERTY_LABEL));
}
}
// Result
result = new RemoteOperationResult(true, status, get.getResponseHeaders());
result.setData(data);
Log_OC.d(TAG, "*** Get Users or groups completed " );
} else {
result = new RemoteOperationResult(false, status, get.getResponseHeaders());
String response = get.getResponseBodyAsString();
Log_OC.e(TAG, "Failed response while getting users/groups from the server ");
if (response != null) {
Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response);
} else {
Log_OC.e(TAG, "*** status code: " + status);
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while getting users/groups", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
}
}
@@ -1,4 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,10 +26,6 @@
package com.owncloud.android.lib.resources.shares;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpStatus;
@@ -35,18 +33,13 @@ import org.apache.http.HttpStatus;
import com.owncloud.android.lib.common.OwnCloudClient;
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.Log_OC;
/**
* 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
*
*/
public class GetRemoteSharesForFileOperation extends RemoteOperation {
private static final String TAG = GetRemoteSharesForFileOperation.class.getSimpleName();
@@ -55,8 +48,6 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
private static final String PARAM_RESHARES = "reshares";
private static final String PARAM_SUBFILES = "subfiles";
private ArrayList<OCShare> mShares; // List of shares for result, one share in this case
private String mRemoteFilePath;
private boolean mReshares;
private boolean mSubfiles;
@@ -64,13 +55,15 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
/**
* Constructor
*
* @param remoteFilePath Path to file or folder
* @param reshares If set to false (default), only shares from the current user are returned
* If set to true, all shares 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.
* @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.
*/
public GetRemoteSharesForFileOperation(String remoteFilePath, boolean reshares, boolean subfiles) {
public GetRemoteSharesForFileOperation(String remoteFilePath, boolean reshares,
boolean subfiles) {
mRemoteFilePath = remoteFilePath;
mReshares = reshares;
mSubfiles = subfiles;
@@ -88,11 +81,11 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH);
// Add Parameters to Get Method
get.setQueryString(new NameValuePair[] {
new NameValuePair(PARAM_PATH, mRemoteFilePath),
new NameValuePair(PARAM_RESHARES, String.valueOf(mReshares)),
new NameValuePair(PARAM_SUBFILES, String.valueOf(mSubfiles))
});
get.setQueryString(new NameValuePair[]{
new NameValuePair(PARAM_PATH, mRemoteFilePath),
new NameValuePair(PARAM_RESHARES, String.valueOf(mReshares)),
new NameValuePair(PARAM_SUBFILES, String.valueOf(mSubfiles))
});
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
@@ -101,25 +94,16 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
result = new RemoteOperationResult(ResultCode.OK);
// Parse xml response --> obtain the response in ShareFiles ArrayList
// convert String into InputStream
InputStream is = new ByteArrayInputStream(response.getBytes());
ShareXMLParser xmlParser = new ShareXMLParser();
mShares = xmlParser.parseXMLResponse(is);
if (mShares != null) {
Log_OC.d(TAG, "Got " + mShares.size() + " shares");
result = new RemoteOperationResult(ResultCode.OK);
ArrayList<Object> sharesObjects = new ArrayList<Object>();
for (OCShare share: mShares) {
// Build the link
if (share.getToken().length() > 0) {
share.setShareLink(client.getBaseUri() + ShareUtils.SHARING_LINK_TOKEN + share.getToken());
}
sharesObjects.add(share);
}
result.setData(sharesObjects);
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
if (result.isSuccess()) {
Log_OC.d(TAG, "Got " + result.getData().size() + " shares");
}
} else {
@@ -1,4 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,34 +26,24 @@
package com.owncloud.android.lib.resources.shares;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpStatus;
import com.owncloud.android.lib.common.OwnCloudClient;
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.Log_OC;
/**
* Get the data from the server to know shares
* Get the data from the server about ALL the known shares owned by the requester.
*
* @author masensio
*
*/
public class GetRemoteSharesOperation extends RemoteOperation {
private static final String TAG = GetRemoteSharesOperation.class.getSimpleName();
private ArrayList<OCShare> mShares; // List of shares for result
public GetRemoteSharesOperation() {
}
@@ -68,23 +60,17 @@ public class GetRemoteSharesOperation extends RemoteOperation {
get = new GetMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH);
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
// Parse xml response --> obtain the response in ShareFiles ArrayList
// convert String into InputStream
InputStream is = new ByteArrayInputStream(response.getBytes());
ShareXMLParser xmlParser = new ShareXMLParser();
mShares = xmlParser.parseXMLResponse(is);
if (mShares != null) {
Log_OC.d(TAG, "Got " + mShares.size() + " shares");
result = new RemoteOperationResult(ResultCode.OK);
ArrayList<Object> sharesObjects = new ArrayList<Object>();
for (OCShare share: mShares) {
sharesObjects.add(share);
}
result.setData(sharesObjects);
}
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
} else {
result = new RemoteOperationResult(false, status, get.getResponseHeaders());
}
@@ -45,7 +45,24 @@ public class OCShare implements Parcelable, Serializable {
private static final long serialVersionUID = 4124975224281327921L;
private static final String TAG = OCShare.class.getSimpleName();
public static final int DEFAULT_PERMISSION = -1;
public static final int READ_PERMISSION_FLAG = 1;
public static final int UPDATE_PERMISSION_FLAG = 2;
public static final int CREATE_PERMISSION_FLAG = 4;
public static final int DELETE_PERMISSION_FLAG = 8;
public static final int SHARE_PERMISSION_FLAG = 16;
public static final int MAXIMUM_PERMISSIONS_FOR_FILE =
READ_PERMISSION_FLAG +
UPDATE_PERMISSION_FLAG +
SHARE_PERMISSION_FLAG
;
public static final int MAXIMUM_PERMISSIONS_FOR_FOLDER =
MAXIMUM_PERMISSIONS_FOR_FILE +
CREATE_PERMISSION_FLAG +
DELETE_PERMISSION_FLAG
;
private long mId;
private long mFileSource;
private long mItemSource;
@@ -59,7 +76,7 @@ public class OCShare implements Parcelable, Serializable {
private String mSharedWithDisplayName;
private boolean mIsFolder;
private long mUserId;
private long mIdRemoteShared;
private long mRemoteId;
private String mShareLink;
public OCShare() {
@@ -84,17 +101,17 @@ public class OCShare implements Parcelable, Serializable {
mFileSource = 0;
mItemSource = 0;
mShareType = ShareType.NO_SHARED;
mShareWith = null;
mPath = null;
mShareWith = "";
mPath = "";
mPermissions = -1;
mSharedDate = 0;
mExpirationDate = 0;
mToken = null;
mSharedWithDisplayName = null;
mToken = "";
mSharedWithDisplayName = "";
mIsFolder = false;
mUserId = -1;
mIdRemoteShared = -1;
mShareLink = null;
mRemoteId = -1;
mShareLink = "";
}
/// Getters and Setters
@@ -136,7 +153,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setShareWith(String shareWith) {
this.mShareWith = shareWith;
this.mShareWith = (shareWith != null) ? shareWith : "";
}
public String getPath() {
@@ -144,7 +161,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setPath(String path) {
this.mPath = path;
this.mPath = (path != null) ? path : "";
}
public int getPermissions() {
@@ -176,7 +193,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setToken(String token) {
this.mToken = token;
this.mToken = (token != null) ? token : "";
}
public String getSharedWithDisplayName() {
@@ -184,7 +201,7 @@ public class OCShare implements Parcelable, Serializable {
}
public void setSharedWithDisplayName(String sharedWithDisplayName) {
this.mSharedWithDisplayName = sharedWithDisplayName;
this.mSharedWithDisplayName = (sharedWithDisplayName != null) ? sharedWithDisplayName : "";
}
public boolean isFolder() {
@@ -203,12 +220,12 @@ public class OCShare implements Parcelable, Serializable {
this.mUserId = userId;
}
public long getIdRemoteShared() {
return mIdRemoteShared;
public long getRemoteId() {
return mRemoteId;
}
public void setIdRemoteShared(long idRemoteShared) {
this.mIdRemoteShared = idRemoteShared;
public void setIdRemoteShared(long remoteId) {
this.mRemoteId = remoteId;
}
public String getShareLink() {
@@ -216,7 +233,11 @@ public class OCShare implements Parcelable, Serializable {
}
public void setShareLink(String shareLink) {
this.mShareLink = shareLink;
this.mShareLink = (shareLink != null) ? shareLink : "";
}
public boolean isPasswordProtected() {
return ShareType.PUBLIC_LINK.equals(mShareType) && mShareWith.length() > 0;
}
/**
@@ -262,7 +283,7 @@ public class OCShare implements Parcelable, Serializable {
mSharedWithDisplayName = source.readString();
mIsFolder = source.readInt() == 0;
mUserId = source.readLong();
mIdRemoteShared = source.readLong();
mRemoteId = source.readLong();
mShareLink = source.readString();
}
@@ -288,7 +309,7 @@ public class OCShare implements Parcelable, Serializable {
dest.writeString(mSharedWithDisplayName);
dest.writeInt(mIsFolder ? 1 : 0);
dest.writeLong(mUserId);
dest.writeLong(mIdRemoteShared);
dest.writeLong(mRemoteId);
dest.writeString(mShareLink);
}
@@ -1,4 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,23 +26,16 @@
package com.owncloud.android.lib.resources.shares;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
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.Log_OC;
/**
* Remove a share
*
* @author masensio
*
*/
public class RemoveRemoteShareOperation extends RemoteOperation {
@@ -72,28 +67,20 @@ public class RemoveRemoteShareOperation extends RemoteOperation {
delete = new DeleteMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH + id);
delete.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(delete);
if(isSuccess(status)) {
String response = delete.getResponseBodyAsString();
result = new RemoteOperationResult(ResultCode.OK);
// Parse xml response
// convert String into InputStream
InputStream is = new ByteArrayInputStream(response.getBytes());
ShareXMLParser xmlParser = new ShareXMLParser();
xmlParser.parseXMLResponse(is);
if (xmlParser.isSuccess()) {
result = new RemoteOperationResult(ResultCode.OK);
} else if (xmlParser.isFileNotFound()){
result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND);
} else {
result = new RemoteOperationResult(false, status, delete.getResponseHeaders());
}
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
result = parser.parse(response);
Log_OC.d(TAG, "Unshare " + id + ": " + result.getLogMessage());
} else {
result = new RemoteOperationResult(false, status, delete.getResponseHeaders());
}
@@ -0,0 +1,106 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
/**
* Provides method to define a set of share permissions and calculate the appropiate
* int value representing it.
*/
public class SharePermissionsBuilder {
/** Set of permissions */
private int mPermissions = OCShare.READ_PERMISSION_FLAG; // READ is minimum permission
/**
* Sets or clears permission to reshare a file or folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setSharePermission(boolean enabled) {
updatePermission(OCShare.SHARE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to update a folder or folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setUpdatePermission(boolean enabled) {
updatePermission(OCShare.UPDATE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to create files in share folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setCreatePermission(boolean enabled) {
updatePermission(OCShare.CREATE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Sets or clears permission to delete files in a shared folder.
*
* @param enabled 'True' to set, 'false' to clear.
* @return Instance to builder itself, to allow consecutive calls to setters
*/
public SharePermissionsBuilder setDeletePermission(boolean enabled) {
updatePermission(OCShare.DELETE_PERMISSION_FLAG, enabled);
return this;
}
/**
* Common code to update the value of the set of permissions.
*
* @param permissionsFlag Flag for the permission to update.
* @param enable 'True' to set, 'false' to clear.
*/
private void updatePermission(int permissionsFlag, boolean enable) {
if (enable) {
// add permission
mPermissions |= permissionsFlag;
} else {
// delete permission
mPermissions &= ~permissionsFlag;
}
}
/**
* 'Builds' the int value for the accumulated set of permissions.
*
* @return An int value representing the accumulated set of permissions.
*/
public int build() {
return mPermissions;
}
}
@@ -0,0 +1,145 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class ShareToRemoteOperationResultParser {
private static final String TAG = ShareToRemoteOperationResultParser.class.getSimpleName();
private ShareXMLParser mShareXmlParser = null;
private boolean mOneOrMoreSharesRequired = false;
private OwnCloudVersion mOwnCloudVersion = null;
private Uri mServerBaseUri = null;
public ShareToRemoteOperationResultParser(ShareXMLParser shareXmlParser) {
mShareXmlParser = shareXmlParser;
}
public void setOneOrMoreSharesRequired(boolean oneOrMoreSharesRequired) {
mOneOrMoreSharesRequired = oneOrMoreSharesRequired;
}
public void setOwnCloudVersion(OwnCloudVersion ownCloudVersion) {
mOwnCloudVersion = ownCloudVersion;
}
public void setServerBaseUri(Uri serverBaseURi) {
mServerBaseUri = serverBaseURi;
}
public RemoteOperationResult parse(String serverResponse) {
if (serverResponse == null || serverResponse.length() == 0) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
RemoteOperationResult result = null;
ArrayList<Object> resultData = new ArrayList<Object>();
try {
// Parse xml response and obtain the list of shares
InputStream is = new ByteArrayInputStream(serverResponse.getBytes());
if (mShareXmlParser == null) {
Log_OC.w(TAG, "No ShareXmlParser provided, creating new instance ");
mShareXmlParser = new ShareXMLParser();
}
List<OCShare> shares = mShareXmlParser.parseXMLResponse(is);
if (mShareXmlParser.isSuccess()) {
if ((shares != null && shares.size() > 0) || !mOneOrMoreSharesRequired) {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.OK);
if (shares != null) {
for (OCShare share : shares) {
resultData.add(share);
// build the share link if not in the response (only received when the share is created)
if (share.getShareType() == ShareType.PUBLIC_LINK &&
(share.getShareLink() == null ||
share.getShareLink().length() <= 0) &&
share.getToken().length() > 0
) {
if (mServerBaseUri != null) {
String sharingLinkPath = ShareUtils.getSharingLinkPath(mOwnCloudVersion);
share.setShareLink(mServerBaseUri + sharingLinkPath + share.getToken());
} else {
Log_OC.e(TAG, "Couldn't build link for public share");
}
}
}
}
result.setData(resultData);
} else {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
Log_OC.e(TAG, "Successful status with no share in the response");
}
} else if (mShareXmlParser.isWrongParameter()){
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
} else if (mShareXmlParser.isNotFound()){
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
} else if (mShareXmlParser.isForbidden()) {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
} else {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
} catch (XmlPullParserException e) {
Log_OC.e(TAG, "Error parsing response from server ", e);
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
} catch (IOException e) {
Log_OC.e(TAG, "Error reading response from server ", e);
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
return result;
}
}
@@ -24,6 +24,8 @@
package com.owncloud.android.lib.resources.shares;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
/**
* Contains Constants for Share Operation
*
@@ -36,7 +38,16 @@ public class ShareUtils {
// OCS Route
public static final String SHARING_API_PATH ="/ocs/v1.php/apps/files_sharing/api/v1/shares";
// String to build the link with the token of a share: server address + "/public.php?service=files&t=" + token
public static final String SHARING_LINK_TOKEN = "/public.php?service=files&t=";
// String to build the link with the token of a share:
public static final String SHARING_LINK_PATH_BEFORE_VERSION_8 = "/public.php?service=files&t=";
public static final String SHARING_LINK_PATH_AFTER_VERSION_8 = "/index.php/s/";
public static String getSharingLinkPath(OwnCloudVersion version){
if (version!= null && version.isAfter8Version()){
return SHARING_LINK_PATH_AFTER_VERSION_8;
} else {
return SHARING_LINK_PATH_BEFORE_VERSION_8;
}
}
}
@@ -57,7 +57,7 @@ public class ShareXMLParser {
private static final String NODE_META = "meta";
private static final String NODE_STATUS = "status";
private static final String NODE_STATUS_CODE = "statuscode";
//private static final String NODE_MESSAGE = "message";
private static final String NODE_MESSAGE = "message";
private static final String NODE_DATA = "data";
private static final String NODE_ELEMENT = "element";
@@ -75,18 +75,20 @@ public class ShareXMLParser {
private static final String NODE_TOKEN = "token";
private static final String NODE_STORAGE = "storage";
private static final String NODE_MAIL_SEND = "mail_send";
private static final String NODE_SHARE_WITH_DISPLAY_NAME = "share_with_display_name";
private static final String NODE_SHARE_WITH_DISPLAY_NAME = "share_with_displayname";
private static final String NODE_URL = "url";
private static final String TYPE_FOLDER = "folder";
private static final int SUCCESS = 100;
private static final int FAILURE = 403;
private static final int FILE_NOT_FOUND = 404;
private static final int ERROR_WRONG_PARAMETER = 400;
private static final int ERROR_FORBIDDEN = 403;
private static final int ERROR_NOT_FOUND = 404;
private String mStatus;
private int mStatusCode;
private String mMessage;
// Getters and Setters
public String getStatus() {
@@ -104,21 +106,36 @@ public class ShareXMLParser {
public void setStatusCode(int statusCode) {
this.mStatusCode = statusCode;
}
public String getMessage() {
return mMessage;
}
public void setMessage(String message) {
this.mMessage = message;
}
// Constructor
public ShareXMLParser() {
mStatusCode = 100;
mStatusCode = -1;
}
public boolean isSuccess() {
return mStatusCode == SUCCESS;
}
public boolean isFailure() {
return mStatusCode == FAILURE;
public boolean isForbidden() {
return mStatusCode == ERROR_FORBIDDEN;
}
public boolean isFileNotFound() {
return mStatusCode == FILE_NOT_FOUND;
public boolean isNotFound() {
return mStatusCode == ERROR_NOT_FOUND;
}
public boolean isWrongParameter() {
return mStatusCode == ERROR_WRONG_PARAMETER;
}
/**
* Parse is as response of Share API
* @param is
@@ -126,7 +143,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
public ArrayList<OCShare> parseXMLResponse(InputStream is) throws XmlPullParserException, IOException {
public ArrayList<OCShare> parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
try {
// XMLPullParser
@@ -151,7 +169,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private ArrayList<OCShare> readOCS (XmlPullParser parser) throws XmlPullParserException, IOException {
private ArrayList<OCShare> readOCS (XmlPullParser parser) throws XmlPullParserException,
IOException {
ArrayList<OCShare> shares = new ArrayList<OCShare>();
parser.require(XmlPullParser.START_TAG, ns , NODE_OCS);
while (parser.next() != XmlPullParser.END_TAG) {
@@ -195,6 +214,9 @@ public class ShareXMLParser {
} else if (name.equalsIgnoreCase(NODE_STATUS_CODE)) {
setStatusCode(Integer.parseInt(readNode(parser, NODE_STATUS_CODE)));
} else if (name.equalsIgnoreCase(NODE_MESSAGE)) {
setMessage(readNode(parser, NODE_MESSAGE));
} else {
skip(parser);
}
@@ -209,7 +231,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private ArrayList<OCShare> readData(XmlPullParser parser) throws XmlPullParserException, IOException {
private ArrayList<OCShare> readData(XmlPullParser parser) throws XmlPullParserException,
IOException {
ArrayList<OCShare> shares = new ArrayList<OCShare>();
OCShare share = null;
@@ -259,7 +282,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private void readElement(XmlPullParser parser, ArrayList<OCShare> shares) throws XmlPullParserException, IOException {
private void readElement(XmlPullParser parser, ArrayList<OCShare> shares)
throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, NODE_ELEMENT);
OCShare share = new OCShare();
@@ -273,7 +297,8 @@ public class ShareXMLParser {
String name = parser.getName();
if (name.equalsIgnoreCase(NODE_ELEMENT)) {
// patch to work around servers responding with extra <element> surrounding all the shares on the same file before
// patch to work around servers responding with extra <element> surrounding all
// the shares on the same file before
// https://github.com/owncloud/core/issues/6992 was fixed
readElement(parser, shares);
@@ -327,6 +352,11 @@ public class ShareXMLParser {
} else if (name.equalsIgnoreCase(NODE_SHARE_WITH_DISPLAY_NAME)) {
share.setSharedWithDisplayName(readNode(parser, NODE_SHARE_WITH_DISPLAY_NAME));
} else if (name.equalsIgnoreCase(NODE_URL)) {
share.setShareType(ShareType.PUBLIC_LINK);
String value = readNode(parser, NODE_URL);
share.setShareLink(value);
} else {
skip(parser);
}
@@ -338,13 +368,12 @@ public class ShareXMLParser {
}
private boolean isValidShare(OCShare share) {
return ((share.getIdRemoteShared() > -1) &&
(share.getShareType() == ShareType.PUBLIC_LINK) // at this moment we only care about public shares
);
return (share.getRemoteId() > -1);
}
private void fixPathForFolder(OCShare share) {
if (share.isFolder() && share.getPath() != null && share.getPath().length() > 0 && !share.getPath().endsWith(FileUtils.PATH_SEPARATOR)) {
if (share.isFolder() && share.getPath() != null && share.getPath().length() > 0 &&
!share.getPath().endsWith(FileUtils.PATH_SEPARATOR)) {
share.setPath(share.getPath() + FileUtils.PATH_SEPARATOR);
}
}
@@ -357,7 +386,8 @@ public class ShareXMLParser {
* @throws XmlPullParserException
* @throws IOException
*/
private String readNode (XmlPullParser parser, String node) throws XmlPullParserException, IOException{
private String readNode (XmlPullParser parser, String node) throws XmlPullParserException,
IOException{
parser.require(XmlPullParser.START_TAG, ns, node);
String value = readText(parser);
//Log_OC.d(TAG, "node= " + node + ", value= " + value);
@@ -0,0 +1,215 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import android.util.Pair;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.http.HttpStatus;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Updates parameters of an existing Share resource, known its remote ID.
*
* Allow updating several parameters, triggering a request to the server per parameter.
*/
public class UpdateRemoteShareOperation extends RemoteOperation {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
private static final String PARAM_PASSWORD = "password";
private static final String PARAM_EXPIRATION_DATE = "expireDate";
private static final String PARAM_PERMISSIONS = "permissions";
private static final String FORMAT_EXPIRATION_DATE = "yyyy-MM-dd";
private static final String ENTITY_CONTENT_TYPE = "application/x-www-form-urlencoded";
private static final String ENTITY_CHARSET = "UTF-8";
/** Identifier of the share to update */
private long mRemoteId;
/** Password to set for the public link */
private String mPassword;
/** Expiration date to set for the public link */
private long mExpirationDateInMillis;
/** Access permissions for the file bound to the share */
private int mPermissions;
/**
* Constructor. No update is initialized by default, need to be applied with setters below.
*
* @param remoteId Identifier of the share to update.
*/
public UpdateRemoteShareOperation(long remoteId) {
mRemoteId = remoteId;
mPassword = null; // no update
mExpirationDateInMillis = 0; // no update
}
/**
* Set password to update in Share resource.
*
* @param password Password to set to the target share.
* Empty string clears the current password.
* Null results in no update applied to the password.
*/
public void setPassword(String password) {
mPassword = password;
}
/**
* Set expiration date to update in Share resource.
*
* @param expirationDateInMillis Expiration date to set to the target share.
* A negative value clears the current expiration date.
* Zero value (start-of-epoch) results in no update done on
* the expiration date.
*/
public void setExpirationDate(long expirationDateInMillis) {
mExpirationDateInMillis = expirationDateInMillis;
}
/**
* Set permissions to update in Share resource.
*
* @param permissions Permissions date to set to the target share.
* Values <= 0 result in no update applied to the permissions.
*/
public void setPermissions(int permissions) {
mPermissions = permissions;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
/// prepare array of parameters to update
List<Pair<String, String>> parametersToUpdate = new ArrayList<Pair<String, String>>();
if (mPassword != null) {
parametersToUpdate.add(new Pair<String, String>(PARAM_PASSWORD, mPassword));
}
if (mExpirationDateInMillis < 0) {
// clear expiration date
parametersToUpdate.add(new Pair(PARAM_EXPIRATION_DATE, ""));
} else if (mExpirationDateInMillis > 0) {
// set expiration date
DateFormat dateFormat = new SimpleDateFormat(FORMAT_EXPIRATION_DATE);
Calendar expirationDate = Calendar.getInstance();
expirationDate.setTimeInMillis(mExpirationDateInMillis);
String formattedExpirationDate = dateFormat.format(expirationDate.getTime());
parametersToUpdate.add(new Pair(PARAM_EXPIRATION_DATE, formattedExpirationDate));
} // else, ignore - no update
if (mPermissions > 0) {
// set permissions
parametersToUpdate.add(new Pair(PARAM_PERMISSIONS, Integer.toString(mPermissions)));
}
/* TODO complete rest of parameters
if (mPublicUpload != null) {
parametersToUpdate.add(new Pair("publicUpload", mPublicUpload.toString());
}
*/
/// perform required PUT requests
PutMethod put = null;
String uriString = null;
try{
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH.substring(1));
uriBuilder.appendEncodedPath(Long.toString(mRemoteId));
uriString = uriBuilder.build().toString();
for (Pair<String, String> parameter : parametersToUpdate) {
if (put != null) {
put.releaseConnection();
}
put = new PutMethod(uriString);
put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
put.setRequestEntity(new StringRequestEntity(
parameter.first + "=" + parameter.second,
ENTITY_CONTENT_TYPE,
ENTITY_CHARSET
));
status = client.executeMethod(put);
if (status == HttpStatus.SC_OK) {
String response = put.getResponseBodyAsString();
// Parse xml response
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
} else {
result = new RemoteOperationResult(false, status, put.getResponseHeaders());
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while updating remote share ", e);
if (put != null) {
put.releaseConnection();
}
} finally {
if (put != null) {
put.releaseConnection();
}
}
return result;
}
}
@@ -0,0 +1,83 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2015 ownCloud Inc.
* @author masensio
*
* 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.status;
/**
* Enum for Boolean Type in OCCapability parameters, with values:
* -1 - Unknown
* 0 - False
* 1 - True
*/
public enum CapabilityBooleanType {
UNKNOWN (-1),
FALSE (0),
TRUE (1);
private int value;
CapabilityBooleanType(int value)
{
this.value = value;
}
public int getValue() {
return value;
}
public static CapabilityBooleanType fromValue(int value)
{
switch (value)
{
case -1:
return UNKNOWN;
case 0:
return FALSE;
case 1:
return TRUE;
}
return null;
}
public static CapabilityBooleanType fromBooleanValue(boolean boolValue){
if (boolValue){
return TRUE;
} else {
return FALSE;
}
}
public boolean isUnknown(){
return getValue() == -1;
}
public boolean isFalse(){
return getValue() == 0;
}
public boolean isTrue(){
return getValue() == 1;
}
};
@@ -0,0 +1,281 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.status;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpStatus;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* Get the Capabilities from the server
*
* Save in Result.getData in a OCCapability object
*/
public class GetRemoteCapabilitiesOperation extends RemoteOperation {
private static final String TAG = GetRemoteCapabilitiesOperation.class.getSimpleName();
// OCS Routes
private static final String OCS_ROUTE = "ocs/v1.php/cloud/capabilities";
// Arguments - names
private static final String PARAM_FORMAT = "format";
// Arguments - constant values
private static final String VALUE_FORMAT = "json";
// JSON Node names
private static final String NODE_OCS = "ocs";
private static final String NODE_META = "meta";
private static final String NODE_DATA = "data";
private static final String NODE_VERSION = "version";
private static final String NODE_CAPABILITIES = "capabilities";
private static final String NODE_CORE = "core";
private static final String NODE_FILES_SHARING = "files_sharing";
private static final String NODE_PUBLIC = "public";
private static final String NODE_PASSWORD = "password";
private static final String NODE_EXPIRE_DATE = "expire_date";
private static final String NODE_USER = "user";
private static final String NODE_FEDERATION = "federation";
private static final String NODE_FILES = "files";
private static final String PROPERTY_STATUS = "status";
private static final String PROPERTY_STATUSCODE = "statuscode";
private static final String PROPERTY_MESSAGE = "message";
private static final String PROPERTY_POLLINTERVAL = "pollinterval";
private static final String PROPERTY_MAJOR = "major";
private static final String PROPERTY_MINOR = "minor";
private static final String PROPERTY_MICRO = "micro";
private static final String PROPERTY_STRING = "string";
private static final String PROPERTY_EDITION = "edition";
private static final String PROPERTY_API_ENABLED = "api_enabled";
private static final String PROPERTY_ENABLED = "enabled";
private static final String PROPERTY_ENFORCED = "enforced";
private static final String PROPERTY_DAYS = "days";
private static final String PROPERTY_SEND_MAIL = "send_mail";
private static final String PROPERTY_UPLOAD = "upload";
private static final String PROPERTY_RESHARING = "resharing";
private static final String PROPERTY_OUTGOING = "outgoing";
private static final String PROPERTY_INCOMING = "incoming";
private static final String PROPERTY_BIGFILECHUNKING = "bigfilechunking";
private static final String PROPERTY_UNDELETE = "undelete";
private static final String PROPERTY_VERSIONING = "versioning";
/**
* Constructor
*
*/
public GetRemoteCapabilitiesOperation() {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status;
GetMethod get = null;
try {
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(OCS_ROUTE); // avoid starting "/" in this method
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT);
// Get Method
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
Log_OC.d(TAG, "Successful response: " + response);
// Parse the response
JSONObject respJSON = new JSONObject(response);
JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
JSONObject respMeta = respOCS.getJSONObject(NODE_META);
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
// Read meta
boolean statusProp = respMeta.getString(PROPERTY_STATUS).equalsIgnoreCase("ok");
int statuscode = respMeta.getInt(PROPERTY_STATUSCODE);
String message = respMeta.getString(PROPERTY_MESSAGE);
if (statusProp) {
ArrayList<Object> data = new ArrayList<Object>(); // For result data
OCCapability capability = new OCCapability();
// Add Version
if (respData.has(NODE_VERSION)) {
JSONObject respVersion = respData.getJSONObject(NODE_VERSION);
capability.setVersionMayor(respVersion.getInt(PROPERTY_MAJOR));
capability.setVersionMinor(respVersion.getInt(PROPERTY_MINOR));
capability.setVersionMicro(respVersion.getInt(PROPERTY_MICRO));
capability.setVersionString(respVersion.getString(PROPERTY_STRING));
capability.setVersionEdition(respVersion.getString(PROPERTY_EDITION));
Log_OC.d(TAG, "*** Added " + NODE_VERSION);
}
// Capabilities Object
if (respData.has(NODE_CAPABILITIES)) {
JSONObject respCapabilities = respData.getJSONObject(NODE_CAPABILITIES);
// Add Core: pollinterval
if (respCapabilities.has(NODE_CORE)) {
JSONObject respCore = respCapabilities.getJSONObject(NODE_CORE);
capability.setCorePollinterval(respCore.getInt(PROPERTY_POLLINTERVAL));
Log_OC.d(TAG, "*** Added " + NODE_CORE);
}
// Add files_sharing: public, user, resharing
if (respCapabilities.has(NODE_FILES_SHARING)) {
JSONObject respFilesSharing = respCapabilities.getJSONObject(NODE_FILES_SHARING);
if (respFilesSharing.has(PROPERTY_API_ENABLED)) {
capability.setFilesSharingApiEnabled(CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_API_ENABLED)));
}
if (respFilesSharing.has(NODE_PUBLIC)) {
JSONObject respPublic = respFilesSharing.getJSONObject(NODE_PUBLIC);
capability.setFilesSharingPublicEnabled(CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_ENABLED)));
if(respPublic.has(NODE_PASSWORD)) {
capability.setFilesSharingPublicPasswordEnforced(
CapabilityBooleanType.fromBooleanValue(
respPublic.getJSONObject(NODE_PASSWORD).getBoolean(PROPERTY_ENFORCED)));
}
if(respPublic.has(NODE_EXPIRE_DATE)){
JSONObject respExpireDate = respPublic.getJSONObject(NODE_EXPIRE_DATE);
capability.setFilesSharingPublicExpireDateEnabled(
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENABLED)));
if (respExpireDate.has(PROPERTY_DAYS)) {
capability.setFilesSharingPublicExpireDateDays(
respExpireDate.getInt(PROPERTY_DAYS));
}
if (respExpireDate.has(PROPERTY_ENFORCED)) {
capability.setFilesSharingPublicExpireDateEnforced(
CapabilityBooleanType.fromBooleanValue(
respExpireDate.getBoolean(PROPERTY_ENFORCED)));
}
}
if (respPublic.has(PROPERTY_UPLOAD)){
capability.setFilesSharingPublicUpload(CapabilityBooleanType.fromBooleanValue(
respPublic.getBoolean(PROPERTY_UPLOAD)));
}
}
if (respFilesSharing.has(NODE_USER)) {
JSONObject respUser = respFilesSharing.getJSONObject(NODE_USER);
capability.setFilesSharingUserSendMail(CapabilityBooleanType.fromBooleanValue(
respUser.getBoolean(PROPERTY_SEND_MAIL)));
}
capability.setFilesSharingResharing(CapabilityBooleanType.fromBooleanValue(
respFilesSharing.getBoolean(PROPERTY_RESHARING)));
if (respFilesSharing.has(NODE_FEDERATION)) {
JSONObject respFederation = respFilesSharing.getJSONObject(NODE_FEDERATION);
capability.setFilesSharingFederationOutgoing(
CapabilityBooleanType.fromBooleanValue(respFederation.getBoolean(PROPERTY_OUTGOING)));
capability.setFilesSharingFederationIncoming(CapabilityBooleanType.fromBooleanValue(
respFederation.getBoolean(PROPERTY_INCOMING)));
}
Log_OC.d(TAG, "*** Added " + NODE_FILES_SHARING);
}
if (respCapabilities.has(NODE_FILES)) {
JSONObject respFiles = respCapabilities.getJSONObject(NODE_FILES);
// Add files
capability.setFilesBigFileChuncking(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_BIGFILECHUNKING)));
if (respFiles.has(PROPERTY_UNDELETE)) {
capability.setFilesUndelete(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_UNDELETE)));
}
capability.setFilesVersioning(CapabilityBooleanType.fromBooleanValue(
respFiles.getBoolean(PROPERTY_VERSIONING)));
Log_OC.d(TAG, "*** Added " + NODE_FILES);
}
}
// Result
data.add(capability);
result = new RemoteOperationResult(true, status, get.getResponseHeaders());
result.setData(data);
Log_OC.d(TAG, "*** Get Capabilities completed ");
} else {
result = new RemoteOperationResult(statusProp, statuscode, null);
Log_OC.e(TAG, "Failed response while getting capabilities from the server ");
Log_OC.e(TAG, "*** status: " + statusProp + "; message: " + message);
}
} else {
result = new RemoteOperationResult(false, status, get.getResponseHeaders());
String response = get.getResponseBodyAsString();
Log_OC.e(TAG, "Failed response while getting capabilities from the server ");
if (response != null) {
Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response);
} else {
Log_OC.e(TAG, "*** status code: " + status);
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while getting capabilities", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
}
}
@@ -103,9 +103,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
);
get.releaseConnection();
get = new GetMethod(redirectedLocation);
status = client.executeMethod(
get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT
);
status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
mLatestResult = new RemoteOperationResult(
(status == HttpStatus.SC_OK),
status,
@@ -0,0 +1,291 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* Copyright (C) 2015 ownCloud Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.status;
/**
* Contains data of the Capabilities for an account, from the Capabilities API
*/
public class OCCapability {
private static final String TAG = OCCapability.class.getSimpleName();
private long mId;
private String mAccountName;
// Server version
private int mVersionMayor;
private int mVersionMinor;
private int mVersionMicro;
private String mVersionString;
private String mVersionEdition;
// Core PollInterval
private int mCorePollinterval;
// Files Sharing
private CapabilityBooleanType mFilesSharingApiEnabled;
private CapabilityBooleanType mFilesSharingPublicEnabled;
private CapabilityBooleanType mFilesSharingPublicPasswordEnforced;
private CapabilityBooleanType mFilesSharingPublicExpireDateEnabled;
private int mFilesSharingPublicExpireDateDays;
private CapabilityBooleanType mFilesSharingPublicExpireDateEnforced;
private CapabilityBooleanType mFilesSharingPublicSendMail;
private CapabilityBooleanType mFilesSharingPublicUpload;
private CapabilityBooleanType mFilesSharingUserSendMail;
private CapabilityBooleanType mFilesSharingResharing;
private CapabilityBooleanType mFilesSharingFederationOutgoing;
private CapabilityBooleanType mFilesSharingFederationIncoming;
// Files
private CapabilityBooleanType mFilesBigFileChuncking;
private CapabilityBooleanType mFilesUndelete;
private CapabilityBooleanType mFilesVersioning;
public OCCapability(){
mId = 0;
mAccountName = "";
mVersionMayor = 0;
mVersionMinor = 0;
mVersionMicro = 0;
mVersionString = "";
mVersionString = "";
mCorePollinterval = 0;
mFilesSharingApiEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicPasswordEnforced = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicExpireDateEnabled = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicExpireDateDays = 0;
mFilesSharingPublicExpireDateEnforced = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicSendMail = CapabilityBooleanType.UNKNOWN;
mFilesSharingPublicUpload = CapabilityBooleanType.UNKNOWN;
mFilesSharingUserSendMail = CapabilityBooleanType.UNKNOWN;
mFilesSharingResharing = CapabilityBooleanType.UNKNOWN;
mFilesSharingFederationOutgoing = CapabilityBooleanType.UNKNOWN;
mFilesSharingFederationIncoming = CapabilityBooleanType.UNKNOWN;
mFilesBigFileChuncking = CapabilityBooleanType.UNKNOWN;
mFilesUndelete = CapabilityBooleanType.UNKNOWN;
mFilesVersioning = CapabilityBooleanType.UNKNOWN;
}
// Getters and Setters
public String getAccountName() {
return mAccountName;
}
public void setAccountName(String accountName) {
this.mAccountName = accountName;
}
public long getId() {
return mId;
}
public void setId(long id) {
this.mId = id;
}
public int getVersionMayor() {
return mVersionMayor;
}
public void setVersionMayor(int versionMayor) {
this.mVersionMayor = versionMayor;
}
public int getVersionMinor() {
return mVersionMinor;
}
public void setVersionMinor(int versionMinor) {
this.mVersionMinor = versionMinor;
}
public int getVersionMicro() {
return mVersionMicro;
}
public void setVersionMicro(int versionMicro) {
this.mVersionMicro = versionMicro;
}
public String getVersionString() {
return mVersionString;
}
public void setVersionString(String versionString) {
this.mVersionString = versionString;
}
public String getVersionEdition() {
return mVersionEdition;
}
public void setVersionEdition(String versionEdition) {
this.mVersionEdition = versionEdition;
}
public int getCorePollinterval() {
return mCorePollinterval;
}
public void setCorePollinterval(int corePollinterval) {
this.mCorePollinterval = corePollinterval;
}
public CapabilityBooleanType getFilesSharingApiEnabled() {
return mFilesSharingApiEnabled;
}
public void setFilesSharingApiEnabled(CapabilityBooleanType filesSharingApiEnabled) {
this.mFilesSharingApiEnabled = filesSharingApiEnabled;
}
public CapabilityBooleanType getFilesSharingPublicEnabled() {
return mFilesSharingPublicEnabled;
}
public void setFilesSharingPublicEnabled(CapabilityBooleanType filesSharingPublicEnabled) {
this.mFilesSharingPublicEnabled = filesSharingPublicEnabled;
}
public CapabilityBooleanType getFilesSharingPublicPasswordEnforced() {
return mFilesSharingPublicPasswordEnforced;
}
public void setFilesSharingPublicPasswordEnforced(CapabilityBooleanType filesSharingPublicPasswordEnforced) {
this.mFilesSharingPublicPasswordEnforced = filesSharingPublicPasswordEnforced;
}
public CapabilityBooleanType getFilesSharingPublicExpireDateEnabled() {
return mFilesSharingPublicExpireDateEnabled;
}
public void setFilesSharingPublicExpireDateEnabled(CapabilityBooleanType filesSharingPublicExpireDateEnabled) {
this.mFilesSharingPublicExpireDateEnabled = filesSharingPublicExpireDateEnabled;
}
public int getFilesSharingPublicExpireDateDays() {
return mFilesSharingPublicExpireDateDays;
}
public void setFilesSharingPublicExpireDateDays(int filesSharingPublicExpireDateDays) {
this.mFilesSharingPublicExpireDateDays = filesSharingPublicExpireDateDays;
}
public CapabilityBooleanType getFilesSharingPublicExpireDateEnforced() {
return mFilesSharingPublicExpireDateEnforced;
}
public void setFilesSharingPublicExpireDateEnforced(CapabilityBooleanType filesSharingPublicExpireDateEnforced) {
this.mFilesSharingPublicExpireDateEnforced = filesSharingPublicExpireDateEnforced;
}
public CapabilityBooleanType getFilesSharingPublicSendMail() {
return mFilesSharingPublicSendMail;
}
public void setFilesSharingPublicSendMail(CapabilityBooleanType filesSharingPublicSendMail) {
this.mFilesSharingPublicSendMail = filesSharingPublicSendMail;
}
public CapabilityBooleanType getFilesSharingPublicUpload() {
return mFilesSharingPublicUpload;
}
public void setFilesSharingPublicUpload(CapabilityBooleanType filesSharingPublicUpload) {
this.mFilesSharingPublicUpload = filesSharingPublicUpload;
}
public CapabilityBooleanType getFilesSharingUserSendMail() {
return mFilesSharingUserSendMail;
}
public void setFilesSharingUserSendMail(CapabilityBooleanType filesSharingUserSendMail) {
this.mFilesSharingUserSendMail = filesSharingUserSendMail;
}
public CapabilityBooleanType getFilesSharingResharing() {
return mFilesSharingResharing;
}
public void setFilesSharingResharing(CapabilityBooleanType filesSharingResharing) {
this.mFilesSharingResharing = filesSharingResharing;
}
public CapabilityBooleanType getFilesSharingFederationOutgoing() {
return mFilesSharingFederationOutgoing;
}
public void setFilesSharingFederationOutgoing(CapabilityBooleanType filesSharingFederationOutgoing) {
this.mFilesSharingFederationOutgoing = filesSharingFederationOutgoing;
}
public CapabilityBooleanType getFilesSharingFederationIncoming() {
return mFilesSharingFederationIncoming;
}
public void setFilesSharingFederationIncoming(CapabilityBooleanType filesSharingFederationIncoming) {
this.mFilesSharingFederationIncoming = filesSharingFederationIncoming;
}
public CapabilityBooleanType getFilesBigFileChuncking() {
return mFilesBigFileChuncking;
}
public void setFilesBigFileChuncking(CapabilityBooleanType filesBigFileChuncking) {
this.mFilesBigFileChuncking = filesBigFileChuncking;
}
public CapabilityBooleanType getFilesUndelete() {
return mFilesUndelete;
}
public void setFilesUndelete(CapabilityBooleanType filesUndelete) {
this.mFilesUndelete = filesUndelete;
}
public CapabilityBooleanType getFilesVersioning() {
return mFilesVersioning;
}
public void setFilesVersioning(CapabilityBooleanType filesVersioning) {
this.mFilesVersioning = filesVersioning;
}
}
@@ -38,6 +38,16 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
0x04050000);
public static final int MINIMUM_VERSION_FOR_SHARING_API = 0x05001B00; // 5.0.27
public static final int MINIMUM_VERSION_WITH_FORBIDDEN_CHARS = 0x08010000; // 8.1
public static final int MINIMUM_SERVER_VERSION_FOR_REMOTE_THUMBNAILS = 0x07080000; // 7.8.0
public static final int MINIMUM_VERSION_FOR_SEARCHING_USERS = 0x08020000; //8.2
public static final int VERSION_8 = 0x08000000; // 8.0
public static final int MINIMUM_VERSION_CAPABILITIES_API = 0x08010000; // 8.1
private static final int MAX_DOTS = 3;
@@ -120,6 +130,26 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
public boolean isSharedSupported() {
return (mVersion >= MINIMUM_VERSION_FOR_SHARING_API);
}
public boolean isVersionWithForbiddenCharacters() {
return (mVersion >= MINIMUM_VERSION_WITH_FORBIDDEN_CHARS);
}
public boolean supportsRemoteThumbnails() {
return (mVersion >= MINIMUM_SERVER_VERSION_FOR_REMOTE_THUMBNAILS);
}
public boolean isAfter8Version(){
return (mVersion >= VERSION_8);
}
public boolean isSearchUsersSupported() {
return (mVersion >= MINIMUM_VERSION_FOR_SEARCHING_USERS);
}
public boolean isVersionWithCapabilitiesAPI(){
return (mVersion>= MINIMUM_VERSION_CAPABILITIES_API);
}
}
@@ -50,7 +50,7 @@ public class GetRemoteUserNameOperation extends RemoteOperation {
private static final String TAG = GetRemoteUserNameOperation.class.getSimpleName();
// OCS Route
private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json";
private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json";
// JSON Node names
private static final String NODE_OCS = "ocs";