+
+ @Override
+ public void handleMessage(Message msg) {
+ @SuppressWarnings("unchecked")
+ AbstractList<String> requestedUploads = (AbstractList<String>) msg.obj;
+ if (msg.obj != null) {
+ Iterator<String> it = requestedUploads.iterator();
+ while (it.hasNext()) {
+ mService.uploadFile(it.next());
+ }
+ }
+ mService.stopSelf(msg.arg1);
+ }
+ }
+
+ /**
+ * Core upload method: sends the file(s) to upload
+ *
+ * @param uploadKey Key to access the upload to perform, contained in
+ * mPendingUploads
+ */
+ public void uploadFile(String uploadKey) {
+
+ synchronized (mPendingUploads) {
+ mCurrentUpload = mPendingUploads.get(uploadKey);
+ }
+
+ if (mCurrentUpload != null) {
+
+ notifyUploadStart(mCurrentUpload);
+
+ // / prepare client object to send requests to the ownCloud server
+ if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
+ mLastAccount = mCurrentUpload.getAccount();
+ mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
+ mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+ }
+
+ // / create remote folder for instant uploads
+ if (mCurrentUpload.isRemoteFolderToBeCreated()) {
+ mUploadClient.createDirectory(FileStorageUtils.getInstantUploadFilePath(this, ""));
+ // ignoring result fail could just mean that it already exists,
+ // but local database is not synchronized the upload will be
+ // tried anyway
+ }
+
+ // / perform the upload
+ RemoteOperationResult uploadResult = null;
+ try {
+ uploadResult = mCurrentUpload.execute(mUploadClient);
+ if (uploadResult.isSuccess()) {
+ saveUploadedFile();
+ }
+
+ } finally {
+ synchronized (mPendingUploads) {
+ mPendingUploads.remove(uploadKey);
+ Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
+ }
+ }
+
+ // notify result
+ notifyUploadResult(uploadResult, mCurrentUpload);
+ sendFinalBroadcast(mCurrentUpload, uploadResult);
+
+ }
+
+ }
+
+ /**
+ * Saves a OC File after a successful upload.
+ *
+ * A PROPFIND is necessary to keep the props in the local database
+ * synchronized with the server, specially the modification time and Etag
+ * (where available)
+ *
+ * TODO refactor this ugly thing
+ */
+ private void saveUploadedFile() {
+ OCFile file = mCurrentUpload.getFile();
+ long syncDate = System.currentTimeMillis();
+ file.setLastSyncDateForData(syncDate);
+
+ // / new PROPFIND to keep data consistent with server in theory, should
+ // return the same we already have
+ PropFindMethod propfind = null;
+ RemoteOperationResult result = null;
+ try {
+ propfind = new PropFindMethod(mUploadClient.getBaseUri()
+ + WebdavUtils.encodePath(mCurrentUpload.getRemotePath()));
+ int status = mUploadClient.executeMethod(propfind);
+ boolean isMultiStatus = (status == HttpStatus.SC_MULTI_STATUS);
+ if (isMultiStatus) {
+ MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
+ WebdavEntry we = new WebdavEntry(resp.getResponses()[0], mUploadClient.getBaseUri().getPath());
+ updateOCFile(file, we);
+ file.setLastSyncDateForProperties(syncDate);
+
+ } else {
+ mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
+ }
+
+ result = new RemoteOperationResult(isMultiStatus, status);
+ Log_OC.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
+ + result.getLogMessage());
+
+ } catch (Exception e) {
+ result = new RemoteOperationResult(e);
+ Log_OC.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
+ + result.getLogMessage(), e);
+
+ } finally {
+ if (propfind != null)
+ propfind.releaseConnection();
+ }
+
+ // / maybe this would be better as part of UploadFileOperation... or
+ // maybe all this method
+ if (mCurrentUpload.wasRenamed()) {
+ OCFile oldFile = mCurrentUpload.getOldFile();
+ if (oldFile.fileExists()) {
+ oldFile.setStoragePath(null);
+ mStorageManager.saveFile(oldFile);
+
+ } // else: it was just an automatic renaming due to a name
+ // coincidence; nothing else is needed, the storagePath is right
+ // in the instance returned by mCurrentUpload.getFile()
+ }
+
+ mStorageManager.saveFile(file);
+ }
+
+ private void updateOCFile(OCFile file, WebdavEntry we) {
+ file.setCreationTimestamp(we.createTimestamp());
+ file.setFileLength(we.contentLength());
+ file.setMimetype(we.contentType());
+ file.setModificationTimestamp(we.modifiedTimestamp());
+ file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp());
+ // file.setEtag(mCurrentUpload.getEtag()); // TODO Etag, where available
+ }
+
+ private boolean checkAndFixInstantUploadDirectory(FileDataStorageManager storageManager) {
+ String instantUploadDirPath = FileStorageUtils.getInstantUploadFilePath(this, "");
+ OCFile instantUploadDir = storageManager.getFileByPath(instantUploadDirPath);
+ if (instantUploadDir == null) {
+ // first instant upload in the account. never account not
+ // synchronized after the remote InstantUpload folder was created
+ OCFile newDir = new OCFile(instantUploadDirPath);
+ newDir.setMimetype("DIR");
+ OCFile path = storageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+
+ if (path != null) {
+ newDir.setParentId(path.getFileId());
+ storageManager.saveFile(newDir);
+ return true;
+ } else { // this should not happen anymore
+ return false;
+ }
+
+ }
+ return false;
+ }
+
+ private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
+ FileDataStorageManager storageManager) {
+ OCFile newFile = new OCFile(remotePath);
+ newFile.setStoragePath(localPath);
+ newFile.setLastSyncDateForProperties(0);
+ newFile.setLastSyncDateForData(0);
+
+ // size
+ if (localPath != null && localPath.length() > 0) {
+ File localFile = new File(localPath);
+ newFile.setFileLength(localFile.length());
+ newFile.setLastSyncDateForData(localFile.lastModified());
+ } // don't worry about not assigning size, the problems with localPath
+ // are checked when the UploadFileOperation instance is created
+
+ // MIME type
+ if (mimeType == null || mimeType.length() <= 0) {
+ try {
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ remotePath.substring(remotePath.lastIndexOf('.') + 1));
+ } catch (IndexOutOfBoundsException e) {
+ Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath);
+ }