You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2013/12/05 01:58:15 UTC

[1/9] git commit: CB-5188:

Updated Branches:
  refs/heads/master ac7cb43da -> 76baae969


CB-5188:


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/60f96e07
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/60f96e07
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/60f96e07

Branch: refs/heads/master
Commit: 60f96e078b5d2cd8cf1c22556fb76d62f473fbca
Parents: ac7cb43
Author: Steven Gill <st...@gmail.com>
Authored: Mon Oct 28 12:27:15 2013 -0700
Committer: Steven Gill <st...@gmail.com>
Committed: Mon Oct 28 12:27:15 2013 -0700

----------------------------------------------------------------------
 plugin.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/60f96e07/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 114b072..d1de8dd 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,7 +2,7 @@
 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     xmlns:android="http://schemas.android.com/apk/res/android"
     id="org.apache.cordova.file-transfer"
-    version="0.3.4">
+    version="0.3.5-dev">
     <name>File Transfer</name>
     <description>Cordova File Transfer Plugin</description>
     <license>Apache 2.0</license>


[7/9] git commit: added ubuntu support

Posted by st...@apache.org.
added ubuntu support


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/fee10fb6
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/fee10fb6
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/fee10fb6

Branch: refs/heads/master
Commit: fee10fb6d8d4db50a5ae5352bfee08329233856b
Parents: 4c259e7 4219ef3
Author: Steven Gill <st...@gmail.com>
Authored: Mon Dec 2 16:12:45 2013 -0800
Committer: Steven Gill <st...@gmail.com>
Committed: Mon Dec 2 16:12:45 2013 -0800

----------------------------------------------------------------------
 plugin.xml                   |   6 +
 src/ubuntu/file-transfer.cpp | 247 ++++++++++++++++++++++++++++++++++++++
 src/ubuntu/file-transfer.h   |  97 +++++++++++++++
 3 files changed, 350 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/fee10fb6/plugin.xml
----------------------------------------------------------------------
diff --cc plugin.xml
index 7513bb0,c9a2019..34371bb
--- a/plugin.xml
+++ b/plugin.xml
@@@ -37,23 -35,12 +37,29 @@@
          <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
      </platform>
  
 +    <!-- amamzon-fireos -->
 +    <platform name="amazon-fireos">
 +        <config-file target="res/xml/config.xml" parent="/*">
 +            <feature name="FileTransfer" >
 +                <param name="android-package" value="org.apache.cordova.filetransfer.FileTransfer"/>
 +            </feature>
 +        </config-file>
 +
 +        <config-file target="AndroidManifest.xml" parent="/*">
 +            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 +        </config-file>
 +
 +        <source-file src="src/amazon/FileTransfer.java" target-dir="src/org/apache/cordova/filetransfer" />
 +        <source-file src="src/android/FileProgressResult.java" target-dir="src/org/apache/cordova/filetransfer" />
 +        <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
 +    </platform>
 +    
+     <!-- ubuntu -->
+     <platform name="ubuntu">
+         <header-file src="src/ubuntu/file-transfer.h" />
+         <source-file src="src/ubuntu/file-transfer.cpp" />
+     </platform>
+ 
      <platform name="blackberry10">
          <config-file target="www/config.xml" parent="/widget">
              <feature name="FileTransfer" value="FileTransfer"></feature>


[8/9] git commit: CB-5466: Partial revert; we're not ready yet for FS urls

Posted by st...@apache.org.
CB-5466: Partial revert; we're not ready yet for FS urls


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/4c11f54b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/4c11f54b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/4c11f54b

Branch: refs/heads/master
Commit: 4c11f54bd587008debf6e22e18199044711d0976
Parents: fee10fb
Author: Ian Clelland <ic...@chromium.org>
Authored: Wed Dec 4 08:50:38 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Wed Dec 4 16:10:00 2013 -0500

----------------------------------------------------------------------
 src/ios/CDVFileTransfer.h |  1 -
 src/ios/CDVFileTransfer.m | 94 +++++++++++++++++++-----------------------
 2 files changed, 43 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4c11f54b/src/ios/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVFileTransfer.h b/src/ios/CDVFileTransfer.h
index aa1cf9e..8e8211d 100644
--- a/src/ios/CDVFileTransfer.h
+++ b/src/ios/CDVFileTransfer.h
@@ -71,7 +71,6 @@ extern NSString* const kOptionsKeyCookie;
 @property (nonatomic, copy) NSString* objectId;
 @property (nonatomic, copy) NSString* source;
 @property (nonatomic, copy) NSString* target;
-@property (nonatomic, copy) NSURL* targetURL;
 @property (nonatomic, copy) NSString* mimeType;
 @property (assign) int responseCode; // atomic
 @property (nonatomic, assign) long long bytesTransfered;

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4c11f54b/src/ios/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFileTransfer.m b/src/ios/CDVFileTransfer.m
index 2eec342..c50754f 100644
--- a/src/ios/CDVFileTransfer.m
+++ b/src/ios/CDVFileTransfer.m
@@ -20,15 +20,12 @@
 #import <Cordova/CDV.h>
 #import "CDVFileTransfer.h"
 #import "CDVFile.h"
-#import "CDVLocalFilesystem.h"
 
 #import <AssetsLibrary/ALAsset.h>
 #import <AssetsLibrary/ALAssetRepresentation.h>
 #import <AssetsLibrary/ALAssetsLibrary.h>
 #import <CFNetwork/CFNetwork.h>
 
-extern CDVFile *filePlugin;
-
 @interface CDVFileTransfer ()
 // Sets the requests headers for the request.
 - (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req;
@@ -277,23 +274,31 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* server = [command.arguments objectAtIndex:1];
     NSError* __autoreleasing err = nil;
 
-    CDVFilesystemURL *sourceURL = [CDVFilesystemURL fileSystemURLWithString:source];
-    NSObject<CDVFileSystem> *fs;
-    if (sourceURL) {
-        // Try to get a CDVFileSystem which will handle this file.
-        // This requires talking to the current CDVFile plugin.
-        fs = [filePlugin filesystemForURL:sourceURL];
-    }
-    if (fs) {
-        [fs readFileAtURL:sourceURL start:0 end:-1 callback:^(NSData *fileData, NSString *mimeType, CDVFileError err) {
-            if (err) {
+    // return unsupported result for assets-library URLs
+    if ([source hasPrefix:kCDVAssetsLibraryPrefix]) {
+        // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+            if (asset) {
+                // We have the asset!  Get the data and send it off.
+                ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+                Byte* buffer = (Byte*)malloc([assetRepresentation size]);
+                NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
+                NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+                [self uploadData:fileData command:command];
+            } else {
                 // We couldn't find the asset.  Send the appropriate error.
                 CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:NOT_FOUND_ERR AndSource:source AndTarget:server]];
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-            }  else {
-                [self uploadData:fileData command:command];
             }
-        }];
+        };
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+            // Retrieving the asset failed for some reason.  Send the appropriate error.
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        };
+
+        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+        [assetsLibrary assetForURL:[NSURL URLWithString:source] resultBlock:resultBlock failureBlock:failureBlock];
         return;
     } else {
         // Extract the path part out of a file: URL.
@@ -304,17 +309,14 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
             return;
         }
-        
+
         // Memory map the file so that it can be read efficiently even if it is large.
         NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err];
-        
+
         if (err != nil) {
             NSLog(@"Error opening file %@: %@", source, err);
-            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:NOT_FOUND_ERR AndSource:source AndTarget:server]];
-            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        } else {
-            [self uploadData:fileData command:command];
         }
+        [self uploadData:fileData command:command];
     }
 }
 
@@ -364,6 +366,13 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* objectId = [command.arguments objectAtIndex:3];
     NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil];
 
+    // return unsupported result for assets-library URLs
+    if ([target hasPrefix:kCDVAssetsLibraryPrefix]) {
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."];
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        return;
+    }
+
     CDVPluginResult* result = nil;
     CDVFileTransferError errorCode = 0;
 
@@ -375,17 +384,14 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         targetURL = [NSURL URLWithString:target];
     }
 
-    NSURL* sourceURL = [NSURL URLWithString:source];
+    NSURL* url = [NSURL URLWithString:source];
 
-    if (!sourceURL) {
+    if (!url) {
         errorCode = INVALID_URL_ERR;
         NSLog(@"File Transfer Error: Invalid server URL %@", source);
     } else if (![targetURL isFileURL]) {
-        CDVFilesystemURL *fsURL = [CDVFilesystemURL fileSystemURLWithString:target];
-        if (!fsURL) {
-           errorCode = FILE_NOT_FOUND_ERR;
-           NSLog(@"File Transfer Error: Invalid file path or URL %@", target);
-        }
+        errorCode = FILE_NOT_FOUND_ERR;
+        NSLog(@"File Transfer Error: Invalid file path or URL %@", target);
     }
 
     if (errorCode > 0) {
@@ -394,7 +400,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         return;
     }
 
-    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:sourceURL];
+    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
     [self applyRequestHeaders:headers toRequest:req];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
@@ -404,7 +410,6 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     delegate.objectId = objectId;
     delegate.source = source;
     delegate.target = target;
-    delegate.targetURL = targetURL;
     delegate.trustAllHosts = trustAllHosts;
 
     delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate];
@@ -517,6 +522,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* downloadResponse = nil;
     NSMutableDictionary* uploadResult;
     CDVPluginResult* result = nil;
+    BOOL bDirRequest = NO;
+    CDVFile* filePlugin;
 
     NSLog(@"File Transfer Finished with response code %d", self.responseCode);
 
@@ -542,7 +549,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
             self.targetFileHandle = nil;
             DLog(@"File Transfer Download success");
 
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[filePlugin makeEntryForURL:self.targetURL]];
+            filePlugin = [[CDVFile alloc] init];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[filePlugin getDirectoryEntry:target isDirectory:bDirRequest]];
         } else {
             downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
@@ -611,23 +619,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
     if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) {
         // Download response is okay; begin streaming output to file
-        NSString *filePath = nil;
-        CDVFilesystemURL *sourceURL = [CDVFilesystemURL fileSystemURLWithString:self.target];
-        if (sourceURL && sourceURL.fileSystemType != -1) {
-            // This requires talking to the current CDVFile plugin
-            NSObject<CDVFileSystem> *fs = [filePlugin.fileSystems objectAtIndex:sourceURL.fileSystemType];
-            filePath = [fs filesystemPathForURL:sourceURL];
-        } else {
-            // Extract the path part out of a file: URL.
-            NSString* filePath = [self.target hasPrefix:@"/"] ? [self.target copy] : [[NSURL URLWithString:self.target] path];
-            if (filePath == nil) {
-                // We couldn't find the asset.  Send the appropriate error.
-                [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create target file"]];
-                return;
-            }
-        }
-
-        NSString* parentPath = [filePath stringByDeletingLastPathComponent];
+        NSString* parentPath = [self.target stringByDeletingLastPathComponent];
 
         // create parent directories if needed
         if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
@@ -639,12 +631,12 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
             return;
         }
         // create target file
-        if ([[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil] == NO) {
+        if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) {
             [self cancelTransferWithError:connection errorMessage:@"Could not create target file"];
             return;
         }
         // open target file for writing
-        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
+        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target];
         if (self.targetFileHandle == nil) {
             [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"];
         }


[3/9] git commit: add ubuntu platform

Posted by st...@apache.org.
add ubuntu platform


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/4219ef3f
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/4219ef3f
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/4219ef3f

Branch: refs/heads/master
Commit: 4219ef3f81d542fad18d6c0716a2953614a381c4
Parents: 2d2e444
Author: Maxim Ermilov <ma...@canonical.com>
Authored: Wed Nov 13 09:54:59 2013 +0400
Committer: Maxim Ermilov <ma...@canonical.com>
Committed: Wed Nov 13 09:54:59 2013 +0400

----------------------------------------------------------------------
 plugin.xml                   |   6 +
 src/ubuntu/file-transfer.cpp | 247 ++++++++++++++++++++++++++++++++++++++
 src/ubuntu/file-transfer.h   |  97 +++++++++++++++
 3 files changed, 350 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4219ef3f/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index deb8dae..c9a2019 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -35,6 +35,12 @@
         <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
     </platform>
 
+    <!-- ubuntu -->
+    <platform name="ubuntu">
+        <header-file src="src/ubuntu/file-transfer.h" />
+        <source-file src="src/ubuntu/file-transfer.cpp" />
+    </platform>
+
     <platform name="blackberry10">
         <config-file target="www/config.xml" parent="/widget">
             <feature name="FileTransfer" value="FileTransfer"></feature>

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4219ef3f/src/ubuntu/file-transfer.cpp
----------------------------------------------------------------------
diff --git a/src/ubuntu/file-transfer.cpp b/src/ubuntu/file-transfer.cpp
new file mode 100644
index 0000000..192ba98
--- /dev/null
+++ b/src/ubuntu/file-transfer.cpp
@@ -0,0 +1,247 @@
+/*
+ *
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+#include "file-transfer.h"
+#include <cassert>
+
+void FileTransfer::download(int scId, int ecId, const QString& url, const QString &target, bool /*trustAllHost*/, int id, const QVariantMap &/*headers*/) {
+    QSharedPointer<FileTransferRequest> request(new FileTransferRequest(_manager, scId, ecId, id, this));
+
+    assert(_id2request.find(id) == _id2request.end());
+
+    _id2request.insert(id, request);
+
+    request->connect(request.data(), &FileTransferRequest::done, [&]() {
+        auto it = _id2request.find(id);
+        while (it != _id2request.end() && it.key() == id) {
+            if (it.value().data() == request.data()) {
+                _id2request.erase(it);
+                break;
+            }
+            it++;
+        }
+    });
+    request->download(url, target);
+}
+
+void FileTransfer::upload(int scId, int ecId, const QString &filePath, const QString& url, const QString& fileKey, const QString& fileName, const QString& mimeType,
+                          const QVariantMap & params, bool /*trustAllHosts*/, bool /*chunkedMode*/, const QVariantMap &headers, int id, const QString &httpMethod) {
+    QSharedPointer<FileTransferRequest> request(new FileTransferRequest(_manager, scId, ecId, id, this));
+
+    assert(_id2request.find(id) == _id2request.end());
+
+    _id2request.insert(id, request);
+
+    request->connect(request.data(), &FileTransferRequest::done, [&]() {
+        auto it = _id2request.find(id);
+        while (it != _id2request.end() && it.key() == id) {
+            if (it.value().data() == request.data()) {
+                _id2request.erase(it);
+                break;
+            }
+            it++;
+        }
+    });
+    request->upload(url, filePath, fileKey, fileName, mimeType, params, headers);
+}
+
+void FileTransfer::abort(int scId, int ecId, int id) {
+    Q_UNUSED(scId)
+    Q_UNUSED(ecId)
+
+    auto it = _id2request.find(id);
+    while (it != _id2request.end() && it.key() == id) {
+        (*it)->abort();
+        it++;
+    }
+}
+
+void FileTransferRequest::download(const QString& uri, const QString &target) {
+    QUrl url(uri);
+    QNetworkRequest request;
+
+    if (!url.isValid()) {
+        QVariantMap map;
+        map.insert("code", INVALID_URL_ERR);
+        map.insert("source", uri);
+        map.insert("target", target);
+        _plugin->cb(_ecId, map);
+        emit done();
+        return;
+    }
+
+    request.setUrl(url);
+    if (url.password().size() || url.userName().size()) {
+        QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64();
+        request.setRawHeader("Authorization", headerData.toLocal8Bit());
+    }
+    _reply = QSharedPointer<QNetworkReply>(_manager.get(request));
+
+    _reply->connect(_reply.data(), &QNetworkReply::finished, [this, target, uri]() {
+        if (!_scId || _reply->error() != QNetworkReply::NoError)
+            return;
+
+        QFile res(target);
+        qCritical() << target;
+        if (target[0] != '/' || !res.open(QIODevice::WriteOnly)) {
+            QVariantMap map;
+            map.insert("code", INVALID_URL_ERR);
+            map.insert("source", uri);
+            map.insert("target", target);
+            _plugin->cb(_ecId, map);
+            emit done();
+            return;
+        }
+        res.write(_reply->readAll());
+
+        QFileInfo info(target);
+        QVariantMap map;
+        map.insert("isFile", true);
+        map.insert("isDirectory", false);
+        map.insert("name", info.fileName());
+        map.insert("fullPath", info.absoluteFilePath());
+
+        _plugin->cb(_scId, map);
+
+        emit done();
+    });
+    _reply->connect(_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
+    _reply->connect(_reply.data(), SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64)));
+}
+
+void FileTransferRequest::upload(const QString& _url, const QString& filePath, QString fileKey, QString fileName, QString mimeType, const QVariantMap &params, const QVariantMap &headers) {
+    QUrl url(_url);
+    QNetworkRequest request;
+
+    if (!url.isValid()) {
+        QVariantMap map;
+        map.insert("code", INVALID_URL_ERR);
+        map.insert("source", filePath);
+        map.insert("target", _url);
+        _plugin->cb(_ecId, map);
+        emit done();
+        return;
+    }
+
+    QFile file(filePath);
+    if (filePath[0] != '/' || !file.open(QIODevice::ReadOnly)) {
+        QVariantMap map;
+        map.insert("code", FILE_NOT_FOUND_ERR);
+        map.insert("source", filePath);
+        map.insert("target", _url);
+        _plugin->cb(_ecId, map);
+        emit done();
+        return;
+    }
+    QString content{file.readAll()};
+
+    request.setUrl(url);
+    if (url.password().size() || url.userName().size()) {
+        QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64();
+        request.setRawHeader("Authorization", headerData.toLocal8Bit());
+    }
+
+    for (const QString &key: headers.keys()) {
+        const QString &value = headers.find(key)->toString();
+        request.setRawHeader(key.toUtf8(), value.toUtf8());
+    }
+
+    QString boundary = QString("CORDOVA-QT-%1A").arg(qrand());
+    while (content.contains(boundary)) {
+        boundary += QString("B%1A").arg(qrand());
+    }
+
+    request.setHeader(QNetworkRequest::ContentTypeHeader, QString("multipart/form-data; boundary=") + boundary);
+
+    fileKey.replace("\"", "");
+    fileName.replace("\"", "");
+    mimeType.replace("\"", "");
+    QString part = "--" + boundary + "\r\n";
+
+    part += "Content-Disposition: form-data; name=\"" + fileKey +"\"; filename=\"" + fileName + "\"\r\n";
+    part += "Content-Type: " + mimeType + "\r\n\r\n";
+    part += content + "\r\n";
+
+    for (QString key: params.keys()) {
+        part += "--" + boundary + "\r\n";
+        part += "Content-Disposition: form-data; name=\"" +  key + "\";\r\n\r\n";
+        part += params.find(key)->toString();
+        part += "\r\n";
+    }
+
+    part += QString("--") + boundary + "--" + "\r\n";
+
+    _reply = QSharedPointer<QNetworkReply>(_manager.post(request, QByteArray(part.toUtf8())));
+
+    _reply->connect(_reply.data(), &QNetworkReply::finished, [this, content]() {
+        if (_reply->error() != QNetworkReply::NoError)
+            return;
+        int status = 200;
+        QVariant statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+
+        if (statusCode.isValid()) {
+            status = statusCode.toInt();
+        }
+
+        QVariantMap map;
+        map.insert("responseCode", status);
+        map.insert("response", QString(_reply->readAll()));
+        map.insert("bytesSent", content.size());
+        _plugin->cb(_scId, map);
+        emit done();
+    });
+    _reply->connect(_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
+    _reply->connect(_reply.data(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64)));
+}
+
+void FileTransferRequest::abort() {
+    QVariantMap map;
+    map.insert("code", ABORT_ERR);
+    _plugin->cb(_ecId, map);
+    _scId = 0;
+    emit done();
+}
+
+void FileTransferRequest::error(QNetworkReply::NetworkError code) {
+    Q_UNUSED(code);
+
+    int status = 404;
+    QVariant statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+
+    if (statusCode.isValid()) {
+        status = statusCode.toInt();
+    }
+
+    QVariantMap map;
+    map.insert("http_status", status);
+    map.insert("body", QString(_reply->readAll()));
+    map.insert("code", CONNECTION_ERR);
+    _plugin->cb(_ecId, map);
+    emit done();
+}
+
+void FileTransferRequest::progress(qint64 bytesReceived, qint64 bytesTotal) {
+    QVariantMap map;
+    map.insert("lengthComputable", true);
+    map.insert("total", bytesTotal);
+    map.insert("loaded", bytesReceived);
+
+    if (bytesReceived && bytesTotal && _scId)
+        _plugin->callbackWithoutRemove(_scId, CordovaInternal::format(map));
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4219ef3f/src/ubuntu/file-transfer.h
----------------------------------------------------------------------
diff --git a/src/ubuntu/file-transfer.h b/src/ubuntu/file-transfer.h
new file mode 100644
index 0000000..b30a99f
--- /dev/null
+++ b/src/ubuntu/file-transfer.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+#ifndef FILE_TRANSFER_H_SDASDASDAS
+#define FILE_TRANSFER_H_SDASDASDAS
+
+#include <QtCore>
+#include <QtNetwork>
+
+#include <cplugin.h>
+
+class FileTransferRequest: public QObject {
+    Q_OBJECT
+
+    QNetworkAccessManager &_manager;
+    int _scId, _ecId;
+    int _id;
+    QSharedPointer<QNetworkReply> _reply;
+
+    enum FileTransferError {
+        FILE_NOT_FOUND_ERR = 1,
+        INVALID_URL_ERR = 2,
+        CONNECTION_ERR = 3,
+        ABORT_ERR = 4
+    };
+
+public:
+    FileTransferRequest(QNetworkAccessManager &manager, int scId, int ecId, int id, CPlugin *plugin):
+        _manager(manager),
+        _scId(scId),
+        _ecId(ecId),
+        _id(id),
+        _plugin(plugin) {
+    }
+
+    void download(const QString& url, const QString &target);
+    void upload(const QString& _url, const QString& filePath, QString fileKey, QString fileName, QString mimeType, const QVariantMap &params, const QVariantMap &headers);
+    void abort();
+
+signals:
+    void done();
+
+private slots:
+    void progress(qint64 bytesReceived, qint64 bytesTotal);
+    void error(QNetworkReply::NetworkError code);
+private:
+    CPlugin *_plugin;
+    Q_DISABLE_COPY(FileTransferRequest);
+};
+
+class FileTransfer : public CPlugin {
+    Q_OBJECT
+public:
+    explicit FileTransfer(Cordova *cordova): CPlugin(cordova) {
+    }
+
+    virtual const QString fullName() override {
+        return FileTransfer::fullID();
+    }
+
+    virtual const QString shortName() override {
+        return "FileTransfer";
+    }
+
+    static const QString fullID() {
+        return "FileTransfer";
+    }
+
+public slots:
+    void abort(int scId, int ecId, int id);
+    void download(int scId, int ecId, const QString& url, const QString &target, bool /*trustAllHost*/, int id, const QVariantMap &/*headers*/);
+    void upload(int scId, int ecId, const QString &filePath, const QString& url, const QString& fileKey, const QString& fileName, const QString& mimeType,
+                const QVariantMap & params, bool /*trustAllHosts*/, bool /*chunkedMode*/, const QVariantMap &headers, int id, const QString &httpMethod);
+
+private:
+    QNetworkAccessManager _manager;
+    QMultiMap<int, QSharedPointer<FileTransferRequest> > _id2request;
+    int lastRequestId;
+};
+
+#endif


[6/9] git commit: Merge branch 'dev' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer into dev

Posted by st...@apache.org.
Merge branch 'dev' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer into dev


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/4c259e7a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/4c259e7a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/4c259e7a

Branch: refs/heads/master
Commit: 4c259e7a1488a49f9d889ec434e9608465339476
Parents: a80ae04 a61f0f3
Author: Steven Gill <st...@gmail.com>
Authored: Tue Nov 26 16:52:17 2013 -0800
Committer: Steven Gill <st...@gmail.com>
Committed: Tue Nov 26 16:52:17 2013 -0800

----------------------------------------------------------------------
 plugin.xml                |   2 +-
 src/ios/CDVFileTransfer.h |   1 +
 src/ios/CDVFileTransfer.m | 129 ++++++++++++++++++++++-------------------
 www/FileTransfer.js       |   1 +
 4 files changed, 72 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/4c259e7a/plugin.xml
----------------------------------------------------------------------


[9/9] git commit: [CB-5565] Updated version and RELEASENOTES.md for release 0.4.0

Posted by st...@apache.org.
[CB-5565] Updated version and RELEASENOTES.md for release 0.4.0


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/76baae96
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/76baae96
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/76baae96

Branch: refs/heads/master
Commit: 76baae9690a1254a8b17cd36970597aabffac07e
Parents: 4c11f54
Author: Steven Gill <st...@gmail.com>
Authored: Wed Dec 4 15:16:30 2013 -0800
Committer: Steven Gill <st...@gmail.com>
Committed: Wed Dec 4 15:16:30 2013 -0800

----------------------------------------------------------------------
 RELEASENOTES.md | 7 +++++++
 plugin.xml      | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/76baae96/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 5985831..2ef1bfd 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -37,3 +37,10 @@
  ### 0.3.4 (Oct 28, 2013)
 * CB-5128: added repo + issue tag to plugin.xml for file transfer plugin
 * [CB-5010] Incremented plugin version on dev branch.
+
+### 0.4.0 (Dec 4, 2013)
+* CB-5466: Partial revert; we're not ready yet for FS urls
+* add ubuntu platform
+* CB-5466: Minor version bump
+* CB-5466: Update FileTransfer plugin to accept filesystem urls
+* Added amazon-fireos platform. Change to use amazon-fireos as the platform if the user agen string contains 'cordova-amazon-fireos'

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/76baae96/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 34371bb..91896f9 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,7 +2,7 @@
 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     xmlns:android="http://schemas.android.com/apk/res/android"
     id="org.apache.cordova.file-transfer"
-    version="0.4.0-dev">
+    version="0.4.0">
     <name>File Transfer</name>
     <description>Cordova File Transfer Plugin</description>
     <license>Apache 2.0</license>


[4/9] git commit: CB-5466: Update FileTransfer plugin to accept filesystem urls

Posted by st...@apache.org.
CB-5466: Update FileTransfer plugin to accept filesystem urls


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/2f1411f5
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/2f1411f5
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/2f1411f5

Branch: refs/heads/master
Commit: 2f1411f5dc37854ded35ee31671e66b380b8117f
Parents: 60f96e0
Author: Ian Clelland <ic...@chromium.org>
Authored: Fri Nov 22 09:40:56 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Fri Nov 22 10:31:38 2013 -0500

----------------------------------------------------------------------
 src/ios/CDVFileTransfer.h |   1 +
 src/ios/CDVFileTransfer.m | 129 ++++++++++++++++++++++-------------------
 www/FileTransfer.js       |   1 +
 3 files changed, 71 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/2f1411f5/src/ios/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVFileTransfer.h b/src/ios/CDVFileTransfer.h
index 8e8211d..aa1cf9e 100644
--- a/src/ios/CDVFileTransfer.h
+++ b/src/ios/CDVFileTransfer.h
@@ -71,6 +71,7 @@ extern NSString* const kOptionsKeyCookie;
 @property (nonatomic, copy) NSString* objectId;
 @property (nonatomic, copy) NSString* source;
 @property (nonatomic, copy) NSString* target;
+@property (nonatomic, copy) NSURL* targetURL;
 @property (nonatomic, copy) NSString* mimeType;
 @property (assign) int responseCode; // atomic
 @property (nonatomic, assign) long long bytesTransfered;

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/2f1411f5/src/ios/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVFileTransfer.m b/src/ios/CDVFileTransfer.m
index f1fd4d3..2eec342 100644
--- a/src/ios/CDVFileTransfer.m
+++ b/src/ios/CDVFileTransfer.m
@@ -20,12 +20,15 @@
 #import <Cordova/CDV.h>
 #import "CDVFileTransfer.h"
 #import "CDVFile.h"
+#import "CDVLocalFilesystem.h"
 
 #import <AssetsLibrary/ALAsset.h>
 #import <AssetsLibrary/ALAssetRepresentation.h>
 #import <AssetsLibrary/ALAssetsLibrary.h>
 #import <CFNetwork/CFNetwork.h>
 
+extern CDVFile *filePlugin;
+
 @interface CDVFileTransfer ()
 // Sets the requests headers for the request.
 - (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req;
@@ -270,52 +273,48 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
 - (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command
 {
-    NSString* target = (NSString*)[command.arguments objectAtIndex:0];
+    NSString* source = (NSString*)[command.arguments objectAtIndex:0];
+    NSString* server = [command.arguments objectAtIndex:1];
     NSError* __autoreleasing err = nil;
 
-    // return unsupported result for assets-library URLs
-    if ([target hasPrefix:kCDVAssetsLibraryPrefix]) {
-        // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
-            if (asset) {
-                // We have the asset!  Get the data and send it off.
-                ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                Byte* buffer = (Byte*)malloc([assetRepresentation size]);
-                NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
-                NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
-                [self uploadData:fileData command:command];
-            } else {
+    CDVFilesystemURL *sourceURL = [CDVFilesystemURL fileSystemURLWithString:source];
+    NSObject<CDVFileSystem> *fs;
+    if (sourceURL) {
+        // Try to get a CDVFileSystem which will handle this file.
+        // This requires talking to the current CDVFile plugin.
+        fs = [filePlugin filesystemForURL:sourceURL];
+    }
+    if (fs) {
+        [fs readFileAtURL:sourceURL start:0 end:-1 callback:^(NSData *fileData, NSString *mimeType, CDVFileError err) {
+            if (err) {
                 // We couldn't find the asset.  Send the appropriate error.
-                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:NOT_FOUND_ERR AndSource:source AndTarget:server]];
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+            }  else {
+                [self uploadData:fileData command:command];
             }
-        };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
-            // Retrieving the asset failed for some reason.  Send the appropriate error.
-            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
-            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        };
-
-        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
-        [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock];
+        }];
         return;
     } else {
         // Extract the path part out of a file: URL.
-        NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
+        NSString* filePath = [source hasPrefix:@"/"] ? [source copy] : [[NSURL URLWithString:source] path];
         if (filePath == nil) {
             // We couldn't find the asset.  Send the appropriate error.
-            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:NOT_FOUND_ERR AndSource:source AndTarget:server]];
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
             return;
         }
-
+        
         // Memory map the file so that it can be read efficiently even if it is large.
         NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err];
-
+        
         if (err != nil) {
-            NSLog(@"Error opening file %@: %@", target, err);
+            NSLog(@"Error opening file %@: %@", source, err);
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:NOT_FOUND_ERR AndSource:source AndTarget:server]];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        } else {
+            [self uploadData:fileData command:command];
         }
-        [self uploadData:fileData command:command];
     }
 }
 
@@ -359,47 +358,43 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 - (void)download:(CDVInvokedUrlCommand*)command
 {
     DLog(@"File Transfer downloading file...");
-    NSString* sourceUrl = [command.arguments objectAtIndex:0];
-    NSString* filePath = [command.arguments objectAtIndex:1];
+    NSString* source = [command.arguments objectAtIndex:0];
+    NSString* target = [command.arguments objectAtIndex:1];
     BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
     NSString* objectId = [command.arguments objectAtIndex:3];
     NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil];
 
-    // return unsupported result for assets-library URLs
-    if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
     CDVPluginResult* result = nil;
     CDVFileTransferError errorCode = 0;
 
-    NSURL* file;
+    NSURL* targetURL;
 
-    if ([filePath hasPrefix:@"/"]) {
-        file = [NSURL fileURLWithPath:filePath];
+    if ([target hasPrefix:@"/"]) {
+        targetURL = [NSURL fileURLWithPath:target];
     } else {
-        file = [NSURL URLWithString:filePath];
+        targetURL = [NSURL URLWithString:target];
     }
 
-    NSURL* url = [NSURL URLWithString:sourceUrl];
+    NSURL* sourceURL = [NSURL URLWithString:source];
 
-    if (!url) {
+    if (!sourceURL) {
         errorCode = INVALID_URL_ERR;
-        NSLog(@"File Transfer Error: Invalid server URL %@", sourceUrl);
-    } else if (![file isFileURL]) {
-        errorCode = FILE_NOT_FOUND_ERR;
-        NSLog(@"File Transfer Error: Invalid file path or URL %@", filePath);
+        NSLog(@"File Transfer Error: Invalid server URL %@", source);
+    } else if (![targetURL isFileURL]) {
+        CDVFilesystemURL *fsURL = [CDVFilesystemURL fileSystemURLWithString:target];
+        if (!fsURL) {
+           errorCode = FILE_NOT_FOUND_ERR;
+           NSLog(@"File Transfer Error: Invalid file path or URL %@", target);
+        }
     }
 
     if (errorCode > 0) {
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:sourceUrl AndTarget:filePath]];
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:source AndTarget:target]];
         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
         return;
     }
 
-    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
+    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:sourceURL];
     [self applyRequestHeaders:headers toRequest:req];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
@@ -407,8 +402,9 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     delegate.direction = CDV_TRANSFER_DOWNLOAD;
     delegate.callbackId = command.callbackId;
     delegate.objectId = objectId;
-    delegate.source = sourceUrl;
-    delegate.target = filePath;
+    delegate.source = source;
+    delegate.target = target;
+    delegate.targetURL = targetURL;
     delegate.trustAllHosts = trustAllHosts;
 
     delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate];
@@ -521,8 +517,6 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* downloadResponse = nil;
     NSMutableDictionary* uploadResult;
     CDVPluginResult* result = nil;
-    BOOL bDirRequest = NO;
-    CDVFile* file;
 
     NSLog(@"File Transfer Finished with response code %d", self.responseCode);
 
@@ -548,8 +542,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
             self.targetFileHandle = nil;
             DLog(@"File Transfer Download success");
 
-            file = [[CDVFile alloc] init];
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[filePlugin makeEntryForURL:self.targetURL]];
         } else {
             downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
@@ -618,7 +611,23 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
     if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) {
         // Download response is okay; begin streaming output to file
-        NSString* parentPath = [self.target stringByDeletingLastPathComponent];
+        NSString *filePath = nil;
+        CDVFilesystemURL *sourceURL = [CDVFilesystemURL fileSystemURLWithString:self.target];
+        if (sourceURL && sourceURL.fileSystemType != -1) {
+            // This requires talking to the current CDVFile plugin
+            NSObject<CDVFileSystem> *fs = [filePlugin.fileSystems objectAtIndex:sourceURL.fileSystemType];
+            filePath = [fs filesystemPathForURL:sourceURL];
+        } else {
+            // Extract the path part out of a file: URL.
+            NSString* filePath = [self.target hasPrefix:@"/"] ? [self.target copy] : [[NSURL URLWithString:self.target] path];
+            if (filePath == nil) {
+                // We couldn't find the asset.  Send the appropriate error.
+                [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create target file"]];
+                return;
+            }
+        }
+
+        NSString* parentPath = [filePath stringByDeletingLastPathComponent];
 
         // create parent directories if needed
         if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
@@ -630,16 +639,16 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
             return;
         }
         // create target file
-        if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) {
+        if ([[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil] == NO) {
             [self cancelTransferWithError:connection errorMessage:@"Could not create target file"];
             return;
         }
         // open target file for writing
-        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target];
+        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
         if (self.targetFileHandle == nil) {
             [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"];
         }
-        DLog(@"Streaming to file %@", target);
+        DLog(@"Streaming to file %@", filePath);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/2f1411f5/www/FileTransfer.js
----------------------------------------------------------------------
diff --git a/www/FileTransfer.js b/www/FileTransfer.js
index 66a1c4b..d6690fe 100644
--- a/www/FileTransfer.js
+++ b/www/FileTransfer.js
@@ -184,6 +184,7 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
             entry.isFile = result.isFile;
             entry.name = result.name;
             entry.fullPath = result.fullPath;
+            entry.filesystem = new FileSystem(result.filesystem == window.PERSISTENT ? 'persistent' : 'temporary');
             successCallback(entry);
         }
     };


[2/9] git commit: Added amazon-fireos platform. Change to use amazon-fireos as the platform if the user agen string contains 'cordova-amazon-fireos'

Posted by st...@apache.org.
Added amazon-fireos platform.
Change to use amazon-fireos as the platform if the user agen string contains 'cordova-amazon-fireos'


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/a80ae041
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/a80ae041
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/a80ae041

Branch: refs/heads/master
Commit: a80ae0417b45052c8e2064f605c7027afcadcd06
Parents: 60f96e0
Author: Archana Naik <na...@lab126.com>
Authored: Fri Oct 18 14:44:05 2013 -0700
Committer: Archana Naik <na...@lab126.com>
Committed: Wed Oct 30 13:20:08 2013 -0700

----------------------------------------------------------------------
 plugin.xml                   |  17 +
 src/amazon/FileTransfer.java | 873 ++++++++++++++++++++++++++++++++++++++
 test/cordova-incl.js         |   3 +-
 3 files changed, 892 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/a80ae041/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index d1de8dd..8d6bafe 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -37,6 +37,23 @@
         <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
     </platform>
 
+    <!-- amamzon-fireos -->
+    <platform name="amazon-fireos">
+        <config-file target="res/xml/config.xml" parent="/*">
+            <feature name="FileTransfer" >
+                <param name="android-package" value="org.apache.cordova.filetransfer.FileTransfer"/>
+            </feature>
+        </config-file>
+
+        <config-file target="AndroidManifest.xml" parent="/*">
+            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+        </config-file>
+
+        <source-file src="src/amazon/FileTransfer.java" target-dir="src/org/apache/cordova/filetransfer" />
+        <source-file src="src/android/FileProgressResult.java" target-dir="src/org/apache/cordova/filetransfer" />
+        <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
+    </platform>
+    
     <platform name="blackberry10">
         <config-file target="www/config.xml" parent="/widget">
             <feature name="FileTransfer" value="FileTransfer"></feature>

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/a80ae041/src/amazon/FileTransfer.java
----------------------------------------------------------------------
diff --git a/src/amazon/FileTransfer.java b/src/amazon/FileTransfer.java
new file mode 100644
index 0000000..2e0c31c
--- /dev/null
+++ b/src/amazon/FileTransfer.java
@@ -0,0 +1,873 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.filetransfer;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.cordova.Config;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
+import org.apache.cordova.PluginResult;
+import org.apache.cordova.file.FileUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.net.Uri;
+import android.os.Build;
+import android.util.Log;
+import com.amazon.android.webkit.AmazonCookieManager;
+
+public class FileTransfer extends CordovaPlugin {
+
+    private static final String LOG_TAG = "FileTransfer";
+    private static final String LINE_START = "--";
+    private static final String LINE_END = "\r\n";
+    private static final String BOUNDARY =  "+++++";
+
+    public static int FILE_NOT_FOUND_ERR = 1;
+    public static int INVALID_URL_ERR = 2;
+    public static int CONNECTION_ERR = 3;
+    public static int ABORTED_ERR = 4;
+
+    private static HashMap<String, RequestContext> activeRequests = new HashMap<String, RequestContext>();
+    private static final int MAX_BUFFER_SIZE = 16 * 1024;
+
+    private static final class RequestContext {
+        String source;
+        String target;
+        File targetFile;
+        CallbackContext callbackContext;
+        InputStream currentInputStream;
+        OutputStream currentOutputStream;
+        boolean aborted;
+        RequestContext(String source, String target, CallbackContext callbackContext) {
+            this.source = source;
+            this.target = target;
+            this.callbackContext = callbackContext;
+        }
+        void sendPluginResult(PluginResult pluginResult) {
+            synchronized (this) {
+                if (!aborted) {
+                    callbackContext.sendPluginResult(pluginResult);
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds an interface method to an InputStream to return the number of bytes
+     * read from the raw stream. This is used to track total progress against
+     * the HTTP Content-Length header value from the server.
+     */
+    private static abstract class TrackingInputStream extends FilterInputStream {
+      public TrackingInputStream(final InputStream in) {
+        super(in);
+      }
+        public abstract long getTotalRawBytesRead();
+  }
+
+    private static class ExposedGZIPInputStream extends GZIPInputStream {
+      public ExposedGZIPInputStream(final InputStream in) throws IOException {
+        super(in);
+      }
+      public Inflater getInflater() {
+        return inf;
+      }
+  }
+
+    /**
+     * Provides raw bytes-read tracking for a GZIP input stream. Reports the
+     * total number of compressed bytes read from the input, rather than the
+     * number of uncompressed bytes.
+     */
+    private static class TrackingGZIPInputStream extends TrackingInputStream {
+      private ExposedGZIPInputStream gzin;
+      public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
+        super(gzin);
+        this.gzin = gzin;
+      }
+      public long getTotalRawBytesRead() {
+        return gzin.getInflater().getBytesRead();
+      }
+  }
+
+    /**
+     * Provides simple total-bytes-read tracking for an existing InputStream
+     */
+    private static class SimpleTrackingInputStream extends TrackingInputStream {
+        private long bytesRead = 0;
+        public SimpleTrackingInputStream(InputStream stream) {
+            super(stream);
+        }
+
+        private int updateBytesRead(int newBytesRead) {
+          if (newBytesRead != -1) {
+            bytesRead += newBytesRead;
+          }
+          return newBytesRead;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return updateBytesRead(super.read());
+        }
+
+        @Override
+        public int read(byte[] buffer) throws IOException {
+            return updateBytesRead(super.read(buffer));
+        }
+
+        @Override
+        public int read(byte[] bytes, int offset, int count) throws IOException {
+            return updateBytesRead(super.read(bytes, offset, count));
+        }
+
+        public long getTotalRawBytesRead() {
+          return bytesRead;
+        }
+    }
+
+    @Override
+    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
+        if (action.equals("upload") || action.equals("download")) {
+            String source = args.getString(0);
+            String target = args.getString(1);
+
+            if (action.equals("upload")) {
+                try {
+                    source = URLDecoder.decode(source, "UTF-8");
+                    upload(source, target, args, callbackContext);
+                } catch (UnsupportedEncodingException e) {
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, "UTF-8 error."));
+                }
+            } else {
+                download(source, target, args, callbackContext);
+            }
+            return true;
+        } else if (action.equals("abort")) {
+            String objectId = args.getString(0);
+            abort(objectId);
+            callbackContext.success();
+            return true;
+        }
+        return false;
+    }
+
+    private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
+        try {
+            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
+                String headerKey = iter.next().toString();
+                JSONArray headerValues = headers.optJSONArray(headerKey);
+                if (headerValues == null) {
+                    headerValues = new JSONArray();
+                    headerValues.put(headers.getString(headerKey));
+                }
+                connection.setRequestProperty(headerKey, headerValues.getString(0));
+                for (int i = 1; i < headerValues.length(); ++i) {
+                    connection.addRequestProperty(headerKey, headerValues.getString(i));
+                }
+            }
+        } catch (JSONException e1) {
+          // No headers to be manipulated!
+        }
+    }
+
+    /**
+     * Uploads the specified file to the server URL provided using an HTTP multipart request.
+     * @param source        Full path of the file on the file system
+     * @param target        URL of the server to receive the file
+     * @param args          JSON Array of args
+     * @param callbackContext    callback id for optional progress reports
+     *
+     * args[2] fileKey       Name of file request parameter
+     * args[3] fileName      File name to be used on server
+     * args[4] mimeType      Describes file content type
+     * args[5] params        key:value pairs of user-defined parameters
+     * @return FileUploadResult containing result of upload request
+     */
+    private void upload(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        Log.d(LOG_TAG, "upload " + source + " to " +  target);
+
+        // Setup the options
+        final String fileKey = getArgument(args, 2, "file");
+        final String fileName = getArgument(args, 3, "image.jpg");
+        final String mimeType = getArgument(args, 4, "image/jpeg");
+        final JSONObject params = args.optJSONObject(5) == null ? new JSONObject() : args.optJSONObject(5);
+        final boolean trustEveryone = args.optBoolean(6);
+        // Always use chunked mode unless set to false as per API
+        final boolean chunkedMode = args.optBoolean(7) || args.isNull(7);
+        // Look for headers on the params map for backwards compatibility with older Cordova versions.
+        final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
+        final String objectId = args.getString(9);
+        final String httpMethod = getArgument(args, 10, "POST");
+        
+        final CordovaResourceApi resourceApi = webView.getResourceApi();
+
+        Log.d(LOG_TAG, "fileKey: " + fileKey);
+        Log.d(LOG_TAG, "fileName: " + fileName);
+        Log.d(LOG_TAG, "mimeType: " + mimeType);
+        Log.d(LOG_TAG, "params: " + params);
+        Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
+        Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
+        Log.d(LOG_TAG, "headers: " + headers);
+        Log.d(LOG_TAG, "objectId: " + objectId);
+        Log.d(LOG_TAG, "httpMethod: " + httpMethod);
+        
+        final Uri targetUri = resourceApi.remapUri(Uri.parse(target));
+        // Accept a path or a URI for the source.
+        Uri tmpSrc = Uri.parse(source);
+        final Uri sourceUri = resourceApi.remapUri(
+            tmpSrc.getScheme() != null ? tmpSrc : Uri.fromFile(new File(source)));
+
+        int uriType = CordovaResourceApi.getUriType(targetUri);
+        final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
+        if (uriType != CordovaResourceApi.URI_TYPE_HTTP && !useHttps) {
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
+            Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+            return;
+        }
+
+        final RequestContext context = new RequestContext(source, target, callbackContext);
+        synchronized (activeRequests) {
+            activeRequests.put(objectId, context);
+        }
+        
+        cordova.getThreadPool().execute(new Runnable() {
+            public void run() {
+                if (context.aborted) {
+                    return;
+                }
+                HttpURLConnection conn = null;
+                HostnameVerifier oldHostnameVerifier = null;
+                SSLSocketFactory oldSocketFactory = null;
+                int totalBytes = 0;
+                int fixedLength = -1;
+                try {
+                    // Create return object
+                    FileUploadResult result = new FileUploadResult();
+                    FileProgressResult progress = new FileProgressResult();
+
+                    //------------------ CLIENT REQUEST
+                    // Open a HTTP connection to the URL based on protocol
+                    conn = resourceApi.createHttpConnection(targetUri);
+                    if (useHttps && trustEveryone) {
+                        // Setup the HTTPS connection class to trust everyone
+                        HttpsURLConnection https = (HttpsURLConnection)conn;
+                        oldSocketFactory  = trustAllHosts(https);
+                        // Save the current hostnameVerifier
+                        oldHostnameVerifier = https.getHostnameVerifier();
+                        // Setup the connection not to verify hostnames
+                        https.setHostnameVerifier(DO_NOT_VERIFY);
+                    }
+
+                    // Allow Inputs
+                    conn.setDoInput(true);
+
+                    // Allow Outputs
+                    conn.setDoOutput(true);
+
+                    // Don't use a cached copy.
+                    conn.setUseCaches(false);
+
+                    // Use a post method.
+                    conn.setRequestMethod(httpMethod);
+                    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
+
+                    // Set the cookies on the response
+                    String cookie = AmazonCookieManager.getInstance().getCookie(target);
+                    if (cookie != null) {
+                        conn.setRequestProperty("Cookie", cookie);
+                    }
+
+                    // Handle the other headers
+                    if (headers != null) {
+                        addHeadersToRequest(conn, headers);
+                    }
+
+                    /*
+                        * Store the non-file portions of the multipart data as a string, so that we can add it
+                        * to the contentSize, since it is part of the body of the HTTP request.
+                        */
+                    StringBuilder beforeData = new StringBuilder();
+                    try {
+                        for (Iterator<?> iter = params.keys(); iter.hasNext();) {
+                            Object key = iter.next();
+                            if(!String.valueOf(key).equals("headers"))
+                            {
+                              beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
+                              beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
+                              beforeData.append(LINE_END).append(LINE_END);
+                              beforeData.append(params.getString(key.toString()));
+                              beforeData.append(LINE_END);
+                            }
+                        }
+                    } catch (JSONException e) {
+                        Log.e(LOG_TAG, e.getMessage(), e);
+                    }
+
+                    beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
+                    beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
+                    beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
+                    beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
+                    byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
+                    byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
+
+                    
+                    // Get a input stream of the file on the phone
+                    OpenForReadResult readResult = resourceApi.openForRead(sourceUri);
+                    
+                    int stringLength = beforeDataBytes.length + tailParamsBytes.length;
+                    if (readResult.length >= 0) {
+                        fixedLength = (int)readResult.length + stringLength;
+                        progress.setLengthComputable(true);
+                        progress.setTotal(fixedLength);
+                    }
+                    Log.d(LOG_TAG, "Content Length: " + fixedLength);
+                    // setFixedLengthStreamingMode causes and OutOfMemoryException on pre-Froyo devices.
+                    // http://code.google.com/p/android/issues/detail?id=3164
+                    // It also causes OOM if HTTPS is used, even on newer devices.
+                    boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
+                    useChunkedMode = useChunkedMode || (fixedLength == -1);
+
+                    if (useChunkedMode) {
+                        conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
+                        // Although setChunkedStreamingMode sets this header, setting it explicitly here works
+                        // around an OutOfMemoryException when using https.
+                        conn.setRequestProperty("Transfer-Encoding", "chunked");
+                    } else {
+                        conn.setFixedLengthStreamingMode(fixedLength);
+                    }
+
+                    conn.connect();
+                    
+                    OutputStream sendStream = null;
+                    try {
+                        sendStream = conn.getOutputStream();
+                        synchronized (context) {
+                            if (context.aborted) {
+                                return;
+                            }
+                            context.currentOutputStream = sendStream;
+                        }
+                        //We don't want to change encoding, we just want this to write for all Unicode.
+                        sendStream.write(beforeDataBytes);
+                        totalBytes += beforeDataBytes.length;
+    
+                        // create a buffer of maximum size
+                        int bytesAvailable = readResult.inputStream.available();
+                        int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
+                        byte[] buffer = new byte[bufferSize];
+    
+                        // read file and write it into form...
+                        int bytesRead = readResult.inputStream.read(buffer, 0, bufferSize);
+    
+                        long prevBytesRead = 0;
+                        while (bytesRead > 0) {
+                            result.setBytesSent(totalBytes);
+                            sendStream.write(buffer, 0, bytesRead);
+                            totalBytes += bytesRead;
+                            if (totalBytes > prevBytesRead + 102400) {
+                                prevBytesRead = totalBytes;
+                                Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
+                            }
+                            bytesAvailable = readResult.inputStream.available();
+                            bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
+                            bytesRead = readResult.inputStream.read(buffer, 0, bufferSize);
+
+                            // Send a progress event.
+                            progress.setLoaded(totalBytes);
+                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
+                            progressResult.setKeepCallback(true);
+                            context.sendPluginResult(progressResult);
+                        }
+    
+                        // send multipart form data necessary after file data...
+                        sendStream.write(tailParamsBytes);
+                        totalBytes += tailParamsBytes.length;
+                        sendStream.flush();
+                    } finally {
+                        safeClose(readResult.inputStream);
+                        safeClose(sendStream);
+                    }
+                    context.currentOutputStream = null;
+                    Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
+
+                    //------------------ read the SERVER RESPONSE
+                    String responseString;
+                    int responseCode = conn.getResponseCode();
+                    Log.d(LOG_TAG, "response code: " + responseCode);
+                    Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
+                    TrackingInputStream inStream = null;
+                    try {
+                        inStream = getInputStream(conn);
+                        synchronized (context) {
+                            if (context.aborted) {
+                                return;
+                            }
+                            context.currentInputStream = inStream;
+                        }
+                        
+                        ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
+                        byte[] buffer = new byte[1024];
+                        int bytesRead = 0;
+                        // write bytes to file
+                        while ((bytesRead = inStream.read(buffer)) > 0) {
+                            out.write(buffer, 0, bytesRead);
+                        }
+                        responseString = out.toString("UTF-8");
+                    } finally {
+                        context.currentInputStream = null;
+                        safeClose(inStream);
+                    }
+                    
+                    Log.d(LOG_TAG, "got response from server");
+                    Log.d(LOG_TAG, responseString.substring(0, Math.min(256, responseString.length())));
+                    
+                    // send request and retrieve response
+                    result.setResponseCode(responseCode);
+                    result.setResponse(responseString);
+
+                    context.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
+                } catch (FileNotFoundException e) {
+                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, conn);
+                    Log.e(LOG_TAG, error.toString(), e);
+                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                } catch (IOException e) {
+                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
+                    Log.e(LOG_TAG, error.toString(), e);
+                    Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
+                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                } catch (JSONException e) {
+                    Log.e(LOG_TAG, e.getMessage(), e);
+                    context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                } catch (Throwable t) {
+                    // Shouldn't happen, but will
+                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
+                    Log.e(LOG_TAG, error.toString(), t);
+                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                } finally {
+                    synchronized (activeRequests) {
+                        activeRequests.remove(objectId);
+                    }
+
+                    if (conn != null) {
+                        // Revert back to the proper verifier and socket factories
+                        // Revert back to the proper verifier and socket factories
+                        if (trustEveryone && useHttps) {
+                            HttpsURLConnection https = (HttpsURLConnection) conn;
+                            https.setHostnameVerifier(oldHostnameVerifier);
+                            https.setSSLSocketFactory(oldSocketFactory);
+                        }
+                    }
+                }                
+            }
+        });
+    }
+
+    private static void safeClose(Closeable stream) {
+        if (stream != null) {
+            try {
+                stream.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
+        String encoding = conn.getContentEncoding();
+        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+          return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
+        }
+        return new SimpleTrackingInputStream(conn.getInputStream());
+    }
+
+    // always verify the host - don't check for certificate
+    private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    };
+    // Create a trust manager that does not validate certificate chains
+    private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
+        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+            return new java.security.cert.X509Certificate[] {};
+        }
+        
+        public void checkClientTrusted(X509Certificate[] chain,
+                String authType) throws CertificateException {
+        }
+        
+        public void checkServerTrusted(X509Certificate[] chain,
+                String authType) throws CertificateException {
+        }
+    } };
+
+    /**
+     * This function will install a trust manager that will blindly trust all SSL
+     * certificates.  The reason this code is being added is to enable developers
+     * to do development using self signed SSL certificates on their web server.
+     *
+     * The standard HttpsURLConnection class will throw an exception on self
+     * signed certificates if this code is not run.
+     */
+    private static SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
+        // Install the all-trusting trust manager
+        SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
+        try {
+            // Install our all trusting manager
+            SSLContext sc = SSLContext.getInstance("TLS");
+            sc.init(null, trustAllCerts, new java.security.SecureRandom());
+            SSLSocketFactory newFactory = sc.getSocketFactory();
+            connection.setSSLSocketFactory(newFactory);
+        } catch (Exception e) {
+            Log.e(LOG_TAG, e.getMessage(), e);
+        }
+        return oldFactory;
+    }
+
+    private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
+
+        int httpStatus = 0;
+        StringBuilder bodyBuilder = new StringBuilder();
+        String body = null;
+        if (connection != null) {
+            try {
+                if (connection instanceof HttpURLConnection) {
+                    httpStatus = ((HttpURLConnection)connection).getResponseCode();
+                    InputStream err = ((HttpURLConnection) connection).getErrorStream();
+                    if(err != null)
+                    {
+                        BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
+                        String line = reader.readLine();
+                        while(line != null)
+                        {
+                            bodyBuilder.append(line);
+                            line = reader.readLine();
+                            if(line != null)
+                                bodyBuilder.append('\n');
+                        }
+                        body = bodyBuilder.toString();
+                    }
+                }
+            // IOException can leave connection object in a bad state, so catch all exceptions.
+            } catch (Throwable e) {
+                Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
+            }
+        }
+
+        return createFileTransferError(errorCode, source, target, body, httpStatus);
+    }
+
+        /**
+        * Create an error object based on the passed in errorCode
+        * @param errorCode      the error
+        * @return JSONObject containing the error
+        */
+    private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
+        JSONObject error = null;
+        try {
+            error = new JSONObject();
+            error.put("code", errorCode);
+            error.put("source", source);
+            error.put("target", target);
+            if(body != null)
+            {
+                error.put("body", body);
+            }   
+            if (httpStatus != null) {
+                error.put("http_status", httpStatus);
+            }
+        } catch (JSONException e) {
+            Log.e(LOG_TAG, e.getMessage(), e);
+        }
+        return error;
+    }
+
+    /**
+     * Convenience method to read a parameter from the list of JSON args.
+     * @param args                      the args passed to the Plugin
+     * @param position          the position to retrieve the arg from
+     * @param defaultString the default to be used if the arg does not exist
+     * @return String with the retrieved value
+     */
+    private static String getArgument(JSONArray args, int position, String defaultString) {
+        String arg = defaultString;
+        if (args.length() > position) {
+            arg = args.optString(position);
+            if (arg == null || "null".equals(arg)) {
+                arg = defaultString;
+            }
+        }
+        return arg;
+    }
+
+    /**
+     * Downloads a file form a given URL and saves it to the specified directory.
+     *
+     * @param source        URL of the server to receive the file
+     * @param target            Full path of the file on the file system
+     */
+    private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        Log.d(LOG_TAG, "download " + source + " to " +  target);
+
+        final CordovaResourceApi resourceApi = webView.getResourceApi();
+
+        final boolean trustEveryone = args.optBoolean(2);
+        final String objectId = args.getString(3);
+        final JSONObject headers = args.optJSONObject(4);
+        
+        final Uri sourceUri = resourceApi.remapUri(Uri.parse(source));
+        // Accept a path or a URI for the source.
+        Uri tmpTarget = Uri.parse(target);
+        final Uri targetUri = resourceApi.remapUri(
+            tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new File(target)));
+
+        int uriType = CordovaResourceApi.getUriType(sourceUri);
+        final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
+        final boolean isLocalTransfer = !useHttps && uriType != CordovaResourceApi.URI_TYPE_HTTP;
+        if (uriType == CordovaResourceApi.URI_TYPE_UNKNOWN) {
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
+            Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+            return;
+        }
+        
+        // TODO: refactor to also allow resources & content:
+        if (!isLocalTransfer && !Config.isUrlWhiteListed(source)) {
+            Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
+            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+            return;
+        }
+
+        
+        final RequestContext context = new RequestContext(source, target, callbackContext);
+        synchronized (activeRequests) {
+            activeRequests.put(objectId, context);
+        }
+        
+        cordova.getThreadPool().execute(new Runnable() {
+            public void run() {
+                if (context.aborted) {
+                    return;
+                }
+                HttpURLConnection connection = null;
+                HostnameVerifier oldHostnameVerifier = null;
+                SSLSocketFactory oldSocketFactory = null;
+                File file = null;
+                PluginResult result = null;
+                TrackingInputStream inputStream = null;
+
+                OutputStream outputStream = null;
+                try {
+                    OpenForReadResult readResult = null;
+                    outputStream = resourceApi.openOutputStream(targetUri);
+
+                    file = resourceApi.mapUriToFile(targetUri);
+                    context.targetFile = file;
+                    
+                    Log.d(LOG_TAG, "Download file:" + sourceUri);
+
+                    FileProgressResult progress = new FileProgressResult();
+
+                    if (isLocalTransfer) {
+                        readResult = resourceApi.openForRead(sourceUri);
+                        if (readResult.length != -1) {
+                            progress.setLengthComputable(true);
+                            progress.setTotal(readResult.length);
+                        }
+                        inputStream = new SimpleTrackingInputStream(readResult.inputStream);
+                    } else {
+                        // connect to server
+                        // Open a HTTP connection to the URL based on protocol
+                        connection = resourceApi.createHttpConnection(sourceUri);
+                        if (useHttps && trustEveryone) {
+                            // Setup the HTTPS connection class to trust everyone
+                            HttpsURLConnection https = (HttpsURLConnection)connection;
+                            oldSocketFactory = trustAllHosts(https);
+                            // Save the current hostnameVerifier
+                            oldHostnameVerifier = https.getHostnameVerifier();
+                            // Setup the connection not to verify hostnames
+                            https.setHostnameVerifier(DO_NOT_VERIFY);
+                        }
+        
+                        connection.setRequestMethod("GET");
+        
+                        // TODO: Make OkHttp use this AmazonCookieManager by default.
+                        String cookie = AmazonCookieManager.getInstance().getCookie(sourceUri.toString());
+                        if(cookie != null)
+                        {
+                            connection.setRequestProperty("cookie", cookie);
+                        }
+                        
+                        // This must be explicitly set for gzip progress tracking to work.
+                        connection.setRequestProperty("Accept-Encoding", "gzip");
+    
+                        // Handle the other headers
+                        if (headers != null) {
+                            addHeadersToRequest(connection, headers);
+                        }
+        
+                        connection.connect();
+    
+                        if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
+                            // Only trust content-length header if we understand
+                            // the encoding -- identity or gzip
+                            progress.setLengthComputable(true);
+                            progress.setTotal(connection.getContentLength());
+                        }
+                        inputStream = getInputStream(connection);
+                    }
+                    
+                    try {
+                        synchronized (context) {
+                            if (context.aborted) {
+                                return;
+                            }
+                            context.currentInputStream = inputStream;
+                        }
+                        
+                        // write bytes to file
+                        byte[] buffer = new byte[MAX_BUFFER_SIZE];
+                        int bytesRead = 0;
+                        while ((bytesRead = inputStream.read(buffer)) > 0) {
+                            outputStream.write(buffer, 0, bytesRead);
+                            // Send a progress event.
+                            progress.setLoaded(inputStream.getTotalRawBytesRead());
+                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
+                            progressResult.setKeepCallback(true);
+                            context.sendPluginResult(progressResult);
+                        }
+                    } finally {
+                        context.currentInputStream = null;
+                        safeClose(inputStream);
+                        safeClose(outputStream);
+                    }
+    
+                    Log.d(LOG_TAG, "Saved file: " + target);
+    
+                    // create FileEntry object
+                    JSONObject fileEntry = FileUtils.getEntry(file);
+                    
+                    result = new PluginResult(PluginResult.Status.OK, fileEntry);
+                } catch (FileNotFoundException e) {
+                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
+                    Log.e(LOG_TAG, error.toString(), e);
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+                } catch (IOException e) {
+                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
+                    Log.e(LOG_TAG, error.toString(), e);
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+                } catch (JSONException e) {
+                    Log.e(LOG_TAG, e.getMessage(), e);
+                    result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+                } catch (Throwable e) {
+                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
+                    Log.e(LOG_TAG, error.toString(), e);
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+                } finally {
+                    safeClose(outputStream);
+                    synchronized (activeRequests) {
+                        activeRequests.remove(objectId);
+                    }
+
+                    if (connection != null) {
+                        // Revert back to the proper verifier and socket factories
+                        if (trustEveryone && useHttps) {
+                            HttpsURLConnection https = (HttpsURLConnection) connection;
+                            https.setHostnameVerifier(oldHostnameVerifier);
+                            https.setSSLSocketFactory(oldSocketFactory);
+                        }
+                    }
+
+                    if (result == null) {
+                        result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
+                    }
+                    // Remove incomplete download.
+                    if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
+                        file.delete();
+                    }
+                    context.sendPluginResult(result);
+                }
+            }
+        });
+    }
+
+    /**
+     * Abort an ongoing upload or download.
+     */
+    private void abort(String objectId) {
+        final RequestContext context;
+        synchronized (activeRequests) {
+            context = activeRequests.remove(objectId);
+        }
+        if (context != null) {
+            File file = context.targetFile;
+            if (file != null) {
+                file.delete();
+            }
+            // Trigger the abort callback immediately to minimize latency between it and abort() being called.
+            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
+            synchronized (context) {
+                context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
+                context.aborted = true;
+            }
+            // Closing the streams can block, so execute on a background thread.
+            cordova.getThreadPool().execute(new Runnable() {
+                public void run() {
+                    synchronized (context) {
+                        safeClose(context.currentInputStream);
+                        safeClose(context.currentOutputStream);
+                    }
+                }
+            });
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/a80ae041/test/cordova-incl.js
----------------------------------------------------------------------
diff --git a/test/cordova-incl.js b/test/cordova-incl.js
index a82c590..bd612be 100644
--- a/test/cordova-incl.js
+++ b/test/cordova-incl.js
@@ -22,6 +22,7 @@
 var PLAT;
 (function getPlatform() {
     var platforms = {
+        amazon_fireos: /cordova-amazon-fireos/,
         android: /Android/,
         ios: /(iPad)|(iPhone)|(iPod)/,
         blackberry10: /(BB10)/,
@@ -76,7 +77,7 @@ if (!window._doNotWriteCordovaScript) {
 }
 
 function backHome() {
-    if (window.device && device.platform && device.platform.toLowerCase() == 'android') {
+    if (window.device && device.platform && (device.platform.toLowerCase() == 'android' || device.platform.toLowerCase() == 'amazon-fireos')) {
         navigator.app.backHistory();
     }
     else {


[5/9] git commit: CB-5466: Minor version bump

Posted by st...@apache.org.
CB-5466: Minor version bump


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/a61f0f3d
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/a61f0f3d
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/a61f0f3d

Branch: refs/heads/master
Commit: a61f0f3d50078590ae4fef099cd9a4d2e4bde751
Parents: 2f1411f
Author: Ian Clelland <ic...@chromium.org>
Authored: Fri Nov 22 10:20:57 2013 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Fri Nov 22 10:31:59 2013 -0500

----------------------------------------------------------------------
 plugin.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/a61f0f3d/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index d1de8dd..529617f 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,7 +2,7 @@
 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     xmlns:android="http://schemas.android.com/apk/res/android"
     id="org.apache.cordova.file-transfer"
-    version="0.3.5-dev">
+    version="0.4.0-dev">
     <name>File Transfer</name>
     <description>Cordova File Transfer Plugin</description>
     <license>Apache 2.0</license>