Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | "use strict"; |
michael@0 | 8 | |
michael@0 | 9 | this.EXPORTED_SYMBOLS = ["WifiCommand"]; |
michael@0 | 10 | |
michael@0 | 11 | const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; |
michael@0 | 12 | |
michael@0 | 13 | Cu.import("resource://gre/modules/systemlibs.js"); |
michael@0 | 14 | |
michael@0 | 15 | const SUPP_PROP = "init.svc.wpa_supplicant"; |
michael@0 | 16 | const WPA_SUPPLICANT = "wpa_supplicant"; |
michael@0 | 17 | const DEBUG = false; |
michael@0 | 18 | |
michael@0 | 19 | this.WifiCommand = function(aControlMessage, aInterface) { |
michael@0 | 20 | function debug(msg) { |
michael@0 | 21 | if (DEBUG) { |
michael@0 | 22 | dump('-------------- WifiCommand: ' + msg); |
michael@0 | 23 | } |
michael@0 | 24 | } |
michael@0 | 25 | |
michael@0 | 26 | var command = {}; |
michael@0 | 27 | |
michael@0 | 28 | //------------------------------------------------- |
michael@0 | 29 | // General commands. |
michael@0 | 30 | //------------------------------------------------- |
michael@0 | 31 | |
michael@0 | 32 | command.loadDriver = function (callback) { |
michael@0 | 33 | voidControlMessage("load_driver", function(status) { |
michael@0 | 34 | callback(status); |
michael@0 | 35 | }); |
michael@0 | 36 | }; |
michael@0 | 37 | |
michael@0 | 38 | command.unloadDriver = function (callback) { |
michael@0 | 39 | voidControlMessage("unload_driver", function(status) { |
michael@0 | 40 | callback(status); |
michael@0 | 41 | }); |
michael@0 | 42 | }; |
michael@0 | 43 | |
michael@0 | 44 | command.startSupplicant = function (callback) { |
michael@0 | 45 | voidControlMessage("start_supplicant", callback); |
michael@0 | 46 | }; |
michael@0 | 47 | |
michael@0 | 48 | command.killSupplicant = function (callback) { |
michael@0 | 49 | // It is interesting to note that this function does exactly what |
michael@0 | 50 | // wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung |
michael@0 | 51 | // changed that function in a way that means that it doesn't recognize |
michael@0 | 52 | // wpa_supplicant as already running. Therefore, we have to roll our own |
michael@0 | 53 | // version here. |
michael@0 | 54 | stopProcess(SUPP_PROP, WPA_SUPPLICANT, callback); |
michael@0 | 55 | }; |
michael@0 | 56 | |
michael@0 | 57 | command.terminateSupplicant = function (callback) { |
michael@0 | 58 | doBooleanCommand("TERMINATE", "OK", callback); |
michael@0 | 59 | }; |
michael@0 | 60 | |
michael@0 | 61 | command.stopSupplicant = function (callback) { |
michael@0 | 62 | voidControlMessage("stop_supplicant", callback); |
michael@0 | 63 | }; |
michael@0 | 64 | |
michael@0 | 65 | command.listNetworks = function (callback) { |
michael@0 | 66 | doStringCommand("LIST_NETWORKS", callback); |
michael@0 | 67 | }; |
michael@0 | 68 | |
michael@0 | 69 | command.addNetwork = function (callback) { |
michael@0 | 70 | doIntCommand("ADD_NETWORK", callback); |
michael@0 | 71 | }; |
michael@0 | 72 | |
michael@0 | 73 | command.setNetworkVariable = function (netId, name, value, callback) { |
michael@0 | 74 | doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + |
michael@0 | 75 | value, "OK", callback); |
michael@0 | 76 | }; |
michael@0 | 77 | |
michael@0 | 78 | command.getNetworkVariable = function (netId, name, callback) { |
michael@0 | 79 | doStringCommand("GET_NETWORK " + netId + " " + name, callback); |
michael@0 | 80 | }; |
michael@0 | 81 | |
michael@0 | 82 | command.removeNetwork = function (netId, callback) { |
michael@0 | 83 | doBooleanCommand("REMOVE_NETWORK " + netId, "OK", callback); |
michael@0 | 84 | }; |
michael@0 | 85 | |
michael@0 | 86 | command.enableNetwork = function (netId, disableOthers, callback) { |
michael@0 | 87 | doBooleanCommand((disableOthers ? "SELECT_NETWORK " : "ENABLE_NETWORK ") + |
michael@0 | 88 | netId, "OK", callback); |
michael@0 | 89 | }; |
michael@0 | 90 | |
michael@0 | 91 | command.disableNetwork = function (netId, callback) { |
michael@0 | 92 | doBooleanCommand("DISABLE_NETWORK " + netId, "OK", callback); |
michael@0 | 93 | }; |
michael@0 | 94 | |
michael@0 | 95 | command.status = function (callback) { |
michael@0 | 96 | doStringCommand("STATUS", callback); |
michael@0 | 97 | }; |
michael@0 | 98 | |
michael@0 | 99 | command.ping = function (callback) { |
michael@0 | 100 | doBooleanCommand("PING", "PONG", callback); |
michael@0 | 101 | }; |
michael@0 | 102 | |
michael@0 | 103 | command.scanResults = function (callback) { |
michael@0 | 104 | doStringCommand("SCAN_RESULTS", callback); |
michael@0 | 105 | }; |
michael@0 | 106 | |
michael@0 | 107 | command.disconnect = function (callback) { |
michael@0 | 108 | doBooleanCommand("DISCONNECT", "OK", callback); |
michael@0 | 109 | }; |
michael@0 | 110 | |
michael@0 | 111 | command.reconnect = function (callback) { |
michael@0 | 112 | doBooleanCommand("RECONNECT", "OK", callback); |
michael@0 | 113 | }; |
michael@0 | 114 | |
michael@0 | 115 | command.reassociate = function (callback) { |
michael@0 | 116 | doBooleanCommand("REASSOCIATE", "OK", callback); |
michael@0 | 117 | }; |
michael@0 | 118 | |
michael@0 | 119 | command.setBackgroundScan = function (enable, callback) { |
michael@0 | 120 | doBooleanCommand("SET pno " + (enable ? "1" : "0"), |
michael@0 | 121 | "OK", |
michael@0 | 122 | function(ok) { |
michael@0 | 123 | callback(true, ok); |
michael@0 | 124 | }); |
michael@0 | 125 | }; |
michael@0 | 126 | |
michael@0 | 127 | command.doSetScanMode = function (setActive, callback) { |
michael@0 | 128 | doBooleanCommand(setActive ? |
michael@0 | 129 | "DRIVER SCAN-ACTIVE" : |
michael@0 | 130 | "DRIVER SCAN-PASSIVE", "OK", callback); |
michael@0 | 131 | }; |
michael@0 | 132 | |
michael@0 | 133 | command.scan = function (callback) { |
michael@0 | 134 | doBooleanCommand("SCAN", "OK", callback); |
michael@0 | 135 | }; |
michael@0 | 136 | |
michael@0 | 137 | command.setLogLevel = function (level, callback) { |
michael@0 | 138 | doBooleanCommand("LOG_LEVEL " + level, "OK", callback); |
michael@0 | 139 | }; |
michael@0 | 140 | |
michael@0 | 141 | command.getLogLevel = function (callback) { |
michael@0 | 142 | doStringCommand("LOG_LEVEL", callback); |
michael@0 | 143 | }; |
michael@0 | 144 | |
michael@0 | 145 | command.wpsPbc = function (iface, callback) { |
michael@0 | 146 | doBooleanCommand("WPS_PBC" + (iface ? (" interface=" + iface) : ""), |
michael@0 | 147 | "OK", callback); |
michael@0 | 148 | }; |
michael@0 | 149 | |
michael@0 | 150 | command.wpsPin = function (detail, callback) { |
michael@0 | 151 | doStringCommand("WPS_PIN " + |
michael@0 | 152 | (detail.bssid === undefined ? "any" : detail.bssid) + |
michael@0 | 153 | (detail.pin === undefined ? "" : (" " + detail.pin)) + |
michael@0 | 154 | (detail.iface ? (" interface=" + detail.iface) : ""), |
michael@0 | 155 | callback); |
michael@0 | 156 | }; |
michael@0 | 157 | |
michael@0 | 158 | command.wpsCancel = function (callback) { |
michael@0 | 159 | doBooleanCommand("WPS_CANCEL", "OK", callback); |
michael@0 | 160 | }; |
michael@0 | 161 | |
michael@0 | 162 | command.startDriver = function (callback) { |
michael@0 | 163 | doBooleanCommand("DRIVER START", "OK"); |
michael@0 | 164 | }; |
michael@0 | 165 | |
michael@0 | 166 | command.stopDriver = function (callback) { |
michael@0 | 167 | doBooleanCommand("DRIVER STOP", "OK"); |
michael@0 | 168 | }; |
michael@0 | 169 | |
michael@0 | 170 | command.startPacketFiltering = function (callback) { |
michael@0 | 171 | var commandChain = ["DRIVER RXFILTER-ADD 0", |
michael@0 | 172 | "DRIVER RXFILTER-ADD 1", |
michael@0 | 173 | "DRIVER RXFILTER-ADD 3", |
michael@0 | 174 | "DRIVER RXFILTER-START"]; |
michael@0 | 175 | |
michael@0 | 176 | doBooleanCommandChain(commandChain, callback); |
michael@0 | 177 | }; |
michael@0 | 178 | |
michael@0 | 179 | command.stopPacketFiltering = function (callback) { |
michael@0 | 180 | var commandChain = ["DRIVER RXFILTER-STOP", |
michael@0 | 181 | "DRIVER RXFILTER-REMOVE 3", |
michael@0 | 182 | "DRIVER RXFILTER-REMOVE 1", |
michael@0 | 183 | "DRIVER RXFILTER-REMOVE 0"]; |
michael@0 | 184 | |
michael@0 | 185 | doBooleanCommandChain(commandChain, callback); |
michael@0 | 186 | }; |
michael@0 | 187 | |
michael@0 | 188 | command.doGetRssi = function (cmd, callback) { |
michael@0 | 189 | doCommand(cmd, function(data) { |
michael@0 | 190 | var rssi = -200; |
michael@0 | 191 | |
michael@0 | 192 | if (!data.status) { |
michael@0 | 193 | // If we are associating, the reply is "OK". |
michael@0 | 194 | var reply = data.reply; |
michael@0 | 195 | if (reply !== "OK") { |
michael@0 | 196 | // Format is: <SSID> rssi XX". SSID can contain spaces. |
michael@0 | 197 | var offset = reply.lastIndexOf("rssi "); |
michael@0 | 198 | if (offset !== -1) { |
michael@0 | 199 | rssi = reply.substr(offset + 5) | 0; |
michael@0 | 200 | } |
michael@0 | 201 | } |
michael@0 | 202 | } |
michael@0 | 203 | callback(rssi); |
michael@0 | 204 | }); |
michael@0 | 205 | }; |
michael@0 | 206 | |
michael@0 | 207 | command.getRssi = function (callback) { |
michael@0 | 208 | command.doGetRssi("DRIVER RSSI", callback); |
michael@0 | 209 | }; |
michael@0 | 210 | |
michael@0 | 211 | command.getRssiApprox = function (callback) { |
michael@0 | 212 | command.doGetRssi("DRIVER RSSI-APPROX", callback); |
michael@0 | 213 | }; |
michael@0 | 214 | |
michael@0 | 215 | command.getLinkSpeed = function (callback) { |
michael@0 | 216 | doStringCommand("DRIVER LINKSPEED", function(reply) { |
michael@0 | 217 | if (reply) { |
michael@0 | 218 | reply = reply.split(" ")[1] | 0; // Format: LinkSpeed XX |
michael@0 | 219 | } |
michael@0 | 220 | callback(reply); |
michael@0 | 221 | }); |
michael@0 | 222 | }; |
michael@0 | 223 | |
michael@0 | 224 | command.getConnectionInfoICS = function (callback) { |
michael@0 | 225 | doStringCommand("SIGNAL_POLL", function(reply) { |
michael@0 | 226 | if (!reply) { |
michael@0 | 227 | callback(null); |
michael@0 | 228 | return; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | let rval = {}; |
michael@0 | 232 | var lines = reply.split("\n"); |
michael@0 | 233 | for (let i = 0; i < lines.length; ++i) { |
michael@0 | 234 | let [key, value] = lines[i].split("="); |
michael@0 | 235 | switch (key.toUpperCase()) { |
michael@0 | 236 | case "RSSI": |
michael@0 | 237 | rval.rssi = value | 0; |
michael@0 | 238 | break; |
michael@0 | 239 | case "LINKSPEED": |
michael@0 | 240 | rval.linkspeed = value | 0; |
michael@0 | 241 | break; |
michael@0 | 242 | default: |
michael@0 | 243 | // Ignore. |
michael@0 | 244 | } |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | callback(rval); |
michael@0 | 248 | }); |
michael@0 | 249 | }; |
michael@0 | 250 | |
michael@0 | 251 | command.getMacAddress = function (callback) { |
michael@0 | 252 | doStringCommand("DRIVER MACADDR", function(reply) { |
michael@0 | 253 | if (reply) { |
michael@0 | 254 | reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX |
michael@0 | 255 | } |
michael@0 | 256 | callback(reply); |
michael@0 | 257 | }); |
michael@0 | 258 | }; |
michael@0 | 259 | |
michael@0 | 260 | command.setPowerModeICS = function (mode, callback) { |
michael@0 | 261 | doBooleanCommand("DRIVER POWERMODE " + (mode === "AUTO" ? 0 : 1), "OK", callback); |
michael@0 | 262 | }; |
michael@0 | 263 | |
michael@0 | 264 | command.setPowerModeJB = function (mode, callback) { |
michael@0 | 265 | doBooleanCommand("SET ps " + (mode === "AUTO" ? 1 : 0), "OK", callback); |
michael@0 | 266 | }; |
michael@0 | 267 | |
michael@0 | 268 | command.getPowerMode = function (callback) { |
michael@0 | 269 | doStringCommand("DRIVER GETPOWER", function(reply) { |
michael@0 | 270 | if (reply) { |
michael@0 | 271 | reply = (reply.split()[2]|0); // Format: powermode = XX |
michael@0 | 272 | } |
michael@0 | 273 | callback(reply); |
michael@0 | 274 | }); |
michael@0 | 275 | }; |
michael@0 | 276 | |
michael@0 | 277 | command.setNumAllowedChannels = function (numChannels, callback) { |
michael@0 | 278 | doBooleanCommand("DRIVER SCAN-CHANNELS " + numChannels, "OK", callback); |
michael@0 | 279 | }; |
michael@0 | 280 | |
michael@0 | 281 | command.getNumAllowedChannels = function (callback) { |
michael@0 | 282 | doStringCommand("DRIVER SCAN-CHANNELS", function(reply) { |
michael@0 | 283 | if (reply) { |
michael@0 | 284 | reply = (reply.split()[2]|0); // Format: Scan-Channels = X |
michael@0 | 285 | } |
michael@0 | 286 | callback(reply); |
michael@0 | 287 | }); |
michael@0 | 288 | }; |
michael@0 | 289 | |
michael@0 | 290 | command.setBluetoothCoexistenceMode = function (mode, callback) { |
michael@0 | 291 | doBooleanCommand("DRIVER BTCOEXMODE " + mode, "OK", callback); |
michael@0 | 292 | }; |
michael@0 | 293 | |
michael@0 | 294 | command.setBluetoothCoexistenceScanMode = function (mode, callback) { |
michael@0 | 295 | doBooleanCommand("DRIVER BTCOEXSCAN-" + (mode ? "START" : "STOP"), |
michael@0 | 296 | "OK", callback); |
michael@0 | 297 | }; |
michael@0 | 298 | |
michael@0 | 299 | command.saveConfig = function (callback) { |
michael@0 | 300 | // Make sure we never write out a value for AP_SCAN other than 1. |
michael@0 | 301 | doBooleanCommand("AP_SCAN 1", "OK", function(ok) { |
michael@0 | 302 | doBooleanCommand("SAVE_CONFIG", "OK", callback); |
michael@0 | 303 | }); |
michael@0 | 304 | }; |
michael@0 | 305 | |
michael@0 | 306 | command.reloadConfig = function (callback) { |
michael@0 | 307 | doBooleanCommand("RECONFIGURE", "OK", callback); |
michael@0 | 308 | }; |
michael@0 | 309 | |
michael@0 | 310 | command.setScanResultHandling = function (mode, callback) { |
michael@0 | 311 | doBooleanCommand("AP_SCAN " + mode, "OK", callback); |
michael@0 | 312 | }; |
michael@0 | 313 | |
michael@0 | 314 | command.addToBlacklist = function (bssid, callback) { |
michael@0 | 315 | doBooleanCommand("BLACKLIST " + bssid, "OK", callback); |
michael@0 | 316 | }; |
michael@0 | 317 | |
michael@0 | 318 | command.clearBlacklist = function (callback) { |
michael@0 | 319 | doBooleanCommand("BLACKLIST clear", "OK", callback); |
michael@0 | 320 | }; |
michael@0 | 321 | |
michael@0 | 322 | command.setSuspendOptimizationsICS = function (enabled, callback) { |
michael@0 | 323 | doBooleanCommand("DRIVER SETSUSPENDOPT " + (enabled ? 0 : 1), |
michael@0 | 324 | "OK", callback); |
michael@0 | 325 | }; |
michael@0 | 326 | |
michael@0 | 327 | command.setSuspendOptimizationsJB = function (enabled, callback) { |
michael@0 | 328 | doBooleanCommand("DRIVER SETSUSPENDMODE " + (enabled ? 1 : 0), |
michael@0 | 329 | "OK", callback); |
michael@0 | 330 | }; |
michael@0 | 331 | |
michael@0 | 332 | command.connectToSupplicant = function(callback) { |
michael@0 | 333 | voidControlMessage("connect_to_supplicant", callback); |
michael@0 | 334 | }; |
michael@0 | 335 | |
michael@0 | 336 | command.closeSupplicantConnection = function(callback) { |
michael@0 | 337 | voidControlMessage("close_supplicant_connection", callback); |
michael@0 | 338 | }; |
michael@0 | 339 | |
michael@0 | 340 | command.getMacAddress = function(callback) { |
michael@0 | 341 | doStringCommand("DRIVER MACADDR", function(reply) { |
michael@0 | 342 | if (reply) { |
michael@0 | 343 | reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX |
michael@0 | 344 | } |
michael@0 | 345 | callback(reply); |
michael@0 | 346 | }); |
michael@0 | 347 | }; |
michael@0 | 348 | |
michael@0 | 349 | command.setDeviceName = function(deviceName, callback) { |
michael@0 | 350 | doBooleanCommand("SET device_name " + deviceName, "OK", callback); |
michael@0 | 351 | }; |
michael@0 | 352 | |
michael@0 | 353 | //------------------------------------------------- |
michael@0 | 354 | // P2P commands. |
michael@0 | 355 | //------------------------------------------------- |
michael@0 | 356 | |
michael@0 | 357 | command.p2pProvDiscovery = function(address, wpsMethod, callback) { |
michael@0 | 358 | var command = "P2P_PROV_DISC " + address + " " + wpsMethod; |
michael@0 | 359 | doBooleanCommand(command, "OK", callback); |
michael@0 | 360 | }; |
michael@0 | 361 | |
michael@0 | 362 | command.p2pConnect = function(config, callback) { |
michael@0 | 363 | var command = "P2P_CONNECT " + config.address + " " + config.wpsMethodWithPin + " "; |
michael@0 | 364 | if (config.joinExistingGroup) { |
michael@0 | 365 | command += "join"; |
michael@0 | 366 | } else { |
michael@0 | 367 | command += "go_intent=" + config.goIntent; |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | debug('P2P connect command: ' + command); |
michael@0 | 371 | doBooleanCommand(command, "OK", callback); |
michael@0 | 372 | }; |
michael@0 | 373 | |
michael@0 | 374 | command.p2pGroupRemove = function(iface, callback) { |
michael@0 | 375 | debug("groupRemove()"); |
michael@0 | 376 | doBooleanCommand("P2P_GROUP_REMOVE " + iface, "OK", callback); |
michael@0 | 377 | }; |
michael@0 | 378 | |
michael@0 | 379 | command.p2pEnable = function(detail, callback) { |
michael@0 | 380 | var commandChain = ["SET device_name " + detail.deviceName, |
michael@0 | 381 | "SET device_type " + detail.deviceType, |
michael@0 | 382 | "SET config_methods " + detail.wpsMethods, |
michael@0 | 383 | "P2P_SET conc_pref sta", |
michael@0 | 384 | "P2P_FLUSH"]; |
michael@0 | 385 | |
michael@0 | 386 | doBooleanCommandChain(commandChain, callback); |
michael@0 | 387 | }; |
michael@0 | 388 | |
michael@0 | 389 | command.p2pDisable = function(callback) { |
michael@0 | 390 | doBooleanCommand("P2P_SET disabled 1", "OK", callback); |
michael@0 | 391 | }; |
michael@0 | 392 | |
michael@0 | 393 | command.p2pEnableScan = function(timeout, callback) { |
michael@0 | 394 | doBooleanCommand("P2P_FIND " + timeout, "OK", callback); |
michael@0 | 395 | }; |
michael@0 | 396 | |
michael@0 | 397 | command.p2pDisableScan = function(callback) { |
michael@0 | 398 | doBooleanCommand("P2P_STOP_FIND", "OK", callback); |
michael@0 | 399 | }; |
michael@0 | 400 | |
michael@0 | 401 | command.p2pGetGroupCapab = function(address, callback) { |
michael@0 | 402 | command.p2pPeer(address, function(reply) { |
michael@0 | 403 | debug('p2p_peer reply: ' + reply); |
michael@0 | 404 | if (!reply) { |
michael@0 | 405 | callback(0); |
michael@0 | 406 | return; |
michael@0 | 407 | } |
michael@0 | 408 | var capab = /group_capab=0x([0-9a-fA-F]+)/.exec(reply)[1]; |
michael@0 | 409 | if (!capab) { |
michael@0 | 410 | callback(0); |
michael@0 | 411 | } else { |
michael@0 | 412 | callback(parseInt(capab, 16)); |
michael@0 | 413 | } |
michael@0 | 414 | }); |
michael@0 | 415 | }; |
michael@0 | 416 | |
michael@0 | 417 | command.p2pPeer = function(address, callback) { |
michael@0 | 418 | doStringCommand("P2P_PEER " + address, callback); |
michael@0 | 419 | }; |
michael@0 | 420 | |
michael@0 | 421 | command.p2pGroupAdd = function(netId, callback) { |
michael@0 | 422 | doBooleanCommand("P2P_GROUP_ADD persistent=" + netId, callback); |
michael@0 | 423 | }; |
michael@0 | 424 | |
michael@0 | 425 | command.p2pReinvoke = function(netId, address, callback) { |
michael@0 | 426 | doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + address, "OK", callback); |
michael@0 | 427 | }; |
michael@0 | 428 | |
michael@0 | 429 | //---------------------------------------------------------- |
michael@0 | 430 | // Private stuff. |
michael@0 | 431 | //---------------------------------------------------------- |
michael@0 | 432 | |
michael@0 | 433 | function voidControlMessage(cmd, callback) { |
michael@0 | 434 | aControlMessage({ cmd: cmd, iface: aInterface }, function (data) { |
michael@0 | 435 | callback(data.status); |
michael@0 | 436 | }); |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | function doCommand(request, callback) { |
michael@0 | 440 | var msg = { cmd: "command", |
michael@0 | 441 | request: request, |
michael@0 | 442 | iface: aInterface }; |
michael@0 | 443 | |
michael@0 | 444 | aControlMessage(msg, callback); |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | function doIntCommand(request, callback) { |
michael@0 | 448 | doCommand(request, function(data) { |
michael@0 | 449 | callback(data.status ? -1 : (data.reply|0)); |
michael@0 | 450 | }); |
michael@0 | 451 | } |
michael@0 | 452 | |
michael@0 | 453 | function doBooleanCommand(request, expected, callback) { |
michael@0 | 454 | doCommand(request, function(data) { |
michael@0 | 455 | callback(data.status ? false : (data.reply === expected)); |
michael@0 | 456 | }); |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | function doStringCommand(request, callback) { |
michael@0 | 460 | doCommand(request, function(data) { |
michael@0 | 461 | callback(data.status ? null : data.reply); |
michael@0 | 462 | }); |
michael@0 | 463 | } |
michael@0 | 464 | |
michael@0 | 465 | function doBooleanCommandChain(commandChain, callback, i) { |
michael@0 | 466 | if (undefined === i) { |
michael@0 | 467 | i = 0; |
michael@0 | 468 | } |
michael@0 | 469 | |
michael@0 | 470 | doBooleanCommand(commandChain[i], "OK", function(ok) { |
michael@0 | 471 | if (!ok) { |
michael@0 | 472 | return callback(false); |
michael@0 | 473 | } |
michael@0 | 474 | i++; |
michael@0 | 475 | if (i === commandChain.length || !commandChain[i]) { |
michael@0 | 476 | // Reach the end or empty command. |
michael@0 | 477 | return callback(true); |
michael@0 | 478 | } |
michael@0 | 479 | doBooleanCommandChain(commandChain, callback, i); |
michael@0 | 480 | }); |
michael@0 | 481 | } |
michael@0 | 482 | |
michael@0 | 483 | //-------------------------------------------------- |
michael@0 | 484 | // Helper functions. |
michael@0 | 485 | //-------------------------------------------------- |
michael@0 | 486 | |
michael@0 | 487 | function stopProcess(service, process, callback) { |
michael@0 | 488 | var count = 0; |
michael@0 | 489 | var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
michael@0 | 490 | function tick() { |
michael@0 | 491 | let result = libcutils.property_get(service); |
michael@0 | 492 | if (result === null) { |
michael@0 | 493 | callback(); |
michael@0 | 494 | return; |
michael@0 | 495 | } |
michael@0 | 496 | if (result === "stopped" || ++count >= 5) { |
michael@0 | 497 | // Either we succeeded or ran out of time. |
michael@0 | 498 | timer = null; |
michael@0 | 499 | callback(); |
michael@0 | 500 | return; |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | // Else it's still running, continue waiting. |
michael@0 | 504 | timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT); |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | setProperty("ctl.stop", process, tick); |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | // Wrapper around libcutils.property_set that returns true if setting the |
michael@0 | 511 | // value was successful. |
michael@0 | 512 | // Note that the callback is not called asynchronously. |
michael@0 | 513 | function setProperty(key, value, callback) { |
michael@0 | 514 | let ok = true; |
michael@0 | 515 | try { |
michael@0 | 516 | libcutils.property_set(key, value); |
michael@0 | 517 | } catch(e) { |
michael@0 | 518 | ok = false; |
michael@0 | 519 | } |
michael@0 | 520 | callback(ok); |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | return command; |
michael@0 | 524 | }; |