You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/07 17:24:32 UTC

[27/51] [partial] [BlackBerry10] Added support for new platform

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/run
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/run b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/run
new file mode 100755
index 0000000..9f47e10
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/run
@@ -0,0 +1,204 @@
+#!/usr/bin/env node
+
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * 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.
+ */
+
+var childProcess = require("child_process"),
+    fs = require("fs"),
+    path = require("path"),
+    util = require("util"),
+    wrench = require("wrench"),
+    conf = require("./conf"),
+    localize = require("./localize"),
+    pkgrUtils = require("./packager-utils"),
+    properties = require('../../project.json'),
+    program = require('commander'),
+    xml2js = require('xml2js'),
+    target,
+    ip,
+    password,
+    workingdir,
+    barPath;
+
+function generateOptions(uninstall) {
+    var options = [];
+
+    workingdir = path.normalize(__dirname + "/.."),
+    barPath = path.normalize(__dirname + "/../../build/" + properties.targets[target].type + "/" + properties.barName + ".bar");
+
+    options.push("-device");
+    options.push(ip);
+
+    if (password) {
+        options.push("-password");
+        options.push(password);
+    }
+
+    options.push("-package");
+    options.push(barPath);
+
+    if (uninstall) {
+        options.push("-uninstallApp");
+        return options;
+    } else {
+
+        options.push("-installApp");
+
+        if (program.launch) {
+            options.push("-launchApp");
+        }
+
+        return options;
+    }
+}
+
+function execNativeDeploy(optionsArray, callback) {
+    var script = "/bin/blackberry-deploy",
+        nativeDeploy;
+        options = optionsArray.join(" ");
+
+    if (pkgrUtils.isWindows()) {
+        script += ".bat";
+    }
+
+    if (fs.existsSync(conf.DEPENDENCIES_TOOLS)) {
+        nativeDeploy = childProcess.exec(path.normalize(conf.DEPENDENCIES_TOOLS + script +" "+ options), {
+            "cwd": workingdir,
+            "env": process.env
+        });
+
+        nativeDeploy.stdout.on("data", pkgrUtils.handleProcessOutput);
+
+        nativeDeploy.stderr.on("data", pkgrUtils.handleProcessOutput);
+
+        nativeDeploy.on("exit", function (code) {
+            if (callback && typeof callback === "function") {
+                callback(code);
+            }
+        });
+    } else {
+        throw localize.translate("EXCEPTION_MISSING_TOOLS");
+    }
+}
+
+function checkTarget() {
+    if (!target) {
+        console.log("No target exists, to add that target please run target add <name> <ip> <type> [-p <password>] [--pin <devicepin>]\n");
+        return false;
+    }
+    if (!properties.targets[target]) {
+        console.log("The target \""+target+"\" does not exist, to add that target please run target add "+target+" <ip> <type> [-p <password>] [--pin <devicepin>]\n");
+        return false;
+    }
+    if (properties.targets[target].ip) {
+       ip = properties.targets[target].ip; 
+    } else {
+        console.log("IP is not defined in target \""+target+"\"\n");
+        return false;
+    }
+    if (properties.targets[target].password) {
+       password = properties.targets[target].password;
+    } 
+    return true;
+
+}
+
+function deployAll(keys) {
+    target = keys[0];
+
+    if (target) {
+        if (checkTarget()) {
+            var options = generateOptions();
+            if (program.uninstall) {
+                uninstall(
+                    function() {
+                        keys.shift();
+                        deployAll(keys);
+                });
+            } else {
+                execNativeDeploy(options,
+                    function() {
+                        deployAll(keys);
+                });
+            }
+        }
+    }
+}
+
+function uninstall(callback) {
+    var script = "/bin/blackberry-deploy",
+        nativeDeploy;
+
+    if (pkgrUtils.isWindows()) {
+        script += ".bat";
+    }
+
+    if (fs.existsSync(conf.DEPENDENCIES_TOOLS)) {
+        nativeDeploy = childProcess.exec(path.normalize(conf.DEPENDENCIES_TOOLS + script +" -listInstalledApps -device " +ip+ " -password " +password), {
+            "cwd": workingdir,
+            "env": process.env
+        }, function (error, stdout, stderr) {
+            var parser = new xml2js.Parser();
+            fs.readFile(path.join(__dirname + "/../../www/", "config.xml"), function(err, data) {
+                parser.parseString(data, function (err, result) {
+                    if (stdout.indexOf(result['@'].id) != -1) {
+                        var options = generateOptions(true);
+                        execNativeDeploy(options,
+                            function(){
+                                options = generateOptions(false);
+                                execNativeDeploy(options, callback);
+                        });
+                    } else {
+                        options = generateOptions(false);
+                        execNativeDeploy(options, callback);
+                    }
+                });
+            });
+        });
+    }
+}
+
+function exec(callback) {
+    program
+        .usage('command [<target>] [--no-launch] [--no-uninstall]')
+        .option('--no-uninstall', 'does not uninstall app from device')
+        .option('--no-launch', 'do not launch the app on device')
+
+    program
+        .command('all')
+        .usage('all [--no-launch] [--no-uninstall]')
+        .description('    Deploy the app on all targets')
+        .option('--no-uninstall', 'does not uninstall app from device')
+        .option('--no-launch', 'do not launch the app on device')
+    
+    program.parse(process.argv);
+    target = program.args[0] ? program.args[0] : properties.defaultTarget
+
+    if (target === "all") {
+        deployAll(Object.keys(properties.targets));
+    } else {
+        if (checkTarget()) {
+            if (program.uninstall) {
+                uninstall(callback);
+            } else {
+                options = generateOptions(false);
+                execNativeDeploy(options, callback)
+            }
+        }
+    }
+}
+
+exec(null);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/session.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/session.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/session.js
new file mode 100644
index 0000000..bb9fa06
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/session.js
@@ -0,0 +1,120 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * 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.
+ */
+
+var path = require("path"),
+    fs = require("fs"),
+    wrench = require("wrench"),
+    logger = require("./logger"),
+    signingHelper = require("./signing-helper"),
+    barConf = require("./bar-conf"),
+    localize = require("./localize"),
+    params;
+
+function getParams(cmdline, toolName) {
+    if (cmdline.params) {
+        if (!params) {
+            var paramsPath = path.resolve(cmdline.params);
+
+            if (fs.existsSync(paramsPath)) {
+                try {
+                    params = require(paramsPath);
+                } catch (e) {
+                    throw localize.translate("EXCEPTION_PARAMS_FILE_ERROR", paramsPath);
+                }
+            } else {
+                throw localize.translate("EXCEPTION_PARAMS_FILE_NOT_FOUND", paramsPath);
+            }
+        }
+
+        if (params) {
+            return params[toolName];
+        }
+    }
+
+    return null;
+}
+
+
+module.exports = {
+    initialize: function (cmdline) {
+        var sourceDir,
+            signingPassword,
+            outputDir = cmdline.output,
+            properties = require("../../project.json"),
+            archivePath = path.resolve(cmdline.args[0]),
+            archiveName = properties.barName ? properties.barName : path.basename(archivePath, '.zip'),
+            appdesc,
+            buildId = cmdline.buildId;
+
+        //If -o option was not provided, default output location is the same as .zip
+        outputDir = outputDir || path.dirname(archivePath);
+
+        //Only set signingPassword if it contains a value
+        if (cmdline.password && "string" === typeof cmdline.password) {
+            signingPassword = cmdline.password;
+        }
+
+        if (cmdline.appdesc && "string" === typeof cmdline.appdesc) {
+            appdesc = path.resolve(cmdline.appdesc);
+        }
+
+        //If -s [dir] is provided
+        if (cmdline.source && "string" === typeof cmdline.source) {
+            sourceDir = cmdline.source + "/src";
+        } else {
+            sourceDir = outputDir + "/src";
+        }
+
+        if (!fs.existsSync(sourceDir)) {
+            wrench.mkdirSyncRecursive(sourceDir, "0755");
+        }
+
+        logger.level(cmdline.loglevel || 'verbose');
+
+        return {
+            "conf": require("./conf"),
+            "keepSource": !!cmdline.source,
+            "sourceDir": path.resolve(sourceDir),
+            "sourcePaths": {
+                "ROOT": path.resolve(sourceDir),
+                "CHROME": path.normalize(path.resolve(sourceDir) + barConf.CHROME),
+                "LIB": path.normalize(path.resolve(sourceDir) + barConf.LIB),
+                "EXT": path.normalize(path.resolve(sourceDir) + barConf.EXT),
+                "UI": path.normalize(path.resolve(sourceDir) + barConf.UI),
+                "PLUGINS": path.normalize(path.resolve(sourceDir) + barConf.PLUGINS),
+                "JNEXT_PLUGINS": path.normalize(path.resolve(sourceDir) + barConf.JNEXT_PLUGINS)
+            },
+            "outputDir": path.resolve(outputDir),
+            "archivePath": archivePath,
+            "archiveName": archiveName,
+            "barPath": outputDir + "/%s/" + archiveName + ".bar",
+            "debug": !!cmdline.debug,
+            "keystore": signingHelper.getKeyStorePath(),
+            "keystoreCsk": signingHelper.getCskPath(),
+            "keystoreDb": signingHelper.getDbPath(),
+            "storepass": signingPassword,
+            "buildId": buildId,
+            "appdesc" : appdesc,
+            getParams: function (toolName) {
+                return getParams(cmdline, toolName);
+            },
+            isSigningRequired: function (config) {
+                return signingHelper.getKeyStorePath() && signingPassword && config.buildId;
+            },
+            "targets": ["simulator", "device"]
+        };
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/signing-helper.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/signing-helper.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/signing-helper.js
new file mode 100644
index 0000000..d0daafd
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/signing-helper.js
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * 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.
+ */
+var path = require('path'),
+    fs = require("fs"),
+    os = require('os'),
+    childProcess = require("child_process"),
+    util = require("util"),
+    conf = require("./conf"),
+    pkgrUtils = require("./packager-utils"),
+    logger = require("./logger"),
+    AUTHOR_P12 = "author.p12",
+    CSK = "barsigner.csk",
+    DB = "barsigner.db",
+    _self;
+
+function getDefaultPath(file) {
+    // The default location where signing key files are stored will vary based on the OS:
+    // Windows XP: %HOMEPATH%\Local Settings\Application Data\Research In Motion
+    // Windows Vista and Windows 7: %HOMEPATH%\AppData\Local\Research In Motion
+    // Mac OS: ~/Library/Research In Motion
+    // UNIX or Linux: ~/.rim
+    var p = "";
+    if (os.type().toLowerCase().indexOf("windows") >= 0) {
+        // Try Windows XP location
+        p = process.env.HOMEDRIVE + process.env.HOMEPATH + "\\Local Settings\\Application Data\\Research In Motion\\" + file;
+        if (fs.existsSync(p)) {
+            return p;
+        }
+
+        // Try Windows Vista and Windows 7 location
+        p = process.env.HOMEDRIVE + process.env.HOMEPATH + "\\AppData\\Local\\Research In Motion\\" + file;
+        if (fs.existsSync(p)) {
+            return p;
+        }
+    } else if (os.type().toLowerCase().indexOf("darwin") >= 0) {
+        // Try Mac OS location
+        p = process.env.HOME + "/Library/Research In Motion/" + file;
+        if (fs.existsSync(p)) {
+            return p;
+        }
+    } else if (os.type().toLowerCase().indexOf("linux") >= 0) {
+        // Try Linux location
+        p = process.env.HOME + "/.rim/" + file;
+        if (fs.existsSync(p)) {
+            return p;
+        }
+    }
+}
+
+function execSigner(session, target, callback) {
+    var script = "blackberry-signer",
+        cwd = path.normalize(conf.DEPENDENCIES_TOOLS + "/bin/"),
+        signer,
+        params = session.getParams("blackberry-signer"),
+        args = [];
+
+    if (pkgrUtils.isWindows()) {
+        script += ".bat";
+    } else {
+        // add path to executable to work around issue with node
+        script = cwd + script;
+    }
+
+    args.push("-keystore");
+    args.push(session.keystore);
+    args.push("-storepass");
+    args.push(session.storepass);
+
+    if (params) {
+        Object.getOwnPropertyNames(params).forEach(function (p) {
+            args.push(p);
+
+            if (params[p]) {
+                args.push(params[p]);
+            }
+        });
+    }
+
+    args.push(path.resolve(util.format(session.barPath, target)));
+
+    signer = childProcess.spawn(script, args, {
+        "cwd": cwd,
+        "env": process.env
+    });
+
+    signer.stdout.on("data", pkgrUtils.handleProcessOutput);
+
+    signer.stderr.on("data", pkgrUtils.handleProcessOutput);
+
+    signer.on("exit", function (code) {
+        if (callback && typeof callback === "function") {
+            callback(code);
+        }
+    });
+}
+
+_self = {
+    getKeyStorePath : function () {
+        // Todo: decide where to put sigtool.p12 which is genereated and used in WebWorks SDK for Tablet OS
+        return getDefaultPath(AUTHOR_P12);
+    },
+
+    getCskPath : function () {
+        return getDefaultPath(CSK);
+    },
+
+    getDbPath : function () {
+        return getDefaultPath(DB);
+    },
+
+    execSigner: execSigner
+};
+
+module.exports = _self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/target
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/target b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/target
new file mode 100644
index 0000000..61211d3
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/lib/target
@@ -0,0 +1,187 @@
+#!/usr/bin/env node
+/*
+ *  Copyright 2013 Research In Motion Limited.
+ *
+ * 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.
+ */
+
+var propertiesFile = 'project.json',
+    properties = require('../../' + propertiesFile),
+    fs = require('fs'),
+    commander = require('commander'),
+    command,
+    name,
+    ip,
+    type,
+    password,
+    pin,
+    pinRegex = new RegExp("[0-9A-Fa-f]{8}");
+
+function writeProjectFile(contents, file) {
+    fs.writeFile(file, contents, 'utf-8', function (err) {
+        if (err) console.log("Error updating project.json :(\n" + err);
+        process.exit();
+    });
+}
+
+function isValidIp(ip) {
+    var num,
+        result = true,
+        ipArray;
+
+    if (typeof ip !== 'string') {
+        throw "IP is required";
+    } else {
+        ipArray = ip.split('.');
+        if (ipArray.length !== 4) {
+            result = false;
+        }
+        ipArray.forEach(function (quadrant) {
+            num = Number(quadrant);
+            if (isNaN(num) || (num < 0) || (num > 255)) {
+                result = false;
+            }
+        });
+    }
+    return result;
+}
+
+function isValidType(type) {
+    var result = true;
+
+    if (typeof type !== 'string') {
+        throw "target type is required";
+    }
+    else if (!(type === 'device' || type === 'simulator')) {
+        result = false;
+    }
+    return result;
+}
+
+function isValidPin(pin) {
+    var result = true;
+    if (typeof pin !== 'undefined' && !pinRegex.test(pin)) {
+        result = false;
+    }
+    return result;
+}
+
+commander
+    .usage('[command] [params]')
+    .option('-p, --password <password>', 'Specifies password for this target')
+    .option('--pin <devicepin>', 'Specifies PIN for this device');
+
+commander
+    .on('--help', function () {
+        console.log('   Synopsis:');
+        console.log('   $ target');
+        console.log('   $ target add <name> <ip> <type> [-p | --password <password>] [--pin <devicepin>]');
+        console.log('   $ target remove <name>');
+        console.log('   $ target default [name]');
+        console.log(' ');
+    });
+
+commander
+    .command('add')
+    .description("Add specified target")
+    .action(function () {
+        if (commander.args.length === 1) {
+            throw "Target details not specified";
+        }
+        name = commander.args[0];
+        ip = commander.args[1];
+        type = commander.args[2];
+        if (commander.password && typeof commander.password === 'string') {
+            password = commander.password;
+        }
+        if (commander.pin && typeof commander.pin === 'string') {
+            pin = commander.pin;
+        }
+        if (!isValidIp(ip)) {
+            throw "Invalid IP: " + ip;
+        }
+        if (!isValidType(type)) {
+            throw "Invalid target type: " + type;
+        }
+        if (!isValidPin(pin)) {
+            throw "Invalid PIN: " + pin;
+        }
+        if (properties.targets.hasOwnProperty(name)) {
+            console.log("Overwriting target: " + name);
+        }
+        properties.targets[name] = {"ip": ip, "type": type, "password": password, "pin": pin};
+    });
+
+commander
+    .command('remove')
+    .description("Remove specified target")
+    .action(function () {
+        if (commander.args.length === 1) {
+            throw 'No target specified';
+        }
+        name = commander.args[0];
+        if (!properties.targets.hasOwnProperty(name)) {
+            throw "Target: '" + name + "' not found";
+        }
+        if (name === properties.defaultTarget) {
+            console.log("Deleting default target, please set a new default target");
+            properties.defaultTarget = "";
+        }
+        delete properties.targets[name];
+    });
+
+commander
+    .command('default')
+    .description("Get or set default target")
+    .action(function () {
+        if (commander.args.length === 1) {
+            console.log(properties.defaultTarget);
+            process.exit();
+        }
+        name = commander.args[0];
+        if (properties.targets.hasOwnProperty(name)) {
+            properties.defaultTarget = name;
+        } else {
+            throw "Target '" + name + "' not found";
+        }
+    });
+
+commander
+    .command('*')
+    .action(function () {
+        throw 'Unrecognized command';
+    });
+
+
+try {
+    commander.parse(process.argv);
+
+    if (commander.args.length === 0) {
+        Object.keys(properties.targets).forEach(function (target) {
+            if (target === properties.defaultTarget) {
+                console.log('* ' + target);
+            } else {
+                console.log('  ' + target);
+            }
+        });
+        process.exit();
+    }
+    if (Object.keys(properties.targets).length === 1) {
+        properties.defaultTarget = Object.keys(properties.targets)[0];
+    }
+
+    writeProjectFile(JSON.stringify(properties, null, 4) + "\n", propertiesFile);
+} catch (e) {
+    console.log(e);
+    process.exit();
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin
new file mode 100755
index 0000000..fb7c467
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd $( dirname "$0")/../
+
+if [ "$1" = "add" ]
+    then
+        ./cordova/node_modules/plugman/plugman.js  --platform blackberry10 --project . --plugin $2
+fi

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin.bat b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin.bat
new file mode 100755
index 0000000..5406de4
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/plugin.bat
@@ -0,0 +1,7 @@
+@ECHO OFF
+
+cd %~dp0..\
+
+if "%1" == "add" (
+    @node.exe ./cordova/node_modules/plugman/plugman.js --platform blackberry10 --project . --plugin %2
+)

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run
new file mode 100755
index 0000000..6e089f9
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run
@@ -0,0 +1,4 @@
+#cd into project dir
+cd $( dirname "$0")/../
+
+node ./cordova/lib/run "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run.bat b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run.bat
new file mode 100755
index 0000000..64e6186
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/run.bat
@@ -0,0 +1,6 @@
+@ECHO OFF
+
+REM cd into project dir
+cd %~dp0\..\
+
+@node.exe ./cordova/lib/run %*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target
new file mode 100755
index 0000000..624f835
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target
@@ -0,0 +1,5 @@
+#!/bin/sh
+# go to project root
+cd $( dirname "$0")/../
+
+node "cordova/lib/target" "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target.bat b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target.bat
new file mode 100755
index 0000000..d9324c7
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/target.bat
@@ -0,0 +1,24 @@
+@ECHO OFF
+goto comment
+       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.
+:comment
+
+REM cd into project dir
+cd %~dp0\..\
+
+@node.exe ./cordova/lib/target %*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/data2xml/data2xml.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/data2xml/data2xml.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/data2xml/data2xml.js
new file mode 100644
index 0000000..8223d12
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/data2xml/data2xml.js
@@ -0,0 +1,86 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// data2xml.js - A data to XML converter with a nice interface (for NodeJS).
+//
+// Copyright (c) 2011 AppsAttic Ltd - http://www.appsattic.com/
+// Written by Andrew Chilton <ch...@appsattic.com>
+//
+// License: http://opensource.org/licenses/MIT
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+var xmlHeader = '<?xml version="1.0" encoding="utf-8"?>\n';
+
+function entitify(str) {
+    str = '' + str;
+    str = str
+        .replace(/&/g, '&amp;')
+        .replace(/</g,'&lt;')
+        .replace(/>/g,'&gt;')
+        .replace(/'/g, '&apos;')
+        .replace(/"/g, '&quot;');
+    return str;
+}
+
+function makeStartTag(name, attr) {
+    attr = attr || {};
+    var tag = '<' + name;
+    for(var a in attr) {
+        tag += ' ' + a + '="' + entitify(attr[a]) + '"';
+    }
+    tag += '>';
+    return tag;
+}
+
+function makeEndTag(name) {
+    return '</' + name + '>';
+}
+
+function makeElement(name, data) {
+    var element = '';
+    if ( Array.isArray(data) ) {
+        data.forEach(function(v) {
+            element += makeElement(name, v);
+        });
+        return element;
+    }
+    else if ( typeof data === 'object' ) {
+        element += makeStartTag(name, data._attr);
+        if ( data._value ) {
+            element += entitify(data._value);
+        }
+/************** MODIFICATION [always execute else condition] ***************/
+        for (var el in data) {
+            /**************** MODIFICATION {if condition altered} **********************/
+            if ( el === '_attr'  || el === '_value') {
+                continue;
+            }
+            element += makeElement(el, data[el]);
+        }
+        element += makeEndTag(name);
+        return element;
+/***************************** END MODIFICATION ***************************/
+    }
+    else {
+        // a piece of data on it's own can't have attributes
+        return makeStartTag(name) + entitify(data) + makeEndTag(name);
+    }
+    throw "Unknown data " + data;
+}
+
+var data2xml = function(name, data) {
+    var xml = xmlHeader;
+    xml += makeElement(name, data);
+    return xml;
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+data2xml.entitify = entitify;
+data2xml.makeStartTag = makeStartTag;
+data2xml.makeEndTag = makeEndTag;
+data2xml.makeElement = makeElement;
+
+module.exports = data2xml;
+
+// --------------------------------------------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/wrench/wrench.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/wrench/wrench.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/wrench/wrench.js
new file mode 100644
index 0000000..8c3d746
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/cordova/third_party/wrench/wrench.js
@@ -0,0 +1,78 @@
+/*  wrench.js
+ *
+ *  A collection of various utility functions I've found myself in need of
+ *  for use with Node.js (http://nodejs.org/). This includes things like:
+ *
+ *  - Recursively deleting directories in Node.js (Sync, not Async)
+ *  - Recursively copying directories in Node.js (Sync, not Async)
+ *  - Recursively chmoding a directory structure from Node.js (Sync, not Async)
+ *  - Other things that I'll add here as time goes on. Shhhh...
+ *
+ *  ~ Ryan McGrath (ryan [at] venodesigns.net)
+ */
+
+/* This file is originally licensed under https://raw.github.com/ryanmcgrath/wrench-js/master/LICENSE
+ * This code has been copied from https://raw.github.com/ryanmcgrath/wrench-js and modified
+ * add the functionality for a callback to the copyDirSyncRecursive method.
+ * Modifications have been clearly marked.
+ * The callback acts like a filter and you must return true/false from it to include/exclude a file
+ */
+
+var wrench = require('wrench'),
+    fs = require("fs"),
+    _path = require("path");
+/*  wrench.copyDirSyncRecursive("directory_to_copy", "new_directory_location", opts);
+ *
+ *  Recursively dives through a directory and moves all its files to a new location. This is a
+ *  Synchronous function, which blocks things until it's done. If you need/want to do this in
+ *  an Asynchronous manner, look at wrench.copyDirRecursively() below.
+ *
+ *  Note: Directories should be passed to this function without a trailing slash.
+ */
+wrench.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts, callback) {
+
+    /**************************Modification*****************************************/
+    if (typeof opts === "function") {
+        callback = opts;
+        opts = {};
+    }
+    /**************************Modification End*****************************************/
+
+    if (!opts || !opts.preserve) {
+        try {
+            if(fs.statSync(newDirLocation).isDirectory()) wrench.rmdirSyncRecursive(newDirLocation);
+        } catch(e) { }
+    }
+
+    /*  Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */
+    var checkDir = fs.statSync(sourceDir);
+    try {
+        fs.mkdirSync(newDirLocation, checkDir.mode);
+    } catch (e) {
+        //if the directory already exists, that's okay
+        if (e.code !== 'EEXIST') throw e;
+    }
+
+    var files = fs.readdirSync(sourceDir);
+
+    for(var i = 0; i < files.length; i++) {
+        var currFile = fs.lstatSync(sourceDir + "/" + files[i]);
+        /**************************Modified to add if statement*****************************************/
+        if (callback && !callback(sourceDir + "/" + files[i], currFile)) {
+            continue;
+        }
+        if(currFile.isDirectory()) {
+            /*  recursion this thing right on back. */
+            wrench.copyDirSyncRecursive(sourceDir + "/" + files[i], newDirLocation + "/" + files[i], opts, callback);
+        } else if(currFile.isSymbolicLink()) {
+            var symlinkFull = fs.readlinkSync(sourceDir + "/" + files[i]);
+            fs.symlinkSync(symlinkFull, newDirLocation + "/" + files[i]);
+        } else {
+            /*  At this point, we've hit a file actually worth copying... so copy it on over. */
+            var contents = fs.readFileSync(sourceDir + "/" + files[i]);
+            fs.writeFileSync(newDirLocation + "/" + files[i], contents);
+        }
+    }
+};
+
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Accelerometer/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Accelerometer/index.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Accelerometer/index.js
new file mode 100644
index 0000000..47abe42
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Accelerometer/index.js
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+var callback;
+
+module.exports = {
+    start: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        window.removeEventListener("devicemotion", callback);
+        callback = function (motion) {
+            var info = {
+                x: motion.accelerationIncludingGravity.x,
+                y: motion.accelerationIncludingGravity.y,
+                z: motion.accelerationIncludingGravity.z,
+                timestamp: motion.timestamp
+            };
+            result.callbackOk(info, true);
+        };
+        window.addEventListener("devicemotion", callback);
+        result.noResult(true);
+    },
+    stop: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        window.removeEventListener("devicemotion", callback);
+        result.ok("removed");
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Battery/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Battery/index.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Battery/index.js
new file mode 100644
index 0000000..fcac7b2
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Battery/index.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * 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.
+ */
+
+var SYSTEM_EVENTS = ["device.battery.statusChange",
+                     "device.battery.chargeLow",
+                     "device.battery.chargeCritical"],
+    clientListener;
+
+module.exports = {
+    start: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        if (!!clientListener) {
+            result.error("Battery listener already running");
+        } else {
+            clientListener = function (info) {
+                result.callbackOk(info, true);
+            };
+            SYSTEM_EVENTS.forEach(function (event) {
+                window.qnx.webplatform.device.addEventListener(event, clientListener);
+            });
+            result.noResult(true);
+        }
+    },
+    stop: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        if (!clientListener) {
+            result.error("Battery listener has not started");
+        } else {
+            SYSTEM_EVENTS.forEach(function (event) {
+                window.qnx.webplatform.device.removeEventListener(event, clientListener);
+            });
+            clientListener = null;
+            result.noResult(false);
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Camera/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Camera/index.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Camera/index.js
new file mode 100644
index 0000000..922f049
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Camera/index.js
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * 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.
+ */
+var PictureSourceType = {
+        PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+        CAMERA : 1,          // Take picture from camera
+        SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
+    },
+    DestinationType = {
+        DATA_URL: 0,         // Return base64 encoded string
+        FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
+        NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
+    };
+
+function encodeBase64(filePath, callback) {
+    var sandbox = window.qnx.webplatform.getController().setFileSystemSandbox, // save original sandbox value
+        errorHandler = function (err) {
+            var msg = "An error occured: ";
+
+            switch (err.code) {
+            case FileError.NOT_FOUND_ERR:
+                msg += "File or directory not found";
+                break;
+
+            case FileError.NOT_READABLE_ERR:
+                msg += "File or directory not readable";
+                break;
+
+            case FileError.PATH_EXISTS_ERR:
+                msg += "File or directory already exists";
+                break;
+
+            case FileError.TYPE_MISMATCH_ERR:
+                msg += "Invalid file type";
+                break;
+
+            default:
+                msg += "Unknown Error";
+                break;
+            };
+
+            // set it back to original value
+            window.qnx.webplatform.getController().setFileSystemSandbox = sandbox;
+            callback(msg);
+        },
+        gotFile = function (fileEntry) {
+            fileEntry.file(function (file) {
+                var reader = new FileReader();
+
+                reader.onloadend = function (e) {
+                    // set it back to original value
+                    window.qnx.webplatform.getController().setFileSystemSandbox = sandbox;
+                    callback(this.result);
+                };
+
+                reader.readAsDataURL(file);
+            }, errorHandler);
+        },
+        onInitFs = function (fs) {
+            window.qnx.webplatform.getController().setFileSystemSandbox = false;
+            fs.root.getFile(filePath, {create: false}, gotFile, errorHandler);
+        };
+
+    window.webkitRequestFileSystem(window.TEMPORARY, 10 * 1024 * 1024, onInitFs, errorHandler); // set size to 10MB max
+}
+
+module.exports = {
+    takePicture: function (success, fail, args, env) {
+        var destinationType = JSON.parse(decodeURIComponent(args[1])),
+            sourceType = JSON.parse(decodeURIComponent(args[2])),
+            result = new PluginResult(args, env),
+            done = function (data) {
+                if (destinationType === DestinationType.FILE_URI) {
+                    data = "file://" + data;
+                    result.callbackOk(data, false);
+                } else {
+                    encodeBase64(data, function (data) {
+                        if (/^data:/.test(data)) {
+                            data = data.slice(data.indexOf(",") + 1);
+                            result.callbackOk(data, false);
+                        } else {
+                            result.callbackError(data, false);
+                        }
+                    });
+                }
+            },
+            cancel = function (reason) {
+                result.callbackError(reason, false);
+            },
+            invoked = function (error) {
+                if (error) {
+                    result.callbackError(error, false);
+                }
+            };
+
+        switch(sourceType) {
+        case PictureSourceType.CAMERA:
+            window.qnx.webplatform.getApplication().cards.camera.open("photo", done, cancel, invoked);
+            break;
+
+        case PictureSourceType.PHOTOLIBRARY:
+        case PictureSourceType.SAVEDPHOTOALBUM:
+            window.qnx.webplatform.getApplication().cards.filePicker.open({
+                mode: "Picker",
+                type: ["picture"]
+            }, done, cancel, invoked);
+            break;
+        }
+
+        result.noResult(true);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Device/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Device/index.js b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Device/index.js
new file mode 100644
index 0000000..f4849f5
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/Device/index.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * 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.
+ */
+
+function getModelName () {
+    var modelName = window.qnx.webplatform.device.modelName;
+    //Pre 10.2 (meaning Z10 or Q10)
+    if (typeof modelName === "undefined") {
+        if (window.screen.height === 720 && window.screen.width === 720) {
+            modelName = "Q10";
+        } else if ((window.screen.height === 1280 && window.screen.width === 768) ||
+                   (window.screen.height === 768 && window.screen.width === 1280)) {
+            modelName = "Z10";
+        } else {
+            modelName = window.qnx.webplatform.deviceName;
+        }
+    }
+
+    return modelName;
+}
+
+function getUUID () {
+    var uuid = "";
+    try {
+        //Must surround by try catch because this will throw if the app is missing permissions
+        uuid = window.qnx.webplatform.device.devicePin;
+    } catch (e) {
+        //DO Nothing
+    }
+    return uuid;
+}
+
+module.exports = {
+    getDeviceInfo: function (success, fail, args, env) {
+        var result = new PluginResult(args, env),
+            modelName = getModelName(),
+            uuid = getUUID(),
+            info = {
+                platform: "blackberry10",
+                version: window.qnx.webplatform.device.scmBundle,
+                model: modelName,
+                name: modelName, // deprecated: please use device.model
+                uuid: uuid,
+                cordova: "2.5.0"
+            };
+        result.ok(info);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
new file mode 100644
index 0000000..0cc5eae
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
@@ -0,0 +1,8 @@
+LIST=CPU
+ifndef QRECURSE
+QRECURSE=recurse.mk
+ifdef QCONFIG
+QRDIR=$(dir $(QCONFIG))
+endif
+endif
+include $(QRDIR)$(QRECURSE)

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
new file mode 100644
index 0000000..6cecca9
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
@@ -0,0 +1,34 @@
+ifndef QCONFIG
+QCONFIG=qconfig.mk
+endif
+include $(QCONFIG)
+
+NAME=jpps
+PLUGIN=yes
+UTILS=yes
+
+include ../../../../../../meta.mk
+
+override CCFLAGS := $(filter-out -Werror , $(CCFLAGS))
+
+EXTRA_SRCVPATH+=$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/utils \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/core \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/plugin
+
+EXTRA_INCVPATH+=$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/utils \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/core \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/plugin
+
+SRCS+=src/utils/Thread.cpp \
+      src/core/PPSInterface.cpp \
+      src/core/PPSNotifier.cpp \
+      src/core/PPSNotifyGroupManager.cpp \
+      src/plugin/JPPSPlugin.cpp \
+      src/plugin/PPSInterfaceGlue.cpp \
+      src/plugin/JPPSServerPlugin.cpp \
+      src/plugin/PPSServerGlue.cpp \
+      src/plugin/pluginManifest.cpp
+
+include $(MKFILES_ROOT)/qtargets.mk
+
+LIBS+=pps

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so
new file mode 100644
index 0000000..f0eb90d
Binary files /dev/null and b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so
new file mode 100644
index 0000000..f2c12ff
Binary files /dev/null and b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
new file mode 100644
index 0000000..808e699
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPSEVENT_H_
+#define PPSEVENT_H_
+
+#include <string>
+#include "PPSTypes.h"
+
+namespace jpps {
+
+/**
+ * A class representing a PPS event. Used to notify interested parties when something
+ * happens to a PPS object.
+ */
+class PPSEvent {
+
+public:
+
+	/**
+	 * The possible types of this event.
+	 */
+	enum PPSEventType {
+		/** The PPS object's first data read is complete. */
+		PPS_EVENT_FIRST_READ_COMPLETE,
+		/** The PPS object has new data. */
+		PPS_EVENT_NEW_DATA,
+		/** The PPS object was successfully opened. */
+		PPS_EVENT_OPENED,
+		/** A PPS object was closed. */
+		PPS_EVENT_CLOSED,
+		/** An attempt to open a PPS object failed. */
+		PPS_EVENT_OPEN_FAILED,
+		/** An attempt to read from a PPS object failed. */
+		PPS_EVENT_READ_FAILED,
+		/** An attempt to write to a PPS object failed. */
+		PPS_EVENT_WRITE_FAILED,
+	};
+
+	/**
+	 * Constructor.
+	 *
+	 * @param eventType The type of event this is.
+	 * @param data If eventType == PPS_EVENT_NEW_DATA, the new data.
+	 */
+	PPSEvent(PPSEventType eventType, const std::string& msg = "", const ppsObject& newData = ppsObject())
+	: m_eventType(eventType)
+	, m_message(msg)
+	, m_newData(newData)
+	{}
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~PPSEvent() {}
+
+	/**
+	 * Get the event type.
+	 */
+	inline PPSEventType getEventType() const { return m_eventType; }
+
+	/**
+	 * Get the message associated with this event.
+	 */
+	inline std::string getMessage() const { return m_message; }
+
+	/**
+	 * Get the new data. This value is only populated if the eventType is PPS_EVENT_NEW_DATA. This data
+	 * is what was parsed out of the PPS object.
+	 */
+	inline ppsObject getNewData() const { return m_newData; }
+
+private:
+
+	// Disable the default constructor.
+	PPSEvent();
+
+	/** The type of this event. */
+	PPSEventType m_eventType;
+
+	/** A message associated to the event. */
+	std::string m_message;
+
+	/** If m_eventType == PPS_EVENT_NEW_DATA, this contains the new data. Else m_newData is empty.
+	 * This data is the data that was read from the PPS object, un-massaged. */
+	ppsObject m_newData;
+};
+
+} /* namespace jpps */
+#endif /* PPSEVENT_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
new file mode 100644
index 0000000..dfb575b
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "PPSInterface.h"
+
+#include <sstream>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <ppsparse.h>
+#include <string.h>
+
+#include "PPSNotifyGroupManager.h"
+#include "PPSEvent.h"
+
+namespace jpps {
+
+// Const statics
+const char* PPSInterface::PPS_ROOT = "/pps/";
+const int PPSInterface::MaxPPSReadSize = (32 * 1024);
+
+// Static data members
+pthread_mutex_t PPSInterface::sm_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t PPSInterface::sm_cond;
+volatile bool PPSInterface::sm_firstInitDone = false;
+std::map<unsigned int, PPSInterface*> PPSInterface::sm_interfaceLookupTable;
+
+PPSInterface::PPSInterface()
+: m_pEventFunc(NULL)
+, m_pEventArg(NULL)
+, m_interfaceId(0)
+, m_fd(-1)
+, m_oflags(0)
+, m_firstRead(true)
+, m_cachedRead()
+, m_logger()
+{
+	// This is used to assign a unique ID to each PPSInterface object
+	static unsigned int interfaceIDs = 0;
+
+	::pthread_mutex_lock(&sm_mutex);
+
+	m_interfaceId = interfaceIDs;
+	interfaceIDs++; // Increment this so that the next object has a unique id.
+
+	// Add myself to the lookup table
+	sm_interfaceLookupTable.insert(std::pair<unsigned int, PPSInterface*>(m_interfaceId, this));
+
+	if (!sm_firstInitDone) {
+
+		// Initialize the condvar
+		pthread_condattr_t condAttr;
+		::pthread_condattr_init(&condAttr);
+		::pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
+		::pthread_cond_init(&sm_cond, &condAttr);
+		::pthread_condattr_destroy(&condAttr);
+
+		sm_firstInitDone = true;
+	}
+
+	::pthread_mutex_unlock(&sm_mutex);
+}
+
+PPSInterface::~PPSInterface()
+{
+	std::ostringstream ostream;
+	ostream << "PPSInterface::~PPSInterface() - Destruct fd:" << m_fd << ".";
+	m_logger.slog(Logger::debug, ostream.str());
+
+	// Close my open PPS object, if I have one
+	close();
+
+	// Remove myself from the lookup table
+	sm_interfaceLookupTable.erase(m_interfaceId);
+}
+
+void PPSInterface::setVerbose(unsigned short v)
+{
+	m_logger.setVerbosity(v);
+}
+
+void PPSInterface::setEventFunc(const PPSEventFunc* pEventFunc, void* pArg)
+{
+	m_pEventFunc = pEventFunc;
+	m_pEventArg = pArg;
+}
+
+bool PPSInterface::open(const std::string& path, int oflag, int mode, bool server)
+{
+	// If we've already got an open file, fail
+	if (m_fd != -1) {
+
+		m_logger.slog(Logger::warning, "PPSInterface::open() Failed - Attempted to open an object that is already open.");
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_OPEN_FAILED, "Attempted to open an object that is already open."));
+		return false;
+	}
+
+	std::string errorMsg;
+	bool ok = false;
+
+	// Prepend PPS_ROOT to the path if it doesn't start with a '/'
+	std::string fullpath = (path[0] != '/' ? PPSInterface::PPS_ROOT : "") + path;
+
+	// This flag is used to prevent the notify thread from performing reads while the
+	// open() function is running and doing its first read.
+	::pthread_mutex_lock(&sm_mutex);
+	m_firstRead = true;
+	::pthread_mutex_unlock(&sm_mutex);
+
+	// Remove any options from the path otherwise lstat will fail
+	std::string pathNoOptions(fullpath);
+	std::size_t nPosOpts = fullpath.rfind('?');
+
+	if (nPosOpts != std::string::npos)
+		pathNoOptions = fullpath.substr(0, nPosOpts);
+
+	// There are a few complexities associated with symbolic links.  If
+	// the last component of the path is a symlink we have to resolve it
+	// since we won't be able to resolve the name when the options are
+	// added.  Also we need to get the path relative to the pps filesystem
+	// so we can locate the .notify file.  So, if the object already
+	// exists, resolve the path.  If it doesn't and O_CREAT is specified
+	// resolve the directory it's in, otherwise it's a failure.
+	std::string resolvedName;
+	char szResolvedName[PATH_MAX+128]; // buffer for use with the C functions
+
+	if (::realpath(pathNoOptions.c_str(), szResolvedName) != NULL) {
+
+		resolvedName = szResolvedName;
+		ok = true;
+	}
+	else if (oflag & O_CREAT) {
+
+		// Chop off the file name, so we can try to resolve the directory
+		size_t nPos = pathNoOptions.rfind('/');
+
+		// We found a '/'
+		if (nPos != std::string::npos) {
+
+			// Get the directory path
+			std::string dirPath = pathNoOptions.substr(0, nPos); // Don't include the '/'
+
+			if (::realpath(dirPath.c_str(), szResolvedName) != NULL) {
+
+				// Concatenate the file name to the resolved directory path
+				resolvedName = szResolvedName + pathNoOptions.substr(nPos); // include the '/' at the start
+				ok = true;
+			}
+		}
+	}
+
+	if (ok) {
+
+		struct stat info;
+		int result = ::lstat(resolvedName.c_str(), &info);
+
+		if (result != 0) {
+
+			// If we failed and we're not creating a non-existent file, it's an error.
+			if ((errno != ENOENT) && !(oflag & O_CREAT))
+				ok = false;
+		}
+		else if (S_ISDIR(info.st_mode))
+			ok = false;
+	}
+
+	if (ok) {
+
+		std::string options;
+
+		// Now lets work with the options to ensure we have a complete version
+		std::string pathOptions;
+		
+		// Get just the stuff after '?'
+		size_t nPos = fullpath.rfind('?');
+
+		if (nPos != std::string::npos) {
+			pathOptions = fullpath.substr(nPos);
+		}
+
+		if ((oflag & O_ACCMODE) != O_WRONLY) {
+
+			// This is used as the return object for the joinNotifyGroup() call
+			// It's only valid if joinNotifyGroup() returned true
+			std::string groupId;
+
+			PPSNotifyGroupManager::mutexLock();
+			PPSNotifyGroupManager& notifyManager = PPSNotifyGroupManager::getInstance();
+			bool groupJoined = notifyManager.joinNotifyGroup(resolvedName, groupId);
+			PPSNotifyGroupManager::mutexUnlock();
+
+			if (groupJoined) {
+
+				// If we're acting as a server, we use server as an option
+				// otherwise we have to specify delta mode.  PPS has a fit
+				// if we specify both delta and deltadir so check for this.
+				std::string modeExtra;
+
+				// Add in the options we need.  If both server and delta are specified, use only
+				// server (it kind of implies delta and at one point pps would not like both being
+				// present)
+				if (server) {
+					modeExtra = ",server";
+				}
+				// If we have no options or there's no 'deltadir' specified, use delta mode
+				else if (pathOptions.empty() || pathOptions.find("deltadir") == std::string::npos) {
+					modeExtra = ",delta";
+				}
+
+				// We embed the m_interfaceID as a unique identifier that will be passed on to the
+				// PPSNotifier. PPSNotifier will use this id in conjunction with getPPSInterface()
+				// in order to send this object notifications that content is ready for reading later.
+				std::ostringstream ostream;
+				ostream << "?" << (pathOptions.empty() ? "" : pathOptions.substr(1) + ",") << "notify="
+						<< groupId << ":" << m_interfaceId << modeExtra;
+				options = ostream.str();
+			}
+		}
+
+		if (!options.empty()) {
+
+			resolvedName += options;
+		}
+
+		// The big moment... Let's try to actually open the PPS object...
+		if (ok) {
+			m_fd = ::open(resolvedName.c_str(), oflag, mode);
+		}
+
+		// Error opening the PPS object
+		if (m_fd < 0) {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::open() Failed - ::open("
+					<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+					   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+					   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+					<< ((oflag & O_CREAT) ? ":create" : "")
+					<< ") " << resolvedName << " (" << errno << ": " << strerror(errno) << ")";
+			m_logger.slog(Logger::warning, ostream.str());
+			errorMsg = ostream.str();
+		}
+		else {
+			// Depending on our umask, the permissions might not have
+			// been as specified. So if O_CREAT was specified, re-set the
+			// permissions.  The object might already exist, but perhaps
+			// that's OK too.
+			if (oflag & O_CREAT) {
+				::fchmod(m_fd, mode);
+			}
+
+			m_oflags = oflag;
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::open() - ::open("
+					<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+					   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+					   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+					<< ((oflag & O_CREAT) ? ":create" : "")
+					<< ") " << resolvedName;
+			m_logger.slog(Logger::debug, ostream.str());
+		}
+	}
+	// For whatever reason, the path to the PPS object was not valid
+	else {
+		std::ostringstream ostream;
+		ostream << "PPSInterface::open() Failed - ::open("
+				<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+				   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+				   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+				<< ((oflag & O_CREAT) ? ":create" : "")
+				<< ") " << path << " The PPS object could not be resolved properly.";
+		m_logger.slog(Logger::warning, ostream.str());
+		errorMsg = ostream.str();
+	}
+
+	sendEvent(PPSEvent(m_fd >= 0 ? PPSEvent::PPS_EVENT_OPENED : PPSEvent::PPS_EVENT_OPEN_FAILED, errorMsg));
+
+	if (m_fd >= 0 && (oflag & O_ACCMODE) != O_WRONLY) {
+
+		// Perform the initial read
+		readFromObject();
+	}
+
+	// Tell the other thread we are done with the first read
+	::pthread_mutex_lock(&sm_mutex);
+	m_firstRead = false;
+	::pthread_cond_broadcast(&sm_cond);
+	::pthread_mutex_unlock(&sm_mutex);
+
+	return m_fd >= 0;
+}
+
+void PPSInterface::write(const std::string& data)
+{
+	// We're trying to write to an unopened PPS object
+	if (m_fd == -1) {
+
+		std::string msg("PPSInterface::write() Failed - Attempting to write to a file that isn't open.");
+		m_logger.slog(Logger::warning, msg);
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_WRITE_FAILED, msg));
+	}
+
+	ssize_t ret = ::write(m_fd, data.c_str(), data.length());
+
+	// Debug slog the write call if it was successful
+	if (ret >= 0) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::write() - fd:" << m_fd << " : \n" << data;
+		m_logger.slog(Logger::debug, ostream.str());
+	}
+
+	// There was an error writing
+	if (ret == -1) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::write() Failed - Error writing to fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+		m_logger.slog(Logger::warning, ostream.str());
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_WRITE_FAILED, ostream.str()));
+	}
+
+	// If we wrote successfully and the file is open in read/write mode, then we need to manually update the
+	// read cache. When in O_RDWR mode, we do NOT receive notifications of our own write() operations.
+	// This means that the cache of read data becomes stale - it is missing the data that we have written
+	// to the object ourselves. In this case, we will manually update the cache.
+	// NOTE: this seems fraught with peril, but unfortunately there don't seem to be any good solutions to
+	// fixing the problem of read/write mode and read() integrity.
+	if (ret >= 0 && (m_oflags & O_RDWR)) {
+
+		// We're going to try to fool the ppsparse() method into parsing the data we write.
+		char* pWriteData = new char[data.length() + 1];
+
+		// The later call to ppsparse() moves the pWriteData pointer forward, and we need the original pointer
+		// in order to properly delete the object later, so let's cache it here
+		char* pWriteDataCopy = pWriteData;
+
+		std::strcpy(pWriteData, data.c_str()); // strcpy null terminates for us
+
+		// Parse the write buffer - this should give us a ppsObject with only attributes
+		ppsObject parsedData = parsePPSData(pWriteData);
+
+		// The data being written does not include the object name other object properties (duh)
+		// So parsedData contains only attribute info. We want to preserve the object name
+		// and properties, so lets just copy the ones in the cache into our parsedData struct
+		// so that the call to updateCachedReadData() will preserve them (i.e. copy them back)
+		parsedData.name = m_cachedRead.name;
+		parsedData.flags = m_cachedRead.flags;
+		parsedData.options = m_cachedRead.options;
+		parsedData.optionMask = m_cachedRead.optionMask;
+
+		// Update the cache
+		updateCachedReadData(parsedData);
+
+		// Cleanup our allocated memory
+		if (pWriteDataCopy) {
+
+			delete[] pWriteDataCopy;
+		}
+	}
+}
+
+void PPSInterface::sync()
+{
+	if (m_fd >= 0)
+		::fsync(m_fd);
+}
+
+void PPSInterface::close()
+{
+	if (m_fd >= 0) {
+
+		::close(m_fd);
+		m_fd = -1;
+		m_cachedRead = ppsObject();
+		m_oflags = 0;
+
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_CLOSED));
+	}
+}
+
+void PPSInterface::onNotify(NotifyType event)
+{
+	// We only handle read notifications
+	if (event != PPS_READ) {
+		return;
+	}
+
+	if (m_firstRead) {
+		::pthread_mutex_lock(&sm_mutex);
+		while (m_firstRead) {
+			::pthread_cond_wait(&sm_cond, &sm_mutex);
+		}
+		::pthread_mutex_unlock(&sm_mutex);
+	}
+
+	readFromObject();
+}
+
+void PPSInterface::readFromObject()
+{
+	bool sendFirstReadEvent = m_firstRead;
+
+	// This was a uint8_t - was there a reason?
+	char szBuffer[MaxPPSReadSize + 1];
+	int bufferLen;
+
+	// Read from the actual PPS file - this call is not blocking
+	while ((bufferLen = ::read(m_fd, szBuffer, MaxPPSReadSize)) > 0) {
+
+		if (bufferLen <= MaxPPSReadSize) {
+
+			// Make sure the buffer is null terminated.
+			szBuffer[bufferLen] = '\0';
+
+			std::string buf(szBuffer, bufferLen);
+			std::ostringstream ostream;
+			ostream << "PPSInterface::readFromObject() - fd:" << m_fd << " len:" << bufferLen << "\n" << buf;
+			m_logger.slog(Logger::debug, ostream.str());
+
+			// Parse the PPS data
+			ppsObject parsedPPS = parsePPSData(szBuffer);
+
+			// Update the cache with the data we just read
+			updateCachedReadData(parsedPPS);
+
+			// If this is the first read, then send the first read event.
+			if (sendFirstReadEvent) {
+
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_FIRST_READ_COMPLETE, "", parsedPPS));
+				sendFirstReadEvent = false;
+			}
+			else {
+
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_NEW_DATA, "", parsedPPS));
+			}
+		}
+		else {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::readFromObject() Failed - fd:" << m_fd << " oversized message len:" << bufferLen << ".";
+			m_logger.slog(Logger::warning, ostream.str());
+		}
+	}
+
+	if (bufferLen == -1) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::readFromObject() Failed - Error reading from fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+		m_logger.slog(Logger::warning, ostream.str());
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, ostream.str()));
+	}
+
+	// It's possible that we won't go into the while() loop above (sometimes the first read is legitimately empty)
+	// in which case, we still need to send a first read complete event
+	if (sendFirstReadEvent) {
+
+		// Send an empty first read object
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_FIRST_READ_COMPLETE, "", ppsObject()));
+		sendFirstReadEvent = false;
+	}
+}
+
+void PPSInterface::sendEvent(const PPSEvent& event) const
+{
+	if (m_pEventFunc) {
+		m_pEventFunc(m_pEventArg, event);
+	}
+}
+
+PPSInterface* const PPSInterface::getPPSInterface(const unsigned int id)
+{
+	::pthread_mutex_lock(&sm_mutex);
+
+	std::map<unsigned int, PPSInterface*>::iterator it = sm_interfaceLookupTable.find(id);
+
+	if (it != sm_interfaceLookupTable.end()) {
+
+		::pthread_mutex_unlock(&sm_mutex);
+		return (*it).second;
+	}
+
+	::pthread_mutex_unlock(&sm_mutex);
+	return NULL;
+}
+
+ppsObject PPSInterface::parsePPSData(char* data) const
+{
+	// This is the structure that will contain parsed data for each line of the PPS object
+	// It needs to be initialized to NULL
+	pps_attrib_t info;
+	std::memset(&info, 0, sizeof(info));
+
+	// The return code for each PPS line that gets parsed
+	pps_status_t rc;
+	ppsObject ppsObj;
+
+	while ((rc = ::ppsparse(&data, NULL, NULL, &info, 0)) != PPS_END) {
+
+		if (rc == -1) {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::parsePPSData() Failed - Error calling ppsparse() fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+			m_logger.slog(Logger::warning, ostream.str());
+			sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, ostream.str()));
+		}
+
+		if (info.flags & PPS_INCOMPLETE) {
+			m_logger.slog(Logger::debug, "PPSInterface::parsePPSData - PPS data incomplete.");
+		}
+
+		switch (rc) {
+
+			// When the object has been modified, update the object settings
+			case PPS_OBJECT:
+			case PPS_OBJECT_CREATED:
+			case PPS_OBJECT_DELETED:
+			case PPS_OBJECT_TRUNCATED:
+			{
+				ppsObj.name = info.obj_name;
+				ppsObj.flags = info.flags;
+				ppsObj.options = info.options;
+				ppsObj.optionMask = info.option_mask;
+				break;
+			}
+
+			// An attribute has been updated
+			case PPS_ATTRIBUTE:
+			case PPS_ATTRIBUTE_DELETED:
+			{
+				ppsAttribute ppsAttrib;
+				ppsAttrib.name = info.attr_name;
+
+				// Value and encoding aren't valid if rc == PPS_ATTRIBUTE_DELETED
+				if (rc == PPS_ATTRIBUTE) {
+
+					ppsAttrib.value = info.value;
+					ppsAttrib.encoding = info.encoding;
+				}
+
+				ppsAttrib.flags = info.flags;
+				ppsAttrib.options = info.options;
+				ppsAttrib.optionMask = info.option_mask;
+
+				ppsObj.attributes.insert(ppsAttrPair(ppsAttrib.name, ppsAttrib));
+				break;
+			}
+
+			case PPS_ERROR:
+			{
+				std::string msg("PPSInterface::parsePPSData() Failed - Error parsing PPS data.");
+				m_logger.slog(Logger::warning, msg);
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, msg));
+				break;
+			}
+
+			case PPS_END:
+			default:
+				break;
+		}
+
+	}
+
+	return ppsObj;
+}
+
+void PPSInterface::updateCachedReadData(const ppsObject& newData)
+{
+	::pthread_mutex_lock(&sm_mutex);
+
+	// Update the object
+	m_cachedRead.name = newData.name;
+	m_cachedRead.flags = newData.flags;
+	m_cachedRead.options = newData.options;
+	m_cachedRead.optionMask = newData.optionMask;
+
+	::pthread_mutex_unlock(&sm_mutex);
+
+	// Update the attributes
+	for (const_ppsAttrIter it = newData.attributes.begin(); it != newData.attributes.end(); it++) {
+
+		ppsAttribute attr = (*it).second;
+
+		// An attribute is being deleted
+		if (attr.flags & PPS_DELETED) {
+
+			::pthread_mutex_lock(&sm_mutex);
+
+			// Look for this attribute in the cache and remove it
+			ppsAttrIter findIt = m_cachedRead.attributes.find(attr.name);
+
+			if (findIt != m_cachedRead.attributes.end()) {
+				m_cachedRead.attributes.erase(findIt);
+			}
+
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+		// We're adding a new attribute - don't search for it
+		else if (attr.flags & PPS_CREATED){
+
+			::pthread_mutex_lock(&sm_mutex);
+			m_cachedRead.attributes.insert(ppsAttrPair(attr.name, attr));
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+		else {
+
+			::pthread_mutex_lock(&sm_mutex);
+
+			// Look for this attribute in the cache
+			ppsAttrIter findIt = m_cachedRead.attributes.find(attr.name);
+
+			// If we find it, update the attribute values
+			if (findIt != m_cachedRead.attributes.end()) {
+
+				(*findIt).second.name = attr.name;
+				(*findIt).second.encoding = attr.encoding;
+				(*findIt).second.value = attr.value;
+				(*findIt).second.flags = attr.flags;
+				(*findIt).second.options = attr.options;
+				(*findIt).second.optionMask = attr.optionMask;
+			}
+			// If we don't find it, insert it
+			else {
+				m_cachedRead.attributes.insert(ppsAttrPair(attr.name, attr));
+			}
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+	}
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
new file mode 100644
index 0000000..0fde80c
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPS_H_
+#define PPS_H_
+
+#include <string>
+#include <map>
+
+#include <sys/types.h>
+
+#include "PPSTypes.h"
+#include "PPSEvent.h"
+#include "../utils/Logger.h"
+
+namespace jpps {
+
+/**
+ * This class augments standard PPS functionality by providing events for when PPS objects are opened,
+ * closed, have new data, etc.
+ *
+ * When a PPS object is opened using PPSInterface::open(), the object is opened as part of a notification group
+ * managed by PPSNotifyGroupManager. The notification group monitors the PPS object and notifies PPSInterface
+ * whenever there is new data available in the PPS object.
+ *
+ * PPSInterface should be used in order to simplify PPS object monitoring (i.e. watching for new data in a PPS
+ * object.) PPSInterface takes over management of watching for new data and uses a notification callback mechanism
+ * with a defined set of possible events to inform the client of changes to the PPS object.
+ */
+class PPSInterface {
+
+public:
+
+	/**
+	 * Used with onNotify to allow the PPSNotifier to tell us what type of notification
+	 * message it is sending.
+	 */
+	enum NotifyType {
+		/** The .notify object received a notification that data is ready to be read. */
+		PPS_READ = 0,
+		/** The .notify object received a notification that a file being watched is closing. */
+		PPS_CLOSE = 1 };
+
+	/**
+	 * Constructor.
+	 */
+	PPSInterface();
+
+	/**
+	 * Destructor.
+	 */
+	~PPSInterface();
+
+	/**
+	 * Set up a function to call to be notified about PPS events.
+	 *
+	 * @param pEventFunc The function to call whenever an event happens in PPSInterface.
+	 * @param pArg An optional parameter that will be passed back to pEventFunc every time it
+	 * is called. PPSInterface will not modify pArg.
+	 */
+	void setEventFunc(const PPSEventFunc* pEventFunc, void* pArg = NULL);
+
+	/**
+	 * Enable verbose mode. Increase the number of �v�s to increase verbosity.
+	 *
+	 * @param v The level of verbosity. A value of 0 is off, 1 shows info messages, 2 shows
+	 * debug messages.
+	 */
+	void setVerbose(unsigned short v);
+
+	/**
+	 * Open a PPS object. If the open() call is successful, a PPS_EVENT_OPENED event will be sent.
+	 * The PPS object will be read as part of the open operation and the PPS_EVENT_FIRST_READ_COMPLETE
+	 * will be sent when the first read is complete. Note that there may be a PPS_EVENT_NEW_DATA
+	 * event *before* the PPS_EVENT_FIRST_READ_COMPLETE event, or there may not be.
+	 * PPS_EVENT_FIRST_READ_COMPLETE only guarantees that at least one read has been performed, not
+	 * that it will be the first read event to fire.
+	 *
+	 * If the open operation fails, the function returns false and a PPS_EVENT_OPEN_FAILED will be sent.
+	 *
+	 * @param path The PPS file/directory path.
+	 * @param oflags Flags passed to ::open.
+	 * @param mode Mode passed to ::open.
+	 * @param serverMode If true, open the object in server mode as the server.
+	 * @return True if the open was successful, false otherwise.
+	 */
+	bool open(const std::string& path, int oflags, int mode, bool serverMode);
+
+	/**
+	 * Check if this PPS object is open.
+	 * @return True if the file is open, false otherwise.
+	 */
+	inline bool isOpen() const { return m_fd >= 0; }
+
+	/**
+	 * Write data to a PPS object.
+	 * @param data The data to write to the PPS object.
+	 */
+	void write(const std::string& data);
+
+	/**
+	 * Read PPS data. Note that this reads cached data from the last read performed when a
+	 * new data available notification was received.
+	 *
+	 * @return A structured representation of the PPS object, culled from a call to ppsparse()
+	 * a function found in ppsparse.h.
+	 */
+
+	inline ppsObject read() const { return m_cachedRead; }
+
+	/**
+	 * Close this PPS object.
+	 */
+	void close();
+
+	/**
+	 * Forces all queued I/O operations for this object to finish, synchronizing the file's state.
+	 * The function blocks until this is finished.
+	 */
+	void sync();
+
+	/**
+	 * Called to notify us that there is data ready to be read.
+	 *
+	 * @param event The type of event we're being notified about.
+	 */
+	void onNotify(NotifyType event);
+
+	/**
+	 * Given a unique id, return the PPSInterface* matching that id.
+	 *
+	 * Every PPSInterface object is assigned a unique identifier at construction. This
+	 * unique identifier can be used to get a pointer to a PPSInterface at runtime.
+	 *
+	 * In particular, the PPSNotifier gets notifications with this number embedded in them.
+	 * Using this id, the PPSNotifier can callback into the correct PPSInterface instance.
+	 *
+	 * @param id An id that uniquely identifies a PPSInterface object.
+	 * @return a PPSInterface* or NULL if no object matches the given id.
+	 */
+	static PPSInterface* const getPPSInterface(const unsigned int id);
+
+private:
+
+	/**
+	 * Read from the PPS object. Generally this function is called by onNotify() when
+	 * the notifier thread is notified that there is data to be read. This function
+	 * performs a read() of the PPS object that is non-blocking.
+	 */
+	void readFromObject();
+
+	/**
+	 * Given data from a PPS read, parse the PPS data.
+	 */
+	ppsObject parsePPSData(char* data) const;
+
+	/**
+	 * Given new PPS data, update the cached read value.
+	 */
+	void updateCachedReadData(const ppsObject& newData);
+
+	/**
+	 * Call the function set in setEventFunc() with the given event.
+	 *
+	 * @param event The event to send.
+	 */
+	void sendEvent(const PPSEvent& event) const;
+
+	/** The default PPS location. */
+	static const char* PPS_ROOT;
+
+	/** The maximum amount of data that can be read from a PPS object. */
+	static const int MaxPPSReadSize;
+
+	/** The function to call to notify about PPS events. */
+	PPSEventFunc* m_pEventFunc;
+
+	/** An argument that goes with m_pEventFunc. PPSInterface does not modify or use
+	 * this parameter - we simply send it back with every m_pEventFunc call. */
+	void* m_pEventArg;
+
+	/** An identifier that uniquely identifies this PPSInterface object. This is used to look up
+	 * this object in a global table. */
+	unsigned int m_interfaceId;
+
+	/** The file descriptor of the PPS object being opened. */
+	int m_fd;
+
+	/** The open mode flags used when this object was opened. */
+	int m_oflags;
+
+	/** If true, main thread is performing initial open/read of PPS object. This is shared
+	 * across threads and needs to be mutexed when accessed.*/
+	volatile bool m_firstRead;
+
+	/** The data from the last read performed. */
+	ppsObject m_cachedRead;
+
+	/** The logger used to log error messages */
+	Logger m_logger;
+
+	/** Mutex used to prevent threads from clobbering each other. */
+	static pthread_mutex_t sm_mutex;
+
+	/** Condvar used for multi-thread signaling. */
+	static pthread_cond_t sm_cond;
+
+	/** Used to ensure that initialization of statics happens only once. This is shared
+	 * across threads and needs to be mutexed when accessed.*/
+	static volatile bool sm_firstInitDone;
+
+	/** The PPSNotifier needs a way to transform an id that uniquely identifies a PPSInterface object
+	 * into an actual PPSInterface*. When we construct a new PPSInterface, we will assign it a unique id
+	 * and we will put the id and the pointer to the object into this table. The table can then be used
+	 * to lookup this object from its unique id. */
+	static std::map<unsigned int, PPSInterface*> sm_interfaceLookupTable;
+};
+
+} /* namespace jpps */
+#endif /* PPS_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
new file mode 100644
index 0000000..7869a56
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "PPSNotifier.h"
+
+#include <sstream>
+
+#include <fcntl.h>
+
+#include "PPSInterface.h"
+#include "../utils/Logger.h"
+
+namespace jpps {
+
+PPSNotifier::PPSNotifier()
+: m_notifyObjPath("")
+, m_notifyObjFd(-1)
+, m_notifyGroupId("")
+, m_thread()
+{
+
+}
+
+PPSNotifier::~PPSNotifier()
+{
+	// Stop the thread
+	m_thread.stop();
+
+	// Close the .notify file
+	if (m_notifyObjFd >= 0) {
+		::close(m_notifyObjFd);
+	}
+}
+
+void PPSNotifier::startNotifyLoop()
+{
+	m_thread.start(_notifyLoop, this, "plugin_jPPS_PPSNotifier(" + m_notifyObjPath + "/.notify)");
+}
+
+
+void* PPSNotifier::_notifyLoop(void* pArg)
+{
+	// Something is messed up
+	if (pArg == NULL)
+		return NULL;
+
+	PPSNotifier* pNotifier = static_cast<PPSNotifier*> (pArg);
+
+	// pArg is supposed to be a PPSNotifier object...
+	if (pNotifier == NULL)
+		return NULL;
+
+	pNotifier->notifyLoop();
+
+	return NULL;
+}
+
+void PPSNotifier::notifyLoop()
+{
+	// Buffer for read() operation
+	char szData[256];
+	int dataLen;
+
+	// This is a blocking read call: this will wait in this loop forever
+	while ((dataLen = ::read(m_notifyObjFd, szData, sizeof(szData)-1)) > 0) {
+
+                szData[dataLen] = '\0';
+		std::string data(szData);
+
+		if ((unsigned int)dataLen > sizeof(szData)-1) {
+
+			std::ostringstream ostream;
+			ostream << "PPSNotifier::notifyLoop() - Notify read overflow " << dataLen << ".";
+			Logger logger;
+			logger.slog(Logger::error, ostream.str());
+		}
+
+		std::size_t nPos = data.find('\n');
+
+		// While we find linefeeds
+		while(nPos != std::string::npos) {
+
+			// Read the first char
+			PPSInterface::NotifyType event = data[0] == '-' ? PPSInterface::PPS_CLOSE : PPSInterface::PPS_READ;
+			std::size_t nAddrPos = data.find(':');
+
+			if (nAddrPos != std::string::npos) {
+
+				std::string sAddress = data.substr(nAddrPos+1);
+				std::size_t nAddrEnd = sAddress.find('\n');
+
+				if (nAddrEnd != std::string::npos) {
+
+					sAddress = sAddress.substr(0, nAddrEnd);
+
+					unsigned int interfaceId = 0;
+
+					std::stringstream ss;
+					ss << sAddress;
+					ss >> interfaceId;
+
+					PPSInterface* const pPPS = PPSInterface::getPPSInterface(interfaceId);
+
+					if (pPPS) {
+						pPPS->onNotify(event);
+					}
+				}
+			}
+
+			// Don't go off the end of the string
+			if (++nPos < data.length()) {
+
+				// Remove the stuff up to the first '\n' and look for the next '\n'
+				data = data.substr(nPos);
+				nPos = data.find('\n');
+			}
+			else {
+
+				nPos = std::string::npos;
+			}
+		}
+	}
+}
+
+} /* namespace jpps */