@Override public void run(AccountManagerFuture<Bundle> future) { FileActivity.this.mRedirectingToSetupAccount = false; boolean accountWasSet = false; if (future != null) { try { Bundle result; result = future.getResult(); String name = result.getString(AccountManager.KEY_ACCOUNT_NAME); String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE); if (AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name)) { setAccount(new Account(name, type), false); accountWasSet = true; } } catch (OperationCanceledException e) { Log_OC.d(TAG, "Account creation canceled"); } catch (Exception e) { Log_OC.e(TAG, "Account creation finished in exception: ", e); } } else { Log_OC.e(TAG, "Account creation callback with null bundle"); } if (!accountWasSet) { moveTaskToBack(true); } }
@Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; /// download will be performed to a temporal file, then moved to the final location File tmpFile = new File(getTmpPath()); /// perform the download try { tmpFile.getParentFile().mkdirs(); int status = downloadFile(client, tmpFile); result = new RemoteOperationResult( isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null)); Log_OC.i( TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); Log_OC.e( TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage(), e); } return result; }
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); } } }
/** * Handles requests to: - (re)start watching (ACTION_START_OBSERVE) - add an {@link OCFile} to be * watched (ATION_ADD_OBSERVED_FILE) - stop observing an {@link OCFile} (ACTION_DEL_OBSERVED_FILE) */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command " + intent); if (intent == null || ACTION_START_OBSERVE.equals(intent.getAction())) { // NULL occurs when system tries to restart the service after its // process was killed startObservation(); return Service.START_STICKY; } else if (ACTION_ADD_OBSERVED_FILE.equals(intent.getAction())) { OCFile file = (OCFile) intent.getParcelableExtra(ARG_FILE); Account account = (Account) intent.getParcelableExtra(ARG_ACCOUNT); addObservedFile(file, account); } else if (ACTION_DEL_OBSERVED_FILE.equals(intent.getAction())) { removeObservedFile( (OCFile) intent.getParcelableExtra(ARG_FILE), (Account) intent.getParcelableExtra(ARG_ACCOUNT)); } else { Log_OC.e(TAG, "Unknown action recieved; ignoring it: " + intent.getAction()); } return Service.START_STICKY; }
/** * Entry point to add a new operation to the queue of operations. * * <p>New operations are added calling to startService(), resulting in a call to this method. This * ensures the service will keep on working although the caller activity goes away. */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); // WIP: for the moment, only SYNC_FOLDER is expected here; // the rest of the operations are requested through the Binder if (ACTION_SYNC_FOLDER.equals(intent.getAction())) { if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_REMOTE_PATH)) { Log_OC.e(TAG, "Not enough information provided in intent"); return START_NOT_STICKY; } Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); Pair<Account, String> itemSyncKey = new Pair<Account, String>(account, remotePath); Pair<Target, RemoteOperation> itemToQueue = newOperation(intent); if (itemToQueue != null) { mSyncFolderHandler.add( account, remotePath, (SynchronizeFolderOperation) itemToQueue.second); Message msg = mSyncFolderHandler.obtainMessage(); msg.arg1 = startId; msg.obj = itemSyncKey; mSyncFolderHandler.sendMessage(msg); } } else { Message msg = mOperationsHandler.obtainMessage(); msg.arg1 = startId; mOperationsHandler.sendMessage(msg); } return START_NOT_STICKY; }
/** * Unregisters the local copy of a remote file to be observed for local changes. * * @param file Object representing a remote file which local copy must be not observed longer. * @param account OwnCloud account containing file. */ private void removeObservedFile(OCFile file, Account account) { Log_OC.v(TAG, "Removing a file from being watched"); if (file == null) { Log_OC.e(TAG, "Trying to remove a NULL file"); return; } if (account == null) { Log_OC.e(TAG, "Trying to add a file with a NULL account to observer"); return; } String localPath = file.getStoragePath(); if (localPath == null || localPath.length() <= 0) { localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file); } removeObservedFile(localPath); }
/** * Registers the local copy of a remote file to be observed for local changes, an automatically * updated in the ownCloud server. * * <p>This method does NOT perform a {@link SynchronizeFileOperation} over the file. * * @param file Object representing a remote file which local copy must be observed. * @param account OwnCloud account containing file. */ private void addObservedFile(OCFile file, Account account) { Log_OC.v(TAG, "Adding a file to be watched"); if (file == null) { Log_OC.e(TAG, "Trying to add a NULL file to observer"); return; } if (account == null) { Log_OC.e(TAG, "Trying to add a file with a NULL account to observer"); return; } String localPath = file.getStoragePath(); if (localPath == null || localPath.length() <= 0) { // file downloading or to be downloaded for the first time localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file); } addObservedFile(localPath, account); }
@Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; int status = -1; GetMethod get = null; try { // Get Method 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.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.setOwnCloudVersion(client.getOwnCloudVersion()); parser.setServerBaseUri(client.getBaseUri()); result = parser.parse(response); if (result.isSuccess()) { Log_OC.d(TAG, "Got " + result.getData().size() + " shares"); } } else { result = new RemoteOperationResult(false, status, get.getResponseHeaders()); } } catch (Exception e) { result = new RemoteOperationResult(e); Log_OC.e(TAG, "Exception while getting shares", e); } finally { if (get != null) { get.releaseConnection(); } } return result; }
/** * 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); } } }
@Override public void writeRequest(final OutputStream out) throws IOException { // byte[] tmp = new byte[4096]; ByteBuffer tmp = ByteBuffer.allocate(4096); int readResult = 0; // 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.getAbsolutePath()); } } } } 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(); } }
protected int downloadFile(OwnCloudClient client, File targetFile) throws HttpException, IOException, OperationCancelledException { int status = -1; boolean savedFile = false; mGet = new GetMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath)); Iterator<OnDatatransferProgressListener> it = null; FileOutputStream fos = null; try { status = client.executeMethod(mGet); if (isSuccess(status)) { targetFile.createNewFile(); BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream()); fos = new FileOutputStream(targetFile); long transferred = 0; Header contentLength = mGet.getResponseHeader("Content-Length"); long totalToTransfer = (contentLength != null && contentLength.getValue().length() > 0) ? Long.parseLong(contentLength.getValue()) : 0; byte[] bytes = new byte[4096]; int readResult = 0; while ((readResult = bis.read(bytes)) != -1) { synchronized (mCancellationRequested) { if (mCancellationRequested.get()) { mGet.abort(); throw new OperationCancelledException(); } } fos.write(bytes, 0, readResult); transferred += readResult; synchronized (mDataTransferListeners) { it = mDataTransferListeners.iterator(); while (it.hasNext()) { it.next() .onTransferProgress( readResult, transferred, totalToTransfer, targetFile.getName()); } } } if (transferred == totalToTransfer) { // Check if the file is completed savedFile = true; 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 { client.exhaustResponse(mGet.getResponseBodyAsStream()); } } finally { if (fos != null) fos.close(); if (!savedFile && targetFile.exists()) { targetFile.delete(); } mGet.releaseConnection(); // let the connection available for other methods } return status; }
@Override protected RemoteOperationResult run(OwnCloudClient client) { AccountManager accountMngr = AccountManager.get(mContext); String statUrl = accountMngr.getUserData(mAccount, Constants.KEY_OC_BASE_URL); statUrl += AccountUtils.STATUS_PATH; RemoteOperationResult result = null; GetMethod get = null; try { get = new GetMethod(statUrl); int status = client.executeMethod(get); if (status != HttpStatus.SC_OK) { client.exhaustResponse(get.getResponseBodyAsStream()); result = new RemoteOperationResult(false, status, get.getResponseHeaders()); } else { String response = get.getResponseBodyAsString(); if (response != null) { JSONObject json = new JSONObject(response); if (json != null && json.getString("version") != null) { String version = json.getString("version"); mOwnCloudVersion = new OwnCloudVersion(version); if (mOwnCloudVersion.isVersionValid()) { accountMngr.setUserData( mAccount, Constants.KEY_OC_VERSION, mOwnCloudVersion.getVersion()); Log_OC.d(TAG, "Got new OC version " + mOwnCloudVersion.toString()); result = new RemoteOperationResult(ResultCode.OK); } else { Log_OC.w( TAG, "Invalid version number received from server: " + json.getString("version")); result = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION); } } } if (result == null) { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } } Log_OC.i( TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage()); } catch (JSONException e) { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); Log_OC.e( TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); } catch (Exception e) { result = new RemoteOperationResult(e); Log_OC.e( TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); } finally { if (get != null) get.releaseConnection(); } return result; }
/** * Creates a new operation, as described by operationIntent. * * <p>TODO - move to ServiceHandler (probably) * * @param operationIntent Intent describing a new operation to queue and execute. * @return Pair with the new operation object and the information about its target server. */ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) { RemoteOperation operation = null; Target target = null; try { if (!operationIntent.hasExtra(EXTRA_ACCOUNT) && !operationIntent.hasExtra(EXTRA_SERVER_URL)) { Log_OC.e(TAG, "Not enough information provided in intent"); } else { Account account = operationIntent.getParcelableExtra(EXTRA_ACCOUNT); String serverUrl = operationIntent.getStringExtra(EXTRA_SERVER_URL); String cookie = operationIntent.getStringExtra(EXTRA_COOKIE); target = new Target(account, (serverUrl == null) ? null : Uri.parse(serverUrl), cookie); String action = operationIntent.getAction(); if (action.equals(ACTION_CREATE_SHARE_VIA_LINK)) { // Create public share via link String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD); if (remotePath.length() > 0) { operation = new CreateShareViaLinkOperation(remotePath, password); } } else if (ACTION_UPDATE_SHARE.equals(action)) { String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); long shareId = operationIntent.getLongExtra(EXTRA_SHARE_ID, -1); if (remotePath != null && remotePath.length() > 0) { operation = new UpdateShareViaLinkOperation(remotePath); String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD); ((UpdateShareViaLinkOperation) operation).setPassword(password); long expirationDate = operationIntent.getLongExtra(EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, 0); ((UpdateShareViaLinkOperation) operation).setExpirationDate(expirationDate); if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_UPLOAD)) { ((UpdateShareViaLinkOperation) operation) .setPublicUpload( operationIntent.getBooleanExtra(EXTRA_SHARE_PUBLIC_UPLOAD, false)); } } else if (shareId > 0) { operation = new UpdateSharePermissionsOperation(shareId); int permissions = operationIntent.getIntExtra(EXTRA_SHARE_PERMISSIONS, 1); ((UpdateSharePermissionsOperation) operation).setPermissions(permissions); } } else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) { // Create private share with user or group String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH); ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE); int permissions = operationIntent.getIntExtra(EXTRA_SHARE_PERMISSIONS, -1); if (remotePath.length() > 0) { operation = new CreateShareWithShareeOperation(remotePath, shareeName, shareType, permissions); } } else if (action.equals(ACTION_UNSHARE)) { // Unshare file String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE); String shareWith = operationIntent.getStringExtra(EXTRA_SHARE_WITH); if (remotePath.length() > 0) { operation = new UnshareOperation(remotePath, shareType, shareWith, OperationsService.this); } } else if (action.equals(ACTION_GET_SERVER_INFO)) { // check OC server and get basic information from it operation = new GetServerInfoOperation(serverUrl, OperationsService.this); } else if (action.equals(ACTION_OAUTH2_GET_ACCESS_TOKEN)) { /// GET ACCESS TOKEN to the OAuth server String oauth2QueryParameters = operationIntent.getStringExtra(EXTRA_OAUTH2_QUERY_PARAMETERS); operation = new OAuth2GetAccessToken( getString(R.string.oauth2_client_id), getString(R.string.oauth2_redirect_uri), getString(R.string.oauth2_grant_type), oauth2QueryParameters); } else if (action.equals(ACTION_GET_USER_NAME)) { // Get User Name operation = new GetRemoteUserInfoOperation(); } else if (action.equals(ACTION_RENAME)) { // Rename file or folder String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String newName = operationIntent.getStringExtra(EXTRA_NEWNAME); operation = new RenameFileOperation(remotePath, newName); } else if (action.equals(ACTION_REMOVE)) { // Remove file or folder String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL, false); operation = new RemoveFileOperation(remotePath, onlyLocalCopy); } else if (action.equals(ACTION_CREATE_FOLDER)) { // Create Folder String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); boolean createFullPath = operationIntent.getBooleanExtra(EXTRA_CREATE_FULL_PATH, true); operation = new CreateFolderOperation(remotePath, createFullPath); } else if (action.equals(ACTION_SYNC_FILE)) { // Sync file String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); boolean syncFileContents = operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true); operation = new SynchronizeFileOperation( remotePath, account, syncFileContents, getApplicationContext()); } else if (action.equals(ACTION_SYNC_FOLDER)) { // Sync folder (all its descendant files are sync'ed) String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); operation = new SynchronizeFolderOperation( this, // TODO remove this dependency from construction time remotePath, account, System.currentTimeMillis() // TODO remove this dependency from construction time ); } else if (action.equals(ACTION_MOVE_FILE)) { // Move file/folder String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH); operation = new MoveFileOperation(remotePath, newParentPath, account); } else if (action.equals(ACTION_COPY_FILE)) { // Copy file/folder String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH); operation = new CopyFileOperation(remotePath, newParentPath, account); } else if (action.equals(ACTION_CHECK_CURRENT_CREDENTIALS)) { // Check validity of currently stored credentials for a given account operation = new CheckCurrentCredentialsOperation(account); } } } catch (IllegalArgumentException e) { Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); operation = null; } if (operation != null) { return new Pair<Target, RemoteOperation>(target, operation); } else { return null; } }
/** Performs the next operation in the queue */ private void nextOperation() { // Log_OC.e(TAG, "nextOperation init" ); Pair<Target, RemoteOperation> next = null; synchronized (mPendingOperations) { next = mPendingOperations.peek(); } if (next != null) { mCurrentOperation = next.second; RemoteOperationResult result = null; try { /// prepare client object to send the request to the ownCloud server if (mLastTarget == null || !mLastTarget.equals(next.first)) { mLastTarget = next.first; if (mLastTarget.mAccount != null) { OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount, mService); mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton() .getClientFor(ocAccount, mService); OwnCloudVersion version = com.owncloud.android.authentication.AccountUtils.getServerVersion( mLastTarget.mAccount); mOwnCloudClient.setOwnCloudVersion(version); mStorageManager = new FileDataStorageManager(mLastTarget.mAccount, mService.getContentResolver()); } else { OwnCloudCredentials credentials = null; if (mLastTarget.mCookie != null && mLastTarget.mCookie.length() > 0) { // just used for GetUserName // TODO refactor to run GetUserName as AsyncTask in the context of // AuthenticatorActivity credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials( null, // unknown mLastTarget.mCookie); // SAML SSO } OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mServerUrl, credentials); mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton() .getClientFor(ocAccount, mService); mStorageManager = null; } } /// perform the operation if (mCurrentOperation instanceof SyncOperation) { result = ((SyncOperation) mCurrentOperation).execute(mOwnCloudClient, mStorageManager); } else { result = mCurrentOperation.execute(mOwnCloudClient); } } catch (AccountsException e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e); } else { Log_OC.e( TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } catch (IOException e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e); } else { Log_OC.e( TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } catch (Exception e) { if (mLastTarget.mAccount == null) { Log_OC.e(TAG, "Unexpected error for a NULL account", e); } else { Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e); } result = new RemoteOperationResult(e); } finally { synchronized (mPendingOperations) { mPendingOperations.poll(); } } // sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result); mService.dispatchResultToOperationListeners(mCurrentOperation, result); } }