import com.owncloud.android.R;\r
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;\r
import com.owncloud.android.network.OwnCloudClientUtils;\r
+import com.owncloud.android.network.webdav.WebdavClient;\r
import com.owncloud.android.operations.ExistenceCheckOperation;\r
import com.owncloud.android.operations.OAuth2GetAccessToken;\r
import com.owncloud.android.operations.OnRemoteOperationListener;\r
import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
import com.owncloud.android.utils.OwnCloudVersion;\r
\r
-import eu.alefzero.webdav.WebdavClient;\r
\r
/**\r
* This Activity is used to add an ownCloud account to the App\r
import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.operations.DownloadFileOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.Log_OC;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
public class FileDownloader extends Service implements OnDatatransferProgressListener {
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.utils.OwnCloudVersion;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavEntry;
+import com.owncloud.android.network.webdav.WebdavUtils;
import android.accounts.Account;
import android.accounts.AccountManager;
import com.owncloud.android.ui.preview.PreviewImageActivity;
import com.owncloud.android.ui.preview.PreviewImageFragment;
-import eu.alefzero.webdav.WebdavClient;
public class FileUploader extends Service implements OnDatatransferProgressListener {
import com.owncloud.android.authentication.AccountAuthenticator;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.Log_OC;
import com.owncloud.android.MainApp;
-import eu.alefzero.webdav.WebdavClient;
import android.accounts.Account;
import android.accounts.AccountManager;
import java.util.Collection;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
+
public interface ProgressiveDataTransferer {
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network.webdav;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.RequestEntity;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
+
+
+/**
+ * A RequestEntity that represents a PIECE of a file.
+ *
+ * @author David A. Velasco
+ */
+public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
+
+ private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
+
+ //private final File mFile;
+ private final FileChannel mChannel;
+ private final String mContentType;
+ private final long mChunkSize;
+ private final File mFile;
+ private long mOffset;
+ private long mTransferred;
+ Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
+ private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
+
+ public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) {
+ super();
+ if (channel == null) {
+ throw new IllegalArgumentException("File may not be null");
+ }
+ if (chunkSize <= 0) {
+ throw new IllegalArgumentException("Chunk size must be greater than zero");
+ }
+ mChannel = channel;
+ mContentType = contentType;
+ mChunkSize = chunkSize;
+ mFile = file;
+ mOffset = 0;
+ mTransferred = 0;
+ }
+
+ public void setOffset(long offset) {
+ mOffset = offset;
+ }
+
+ public long getContentLength() {
+ try {
+ return Math.min(mChunkSize, mChannel.size() - mChannel.position());
+ } catch (IOException e) {
+ return mChunkSize;
+ }
+ }
+
+ public String getContentType() {
+ return mContentType;
+ }
+
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ @Override
+ public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
+ }
+
+ @Override
+ public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.addAll(listeners);
+ }
+ }
+
+ @Override
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
+ }
+
+
+ public void writeRequest(final OutputStream out) throws IOException {
+ int readCount = 0;
+ Iterator<OnDatatransferProgressListener> it = null;
+
+ try {
+ mChannel.position(mOffset);
+ long size = mFile.length();
+ if (size == 0) size = -1;
+ long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
+ while (mChannel.position() < maxCount) {
+ readCount = mChannel.read(mBuffer);
+ out.write(mBuffer.array(), 0, readCount);
+ mBuffer.clear();
+ if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
+ mTransferred += readCount;
+ }
+ synchronized (mDataTransferListeners) {
+ it = mDataTransferListeners.iterator();
+ while (it.hasNext()) {
+ it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
+ }
+ }
+ }
+
+ } catch (IOException io) {
+ Log_OC.e(TAG, io.getMessage());
+ throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
+
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012 Bartek Przybylski
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network.webdav;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.httpclient.methods.RequestEntity;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
+
+
+/**
+ * A RequestEntity that represents a File.
+ *
+ */
+public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
+
+ final File mFile;
+ final String mContentType;
+ Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
+
+ public FileRequestEntity(final File file, final String contentType) {
+ super();
+ this.mFile = file;
+ this.mContentType = contentType;
+ if (file == null) {
+ throw new IllegalArgumentException("File may not be null");
+ }
+ }
+
+ @Override
+ public long getContentLength() {
+ return mFile.length();
+ }
+
+ @Override
+ public String getContentType() {
+ return mContentType;
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ @Override
+ public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
+ }
+
+ @Override
+ public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.addAll(listeners);
+ }
+ }
+
+ @Override
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
+ }
+
+
+ @Override
+ public void writeRequest(final OutputStream out) throws IOException {
+ //byte[] tmp = new byte[4096];
+ ByteBuffer tmp = ByteBuffer.allocate(4096);
+ int readResult = 0;
+
+ // TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it
+ // globally in some fashionable manner
+ RandomAccessFile raf = new RandomAccessFile(mFile, "r");
+ FileChannel channel = raf.getChannel();
+ Iterator<OnDatatransferProgressListener> it = null;
+ long transferred = 0;
+ long size = mFile.length();
+ if (size == 0) size = -1;
+ try {
+ while ((readResult = channel.read(tmp)) >= 0) {
+ out.write(tmp.array(), 0, readResult);
+ tmp.clear();
+ transferred += readResult;
+ synchronized (mDataTransferListeners) {
+ it = mDataTransferListeners.iterator();
+ while (it.hasNext()) {
+ it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
+ }
+ }
+ }
+
+ } catch (IOException io) {
+ Log_OC.e("FileRequestException", io.getMessage());
+ throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
+
+ } finally {
+ channel.close();
+ raf.close();
+ }
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012 Bartek Przybylski
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network.webdav;
+
+public interface OnDatatransferProgressListener {
+ public void onTransferProgress(long progressRate);
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName);
+}
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2011 Bartek Przybylski
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network.webdav;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthPolicy;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.http.HttpStatus;
+import org.apache.http.params.CoreProtocolPNames;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.MainApp;
+
+import com.owncloud.android.network.BearerAuthScheme;
+import com.owncloud.android.network.BearerCredentials;
+
+
+import android.net.Uri;
+
+public class WebdavClient extends HttpClient {
+ private static final int MAX_REDIRECTIONS_COUNT = 3;
+
+ private Uri mUri;
+ private Credentials mCredentials;
+ private boolean mFollowRedirects;
+ private String mSsoSessionCookie;
+ private String mAuthTokenType;
+ final private static String TAG = "WebdavClient";
+ public static final String USER_AGENT = "Android-ownCloud";
+
+ static private byte[] sExhaustBuffer = new byte[1024];
+
+ /**
+ * Constructor
+ */
+ public WebdavClient(HttpConnectionManager connectionMgr) {
+ super(connectionMgr);
+ Log_OC.d(TAG, "Creating WebdavClient");
+ getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
+ getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+ mFollowRedirects = true;
+ mSsoSessionCookie = null;
+ mAuthTokenType = MainApp.getAuthTokenTypePass();
+ }
+
+ public void setBearerCredentials(String accessToken) {
+ AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
+
+ List<String> authPrefs = new ArrayList<String>(1);
+ authPrefs.add(BearerAuthScheme.AUTH_POLICY);
+ getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
+
+ mCredentials = new BearerCredentials(accessToken);
+ getState().setCredentials(AuthScope.ANY, mCredentials);
+ mSsoSessionCookie = null;
+ mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();
+ }
+
+ public void setBasicCredentials(String username, String password) {
+ List<String> authPrefs = new ArrayList<String>(1);
+ authPrefs.add(AuthPolicy.BASIC);
+ getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
+
+ getParams().setAuthenticationPreemptive(true);
+ mCredentials = new UsernamePasswordCredentials(username, password);
+ getState().setCredentials(AuthScope.ANY, mCredentials);
+ mSsoSessionCookie = null;
+ mAuthTokenType = MainApp.getAuthTokenTypePass();
+ }
+
+ public void setSsoSessionCookie(String accessToken) {
+ getParams().setAuthenticationPreemptive(false);
+ getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
+ mSsoSessionCookie = accessToken;
+ mCredentials = null;
+ mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie();
+ }
+
+
+ /**
+ * Check if a file exists in the OC server
+ *
+ * TODO replace with ExistenceOperation
+ *
+ * @return 'true' if the file exists; 'false' it doesn't exist
+ * @throws Exception When the existence could not be determined
+ */
+ public boolean existsFile(String path) throws IOException, HttpException {
+ HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
+ try {
+ int status = executeMethod(head);
+ Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
+ exhaustResponse(head.getResponseBodyAsStream());
+ return (status == HttpStatus.SC_OK);
+
+ } finally {
+ head.releaseConnection(); // let the connection available for other methods
+ }
+ }
+
+ /**
+ * Requests the received method with the received timeout (milliseconds).
+ *
+ * Executes the method through the inherited HttpClient.executedMethod(method).
+ *
+ * Sets the socket and connection timeouts only for the method received.
+ *
+ * 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 conntionTimout Timeout to set for connection establishment
+ */
+ public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
+ int oldSoTimeout = getParams().getSoTimeout();
+ int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
+ try {
+ if (readTimeout >= 0) {
+ method.getParams().setSoTimeout(readTimeout); // this should be enough...
+ getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS
+ }
+ if (connectionTimeout >= 0) {
+ getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
+ }
+ return executeMethod(method);
+ } finally {
+ getParams().setSoTimeout(oldSoTimeout);
+ getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
+ }
+ }
+
+
+ @Override
+ public int executeMethod(HttpMethod method) throws IOException, HttpException {
+ 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;
+ }
+ if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
+ method.setRequestHeader("Cookie", mSsoSessionCookie);
+ }
+ int status = super.executeMethod(method);
+ int redirectionsCount = 0;
+ while (customRedirectionNeeded &&
+ redirectionsCount < MAX_REDIRECTIONS_COUNT &&
+ ( status == HttpStatus.SC_MOVED_PERMANENTLY ||
+ status == HttpStatus.SC_MOVED_TEMPORARILY ||
+ status == HttpStatus.SC_TEMPORARY_REDIRECT)
+ ) {
+
+ Header location = method.getResponseHeader("Location");
+ if (location != null) {
+ Log_OC.d(TAG, "Location to redirect: " + location.getValue());
+ method.setURI(new URI(location.getValue(), true));
+ status = super.executeMethod(method);
+ redirectionsCount++;
+
+ } else {
+ Log_OC.d(TAG, "No location to redirect!");
+ status = HttpStatus.SC_NOT_FOUND;
+ }
+ }
+
+ return status;
+ }
+
+
+ /**
+ * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
+ *
+ * @param responseBodyAsStream InputStream with the HTTP response to exhaust.
+ */
+ public void exhaustResponse(InputStream responseBodyAsStream) {
+ if (responseBodyAsStream != null) {
+ try {
+ while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
+ responseBodyAsStream.close();
+
+ } catch (IOException io) {
+ Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
+ }
+ }
+ }
+
+ /**
+ * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
+ */
+ public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
+ getParams().setSoTimeout(defaultDataTimeout);
+ getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
+ }
+
+ /**
+ * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
+ * @param uri
+ */
+ public void setBaseUri(Uri uri) {
+ mUri = uri;
+ }
+
+ public Uri getBaseUri() {
+ return mUri;
+ }
+
+ public final Credentials getCredentials() {\r
+ return mCredentials;\r
+ }
+
+ public final String getSsoSessionCookie() {
+ return mSsoSessionCookie;
+ }
+
+ public void setFollowRedirects(boolean followRedirects) {
+ mFollowRedirects = followRedirects;
+ }
+
+ public String getAuthTokenType() {
+ return mAuthTokenType;
+ }
+
+}
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012 ownCloud
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.network.webdav;
+
+import java.util.Date;
+
+import org.apache.jackrabbit.webdav.MultiStatusResponse;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+
+import com.owncloud.android.Log_OC;
+
+
+import android.net.Uri;
+
+public class WebdavEntry {
+ private String mName, mPath, mUri, mContentType, mEtag;
+ private long mContentLength, mCreateTimestamp, mModifiedTimestamp;
+
+ public WebdavEntry(MultiStatusResponse ms, String splitElement) {
+ resetData();
+ if (ms.getStatus().length != 0) {
+ mUri = ms.getHref();
+
+ mPath = mUri.split(splitElement, 2)[1];
+
+ int status = ms.getStatus()[0].getStatusCode();
+ DavPropertySet propSet = ms.getProperties(status);
+ @SuppressWarnings("rawtypes")
+ DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME);
+ if (prop != null) {
+ mName = (String) prop.getName().toString();
+ mName = mName.substring(1, mName.length()-1);
+ }
+ else {
+ String[] tmp = mPath.split("/");
+ if (tmp.length > 0)
+ mName = tmp[tmp.length - 1];
+ }
+
+ // use unknown mimetype as default behavior
+ mContentType = "application/octet-stream";
+ prop = propSet.get(DavPropertyName.GETCONTENTTYPE);
+ if (prop != null) {
+ mContentType = (String) prop.getValue();
+ // dvelasco: some builds of ownCloud server 4.0.x added a trailing ';' to the MIME type ; if looks fixed, but let's be cautious
+ if (mContentType.indexOf(";") >= 0) {
+ mContentType = mContentType.substring(0, mContentType.indexOf(";"));
+ }
+ }
+
+ // check if it's a folder in the standard way: see RFC2518 12.2 . RFC4918 14.3
+ prop = propSet.get(DavPropertyName.RESOURCETYPE);
+ if (prop!= null) {
+ Object value = prop.getValue();
+ if (value != null) {
+ mContentType = "DIR"; // a specific attribute would be better, but this is enough; unless while we have no reason to distinguish MIME types for folders
+ }
+ }
+
+ prop = propSet.get(DavPropertyName.GETCONTENTLENGTH);
+ if (prop != null)
+ mContentLength = Long.parseLong((String) prop.getValue());
+
+ prop = propSet.get(DavPropertyName.GETLASTMODIFIED);
+ if (prop != null) {
+ Date d = WebdavUtils
+ .parseResponseDate((String) prop.getValue());
+ mModifiedTimestamp = (d != null) ? d.getTime() : 0;
+ }
+
+ prop = propSet.get(DavPropertyName.CREATIONDATE);
+ if (prop != null) {
+ Date d = WebdavUtils
+ .parseResponseDate((String) prop.getValue());
+ mCreateTimestamp = (d != null) ? d.getTime() : 0;
+ }
+
+ prop = propSet.get(DavPropertyName.GETETAG);
+ if (prop != null) {
+ mEtag = (String) prop.getValue();
+ mEtag = mEtag.substring(1, mEtag.length()-1);
+ }
+
+ } else {
+ Log_OC.e("WebdavEntry",
+ "General fuckup, no status for webdav response");
+ }
+ }
+
+ public String path() {
+ return mPath;
+ }
+
+ public String decodedPath() {
+ return Uri.decode(mPath);
+ }
+
+ public String name() {
+ return mName;
+ }
+
+ public boolean isDirectory() {
+ return mContentType.equals("DIR");
+ }
+
+ public String contentType() {
+ return mContentType;
+ }
+
+ public String uri() {
+ return mUri;
+ }
+
+ public long contentLength() {
+ return mContentLength;
+ }
+
+ public long createTimestamp() {
+ return mCreateTimestamp;
+ }
+
+ public long modifiedTimestamp() {
+ return mModifiedTimestamp;
+ }
+
+ public String etag() {
+ return mEtag;
+ }
+
+ private void resetData() {
+ mName = mUri = mContentType = null;
+ mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
+ }
+}
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012 Bartek Przybylski
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network.webdav;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import android.net.Uri;
+
+public class WebdavUtils {
+ public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
+ "dd.MM.yyyy hh:mm");
+ private static final SimpleDateFormat DATETIME_FORMATS[] = {
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
+ new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
+ new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
+
+ public static String prepareXmlForPropFind() {
+ String ret = "<?xml version=\"1.0\" ?><D:propfind xmlns:D=\"DAV:\"><D:allprop/></D:propfind>";
+ return ret;
+ }
+
+ public static String prepareXmlForPatch() {
+ return "<?xml version=\"1.0\" ?><D:propertyupdate xmlns:D=\"DAV:\"></D:propertyupdate>";
+ }
+
+ public static Date parseResponseDate(String date) {
+ Date returnDate = null;
+ for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
+ try {
+ returnDate = DATETIME_FORMATS[i].parse(date);
+ return returnDate;
+ } catch (ParseException e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Encodes a path according to URI RFC 2396.
+ *
+ * If the received path doesn't start with "/", the method adds it.
+ *
+ * @param remoteFilePath Path
+ * @return Encoded path according to RFC 2396, always starting with "/"
+ */
+ public static String encodePath(String remoteFilePath) {
+ String encodedPath = Uri.encode(remoteFilePath, "/");
+ if (!encodedPath.startsWith("/"))
+ encodedPath = "/" + encodedPath;
+ return encodedPath;
+ }
+
+}
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.network.ProgressiveDataTransferer;
+import com.owncloud.android.network.webdav.ChunkFromFileChannelRequestEntity;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
import android.accounts.Account;
-import eu.alefzero.webdav.ChunkFromFileChannelRequestEntity;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
public class ChunkedUploadFileOperation extends UploadFileOperation {
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.operations.remote.CreateRemoteFolderOperation;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.WebdavClient;
/**
* Access to remote operation performing the creation of a new folder in the ownCloud server.
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
import android.accounts.Account;
import android.webkit.MimeTypeMap;
import org.apache.commons.httpclient.methods.HeadMethod;
import com.owncloud.android.Log_OC;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
import android.content.Context;
import android.net.ConnectivityManager;
import com.owncloud.android.Log_OC;
import com.owncloud.android.authentication.OAuth2Constants;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import eu.alefzero.webdav.WebdavClient;
public class OAuth2GetAccessToken extends RemoteOperation {
import com.owncloud.android.Log_OC;
import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.utils.OwnCloudVersion;
-import eu.alefzero.webdav.WebdavClient;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Uri;
import com.owncloud.android.MainApp;
import com.owncloud.android.network.BearerCredentials;
import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import android.accounts.Account;
import android.content.Context;
import android.os.Handler;
-import eu.alefzero.webdav.WebdavClient;
/**
* Operation which execution involves one or several interactions with an ownCloud server.
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavEntry;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
public class SynchronizeFileOperation extends RemoteOperation {
import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavEntry;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.syncadapter.FileSyncService;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
/**
import com.owncloud.android.authentication.AccountAuthenticator;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.Log_OC;
+import com.owncloud.android.network.webdav.WebdavClient;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.utils.OwnCloudVersion;
-import eu.alefzero.webdav.WebdavClient;
/**
* Remote operation that checks the version of an ownCloud server and stores it locally
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.network.ProgressiveDataTransferer;
+import com.owncloud.android.network.webdav.FileRequestEntity;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.FileRequestEntity;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Remote operation performing the upload of a file to an ownCloud server
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import com.owncloud.android.Log_OC;
+import com.owncloud.android.network.webdav.WebdavClient;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.utils.FileStorageUtils;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Remote operation performing the creation of a new folder in the ownCloud server.
import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;\r
import com.owncloud.android.datamodel.FileDataStorageManager;\r
import com.owncloud.android.network.OwnCloudClientUtils;\r
+import com.owncloud.android.network.webdav.WebdavClient;\r
\r
import android.accounts.Account;\r
import android.accounts.AccountManager;\r
import android.content.AbstractThreadedSyncAdapter;\r
import android.content.ContentProviderClient;\r
import android.content.Context;\r
-import eu.alefzero.webdav.WebdavClient;\r
\r
/**\r
* Base synchronization adapter for ownCloud designed to be subclassed for different\r
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavUtils;
-import eu.alefzero.webdav.WebdavUtils;
/**
* Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
import com.owncloud.android.R;
import com.owncloud.android.authentication.SsoWebViewClient;
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
+import com.owncloud.android.network.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavClient;
/**
* Dialog to show the WebView for SAML Authentication
import com.owncloud.android.files.services.FileObserverService;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
import com.owncloud.android.operations.OnRemoteOperationListener;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
import com.owncloud.android.ui.preview.PreviewImageFragment;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
/**
* This Fragment is used to display the details about a file.
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.network.webdav.OnDatatransferProgressListener;
import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
/**
* This Fragment is used to monitor the progress of a file downloading.
import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.OnRemoteOperationListener;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavUtils;
/**
import com.owncloud.android.media.MediaControlView;
import com.owncloud.android.media.MediaService;
import com.owncloud.android.media.MediaServiceBinder;
+import com.owncloud.android.network.webdav.WebdavUtils;
import com.owncloud.android.operations.OnRemoteOperationListener;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavUtils;
/**
* This fragment shows a preview of a downloaded media file (audio or video).
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.apache.commons.httpclient.methods.RequestEntity;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
-
-/**
- * A RequestEntity that represents a PIECE of a file.
- *
- * @author David A. Velasco
- */
-public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
-
- private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
-
- //private final File mFile;
- private final FileChannel mChannel;
- private final String mContentType;
- private final long mChunkSize;
- private final File mFile;
- private long mOffset;
- private long mTransferred;
- Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
- private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
-
- public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) {
- super();
- if (channel == null) {
- throw new IllegalArgumentException("File may not be null");
- }
- if (chunkSize <= 0) {
- throw new IllegalArgumentException("Chunk size must be greater than zero");
- }
- mChannel = channel;
- mContentType = contentType;
- mChunkSize = chunkSize;
- mFile = file;
- mOffset = 0;
- mTransferred = 0;
- }
-
- public void setOffset(long offset) {
- mOffset = offset;
- }
-
- public long getContentLength() {
- try {
- return Math.min(mChunkSize, mChannel.size() - mChannel.position());
- } catch (IOException e) {
- return mChunkSize;
- }
- }
-
- public String getContentType() {
- return mContentType;
- }
-
- public boolean isRepeatable() {
- return true;
- }
-
- @Override
- public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.add(listener);
- }
- }
-
- @Override
- public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.addAll(listeners);
- }
- }
-
- @Override
- public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.remove(listener);
- }
- }
-
-
- public void writeRequest(final OutputStream out) throws IOException {
- int readCount = 0;
- Iterator<OnDatatransferProgressListener> it = null;
-
- try {
- mChannel.position(mOffset);
- long size = mFile.length();
- if (size == 0) size = -1;
- long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
- while (mChannel.position() < maxCount) {
- readCount = mChannel.read(mBuffer);
- out.write(mBuffer.array(), 0, readCount);
- mBuffer.clear();
- if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
- mTransferred += readCount;
- }
- synchronized (mDataTransferListeners) {
- it = mDataTransferListeners.iterator();
- while (it.hasNext()) {
- it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
- }
- }
- }
-
- } catch (IOException io) {
- Log_OC.e(TAG, io.getMessage());
- throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
-
- }
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.apache.commons.httpclient.methods.RequestEntity;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
-
-/**
- * A RequestEntity that represents a File.
- *
- */
-public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
-
- final File mFile;
- final String mContentType;
- Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
-
- public FileRequestEntity(final File file, final String contentType) {
- super();
- this.mFile = file;
- this.mContentType = contentType;
- if (file == null) {
- throw new IllegalArgumentException("File may not be null");
- }
- }
-
- @Override
- public long getContentLength() {
- return mFile.length();
- }
-
- @Override
- public String getContentType() {
- return mContentType;
- }
-
- @Override
- public boolean isRepeatable() {
- return true;
- }
-
- @Override
- public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.add(listener);
- }
- }
-
- @Override
- public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.addAll(listeners);
- }
- }
-
- @Override
- public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.remove(listener);
- }
- }
-
-
- @Override
- public void writeRequest(final OutputStream out) throws IOException {
- //byte[] tmp = new byte[4096];
- ByteBuffer tmp = ByteBuffer.allocate(4096);
- int readResult = 0;
-
- // TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it
- // globally in some fashionable manner
- RandomAccessFile raf = new RandomAccessFile(mFile, "r");
- FileChannel channel = raf.getChannel();
- Iterator<OnDatatransferProgressListener> it = null;
- long transferred = 0;
- long size = mFile.length();
- if (size == 0) size = -1;
- try {
- while ((readResult = channel.read(tmp)) >= 0) {
- out.write(tmp.array(), 0, readResult);
- tmp.clear();
- transferred += readResult;
- synchronized (mDataTransferListeners) {
- it = mDataTransferListeners.iterator();
- while (it.hasNext()) {
- it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
- }
- }
- }
-
- } catch (IOException io) {
- Log_OC.e("FileRequestException", io.getMessage());
- throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
-
- } finally {
- channel.close();
- raf.close();
- }
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-public interface OnDatatransferProgressListener {
- public void onTransferProgress(long progressRate);
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName);
-}
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpConnectionManager;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.HttpMethodBase;
-import org.apache.commons.httpclient.HttpVersion;
-import org.apache.commons.httpclient.URI;
-import org.apache.commons.httpclient.UsernamePasswordCredentials;
-import org.apache.commons.httpclient.auth.AuthPolicy;
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.cookie.CookiePolicy;
-import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.params.HttpMethodParams;
-import org.apache.http.HttpStatus;
-import org.apache.http.params.CoreProtocolPNames;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-
-import com.owncloud.android.network.BearerAuthScheme;
-import com.owncloud.android.network.BearerCredentials;
-
-import android.net.Uri;
-
-public class WebdavClient extends HttpClient {
- private static final int MAX_REDIRECTIONS_COUNT = 3;
-
- private Uri mUri;
- private Credentials mCredentials;
- private boolean mFollowRedirects;
- private String mSsoSessionCookie;
- private String mAuthTokenType;
- final private static String TAG = "WebdavClient";
- public static final String USER_AGENT = "Android-ownCloud";
-
- static private byte[] sExhaustBuffer = new byte[1024];
-
- /**
- * Constructor
- */
- public WebdavClient(HttpConnectionManager connectionMgr) {
- super(connectionMgr);
- Log_OC.d(TAG, "Creating WebdavClient");
- getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
- getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
- mFollowRedirects = true;
- mSsoSessionCookie = null;
- mAuthTokenType = MainApp.getAuthTokenTypePass();
- }
-
- public void setBearerCredentials(String accessToken) {
- AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
-
- List<String> authPrefs = new ArrayList<String>(1);
- authPrefs.add(BearerAuthScheme.AUTH_POLICY);
- getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
-
- mCredentials = new BearerCredentials(accessToken);
- getState().setCredentials(AuthScope.ANY, mCredentials);
- mSsoSessionCookie = null;
- mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();
- }
-
- public void setBasicCredentials(String username, String password) {
- List<String> authPrefs = new ArrayList<String>(1);
- authPrefs.add(AuthPolicy.BASIC);
- getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
-
- getParams().setAuthenticationPreemptive(true);
- mCredentials = new UsernamePasswordCredentials(username, password);
- getState().setCredentials(AuthScope.ANY, mCredentials);
- mSsoSessionCookie = null;
- mAuthTokenType = MainApp.getAuthTokenTypePass();
- }
-
- public void setSsoSessionCookie(String accessToken) {
- getParams().setAuthenticationPreemptive(false);
- getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
- mSsoSessionCookie = accessToken;
- mCredentials = null;
- mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie();
- }
-
-
- /**
- * Check if a file exists in the OC server
- *
- * TODO replace with ExistenceOperation
- *
- * @return 'true' if the file exists; 'false' it doesn't exist
- * @throws Exception When the existence could not be determined
- */
- public boolean existsFile(String path) throws IOException, HttpException {
- HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
- try {
- int status = executeMethod(head);
- Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
- exhaustResponse(head.getResponseBodyAsStream());
- return (status == HttpStatus.SC_OK);
-
- } finally {
- head.releaseConnection(); // let the connection available for other methods
- }
- }
-
- /**
- * Requests the received method with the received timeout (milliseconds).
- *
- * Executes the method through the inherited HttpClient.executedMethod(method).
- *
- * Sets the socket and connection timeouts only for the method received.
- *
- * 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 conntionTimout Timeout to set for connection establishment
- */
- public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
- int oldSoTimeout = getParams().getSoTimeout();
- int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
- try {
- if (readTimeout >= 0) {
- method.getParams().setSoTimeout(readTimeout); // this should be enough...
- getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS
- }
- if (connectionTimeout >= 0) {
- getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
- }
- return executeMethod(method);
- } finally {
- getParams().setSoTimeout(oldSoTimeout);
- getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
- }
- }
-
-
- @Override
- public int executeMethod(HttpMethod method) throws IOException, HttpException {
- 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;
- }
- if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
- method.setRequestHeader("Cookie", mSsoSessionCookie);
- }
- int status = super.executeMethod(method);
- int redirectionsCount = 0;
- while (customRedirectionNeeded &&
- redirectionsCount < MAX_REDIRECTIONS_COUNT &&
- ( status == HttpStatus.SC_MOVED_PERMANENTLY ||
- status == HttpStatus.SC_MOVED_TEMPORARILY ||
- status == HttpStatus.SC_TEMPORARY_REDIRECT)
- ) {
-
- Header location = method.getResponseHeader("Location");
- if (location != null) {
- Log_OC.d(TAG, "Location to redirect: " + location.getValue());
- method.setURI(new URI(location.getValue(), true));
- status = super.executeMethod(method);
- redirectionsCount++;
-
- } else {
- Log_OC.d(TAG, "No location to redirect!");
- status = HttpStatus.SC_NOT_FOUND;
- }
- }
-
- return status;
- }
-
-
- /**
- * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
- *
- * @param responseBodyAsStream InputStream with the HTTP response to exhaust.
- */
- public void exhaustResponse(InputStream responseBodyAsStream) {
- if (responseBodyAsStream != null) {
- try {
- while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
- responseBodyAsStream.close();
-
- } catch (IOException io) {
- Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
- }
- }
- }
-
- /**
- * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
- */
- public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
- getParams().setSoTimeout(defaultDataTimeout);
- getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
- }
-
- /**
- * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
- * @param uri
- */
- public void setBaseUri(Uri uri) {
- mUri = uri;
- }
-
- public Uri getBaseUri() {
- return mUri;
- }
-
- public final Credentials getCredentials() {\r
- return mCredentials;\r
- }
-
- public final String getSsoSessionCookie() {
- return mSsoSessionCookie;
- }
-
- public void setFollowRedirects(boolean followRedirects) {
- mFollowRedirects = followRedirects;
- }
-
- public String getAuthTokenType() {
- return mAuthTokenType;
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 ownCloud
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package eu.alefzero.webdav;
-
-import java.util.Date;
-
-import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
-
-import com.owncloud.android.Log_OC;
-
-import android.net.Uri;
-
-public class WebdavEntry {
- private String mName, mPath, mUri, mContentType, mEtag;
- private long mContentLength, mCreateTimestamp, mModifiedTimestamp;
-
- public WebdavEntry(MultiStatusResponse ms, String splitElement) {
- resetData();
- if (ms.getStatus().length != 0) {
- mUri = ms.getHref();
-
- mPath = mUri.split(splitElement, 2)[1];
-
- int status = ms.getStatus()[0].getStatusCode();
- DavPropertySet propSet = ms.getProperties(status);
- @SuppressWarnings("rawtypes")
- DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME);
- if (prop != null) {
- mName = (String) prop.getName().toString();
- mName = mName.substring(1, mName.length()-1);
- }
- else {
- String[] tmp = mPath.split("/");
- if (tmp.length > 0)
- mName = tmp[tmp.length - 1];
- }
-
- // use unknown mimetype as default behavior
- mContentType = "application/octet-stream";
- prop = propSet.get(DavPropertyName.GETCONTENTTYPE);
- if (prop != null) {
- mContentType = (String) prop.getValue();
- // dvelasco: some builds of ownCloud server 4.0.x added a trailing ';' to the MIME type ; if looks fixed, but let's be cautious
- if (mContentType.indexOf(";") >= 0) {
- mContentType = mContentType.substring(0, mContentType.indexOf(";"));
- }
- }
-
- // check if it's a folder in the standard way: see RFC2518 12.2 . RFC4918 14.3
- prop = propSet.get(DavPropertyName.RESOURCETYPE);
- if (prop!= null) {
- Object value = prop.getValue();
- if (value != null) {
- mContentType = "DIR"; // a specific attribute would be better, but this is enough; unless while we have no reason to distinguish MIME types for folders
- }
- }
-
- prop = propSet.get(DavPropertyName.GETCONTENTLENGTH);
- if (prop != null)
- mContentLength = Long.parseLong((String) prop.getValue());
-
- prop = propSet.get(DavPropertyName.GETLASTMODIFIED);
- if (prop != null) {
- Date d = WebdavUtils
- .parseResponseDate((String) prop.getValue());
- mModifiedTimestamp = (d != null) ? d.getTime() : 0;
- }
-
- prop = propSet.get(DavPropertyName.CREATIONDATE);
- if (prop != null) {
- Date d = WebdavUtils
- .parseResponseDate((String) prop.getValue());
- mCreateTimestamp = (d != null) ? d.getTime() : 0;
- }
-
- prop = propSet.get(DavPropertyName.GETETAG);
- if (prop != null) {
- mEtag = (String) prop.getValue();
- mEtag = mEtag.substring(1, mEtag.length()-1);
- }
-
- } else {
- Log_OC.e("WebdavEntry",
- "General fuckup, no status for webdav response");
- }
- }
-
- public String path() {
- return mPath;
- }
-
- public String decodedPath() {
- return Uri.decode(mPath);
- }
-
- public String name() {
- return mName;
- }
-
- public boolean isDirectory() {
- return mContentType.equals("DIR");
- }
-
- public String contentType() {
- return mContentType;
- }
-
- public String uri() {
- return mUri;
- }
-
- public long contentLength() {
- return mContentLength;
- }
-
- public long createTimestamp() {
- return mCreateTimestamp;
- }
-
- public long modifiedTimestamp() {
- return mModifiedTimestamp;
- }
-
- public String etag() {
- return mEtag;
- }
-
- private void resetData() {
- mName = mUri = mContentType = null;
- mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
- }
-}
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-import android.net.Uri;
-
-public class WebdavUtils {
- public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
- "dd.MM.yyyy hh:mm");
- private static final SimpleDateFormat DATETIME_FORMATS[] = {
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
- new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
- new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
- new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
- new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
-
- public static String prepareXmlForPropFind() {
- String ret = "<?xml version=\"1.0\" ?><D:propfind xmlns:D=\"DAV:\"><D:allprop/></D:propfind>";
- return ret;
- }
-
- public static String prepareXmlForPatch() {
- return "<?xml version=\"1.0\" ?><D:propertyupdate xmlns:D=\"DAV:\"></D:propertyupdate>";
- }
-
- public static Date parseResponseDate(String date) {
- Date returnDate = null;
- for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
- try {
- returnDate = DATETIME_FORMATS[i].parse(date);
- return returnDate;
- } catch (ParseException e) {
- }
- }
- return null;
- }
-
- /**
- * Encodes a path according to URI RFC 2396.
- *
- * If the received path doesn't start with "/", the method adds it.
- *
- * @param remoteFilePath Path
- * @return Encoded path according to RFC 2396, always starting with "/"
- */
- public static String encodePath(String remoteFilePath) {
- String encodedPath = Uri.encode(remoteFilePath, "/");
- if (!encodedPath.startsWith("/"))
- encodedPath = "/" + encodedPath;
- return encodedPath;
- }
-
-}