mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
fe0509a62e
- Bug 904479 - Added createPromiseWithId() that returns id of resolver r=kanru,nsm (2ac672d882) - Bug 1166580 - Disable mozHasPendingMessage tests on non-browser platform. r=me (03c689964b) - Bug 1162281 - Invalid system message handler in an App Manifest can break the entire system. r=fabrice (e192a95f9c) - Bug 1198988 - Turn off some useless dump() calls r=ferjm (34fc83b236) - Bug 1164498: Remove |DispatchBluetoothReply|, r=btian (6143335efa) - Bug 1001757 - Add ability to store core apps outside of profile on desktop b2g; r=fabrice (f6b605e7aa) - Bug 1155245 - Set the app status correctly for hosted certified apps in developer mode. r=fabrice (131178b80e) - Bug 1179052 - Add some raptor markers to b2g gecko startup r=gwagner (222256fad8) - Bug 1163904 - handle -url command line argument. r=fabrice (ee61af1ff9) - Bug 1167275 - JS error in shell.js handleCmdLine() r=me (32e75c604f) - Bug 1167197 - Fix GMPProvider on Android r=cpearce Bug 1181209 - Make changes to Gecko needed for b2gdroid to boot. r=fabrice (b35d3a372f) - Bug 1158544 - Remove FTPChannelChild::mWasOpened and make the base class mWasOpened protected; r=mcmanus (9111e1bc00) - Bug 1171716 - Part 2: Use NS_ReleaseOnMainThread in nsBaseChannel. r=froydnj (f138124f14) - partial of Bug 1177175 - Add a UITour target inside the TP panel. (603cc719b3) - Bug 1175545 - Dont process alt-svc on 421 r=hurley (ad0f2f6e91) - Bug 1191291 - convert nsHttpChannel::RetargetDeliveryTo warning to log r=michal.novotny (b9c6003df8) - Bug 1182487 - Don't try to write to HTTP cache entry in nsHttpChannel when entry is open for reading only. r=michal (b36d7014a0) - Bug 1173069 - Don't accumulate the cache hit telemetry for intercepted channels; r=mayhemer,jdm (aaed79183d) - Bug 1208755 HttpBaseChannel::ShouldIntercept() should not assume every channel has a LoadInfo. r=ckerschb (d55be94901) - Bug 1201229 - Return an empty string for a header when an error occurs; r=dragana (256d0462c8) - Bug 1048048 - add preload content policy types - web platform test updates (r=dveditz) (baa1004dd6) - Bug 1048048 - add preload content policy types - csp changes (r=dveditz) (17914dadba) - Bug 1048048 - add preload content policy types for stylesheets (r=cam) (29af13263a) - Bug 1048048 - add preload content policy types (r=ehsan) (f58a32d51b) - Bug 1201747 - Don't inspect the subject principal in StorageAllowedForPrincipal. r=mystor (4f2c100882) - Bug 1176829 - Remove custom elements base element queue. r=smaug (03a520c13d) - Bug 1176829 follow-up, finish removing unused member to fix bustage. CLOSED TREE (29c6150af8) - Bug 1179909: Build fix. r=me CLOSED TREE (40e3bdb971) - Bug 1188932 - Allow the User-Agent header to be explicitly set by requests, r=bkelly, r=jgraham (37aacbd37d)
603 lines
17 KiB
JavaScript
603 lines
17 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* Copyright © 2014, Deutsche Telekom, Inc. */
|
|
|
|
"use strict";
|
|
|
|
/* globals dump, Components, XPCOMUtils, DOMRequestIpcHelper, cpmm, SE */
|
|
|
|
const DEBUG = false;
|
|
function debug(s) {
|
|
if (DEBUG) {
|
|
dump("-*- SecureElement DOM: " + s + "\n");
|
|
}
|
|
}
|
|
|
|
const Ci = Components.interfaces;
|
|
const Cu = Components.utils;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
|
"@mozilla.org/childprocessmessagemanager;1",
|
|
"nsISyncMessageSender");
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "SE", function() {
|
|
let obj = {};
|
|
Cu.import("resource://gre/modules/se_consts.js", obj);
|
|
return obj;
|
|
});
|
|
|
|
function PromiseHelpersSubclass(win) {
|
|
this._window = win;
|
|
}
|
|
|
|
PromiseHelpersSubclass.prototype = {
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
|
|
_window: null,
|
|
|
|
_context: [],
|
|
|
|
createSEPromise: function createSEPromise(callback, /* optional */ ctx) {
|
|
let ctxCallback = (resolverId) => {
|
|
if (ctx) {
|
|
this._context[resolverId] = ctx;
|
|
}
|
|
|
|
callback(resolverId);
|
|
};
|
|
|
|
return this.createPromiseWithId((aResolverId) => {
|
|
ctxCallback(aResolverId);
|
|
});
|
|
},
|
|
|
|
takePromise: function takePromise(resolverId) {
|
|
let resolver = this.takePromiseResolver(resolverId);
|
|
if (!resolver) {
|
|
return;
|
|
}
|
|
|
|
// Get the context associated with this resolverId
|
|
let context = this._context[resolverId];
|
|
delete this._context[resolverId];
|
|
|
|
return {resolver: resolver, context: context};
|
|
},
|
|
|
|
rejectWithSEError: function rejectWithSEError(reason) {
|
|
return this.createSEPromise((resolverId) => {
|
|
debug("rejectWithSEError : " + reason);
|
|
this.takePromiseResolver(resolverId).reject(new Error(reason));
|
|
});
|
|
}
|
|
};
|
|
|
|
// Helper wrapper class to do promises related chores
|
|
let PromiseHelpers;
|
|
|
|
/**
|
|
* Instance of 'SEReaderImpl' class is the connector to a secure element.
|
|
* A reader may or may not have a secure element present, since some
|
|
* secure elements are removable in nature (eg:- 'uicc'). These
|
|
* Readers can be physical devices or virtual devices.
|
|
*/
|
|
function SEReaderImpl() {}
|
|
|
|
SEReaderImpl.prototype = {
|
|
_window: null,
|
|
|
|
_sessions: [],
|
|
|
|
type: null,
|
|
_isSEPresent: false,
|
|
|
|
classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
|
|
contractID: "@mozilla.org/secureelement/reader;1",
|
|
QueryInterface: XPCOMUtils.generateQI([]),
|
|
|
|
// Chrome-only function
|
|
onSessionClose: function onSessionClose(sessionCtx) {
|
|
let index = this._sessions.indexOf(sessionCtx);
|
|
if (index != -1) {
|
|
this._sessions.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
initialize: function initialize(win, type, isPresent) {
|
|
this._window = win;
|
|
this.type = type;
|
|
this._isSEPresent = isPresent;
|
|
},
|
|
|
|
_checkPresence: function _checkPresence() {
|
|
if (!this._isSEPresent) {
|
|
throw new Error(SE.ERROR_NOTPRESENT);
|
|
}
|
|
},
|
|
|
|
openSession: function openSession() {
|
|
this._checkPresence();
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
let sessionImpl = new SESessionImpl();
|
|
sessionImpl.initialize(this._window, this);
|
|
this._window.SESession._create(this._window, sessionImpl);
|
|
this._sessions.push(sessionImpl);
|
|
PromiseHelpers.takePromiseResolver(resolverId)
|
|
.resolve(sessionImpl.__DOM_IMPL__);
|
|
});
|
|
},
|
|
|
|
closeAll: function closeAll() {
|
|
this._checkPresence();
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
let promises = [];
|
|
for (let session of this._sessions) {
|
|
if (!session.isClosed) {
|
|
promises.push(session.closeAll());
|
|
}
|
|
}
|
|
|
|
let resolver = PromiseHelpers.takePromiseResolver(resolverId);
|
|
// Wait till all the promises are resolved
|
|
Promise.all(promises).then(() => {
|
|
this._sessions = [];
|
|
resolver.resolve();
|
|
}, (reason) => {
|
|
resolver.reject(new Error(SE.ERROR_BADSTATE +
|
|
" Unable to close all channels associated with this reader"));
|
|
});
|
|
});
|
|
},
|
|
|
|
updateSEPresence: function updateSEPresence(isSEPresent) {
|
|
if (!isSEPresent) {
|
|
this.invalidate();
|
|
return;
|
|
}
|
|
|
|
this._isSEPresent = isSEPresent;
|
|
},
|
|
|
|
invalidate: function invalidate() {
|
|
debug("Invalidating SE reader: " + this.type);
|
|
this._isSEPresent = false;
|
|
this._sessions.forEach(s => s.invalidate());
|
|
this._sessions = [];
|
|
},
|
|
|
|
get isSEPresent() {
|
|
return this._isSEPresent;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Instance of 'SESessionImpl' object represent a connection session
|
|
* to one of the secure elements available on the device.
|
|
* These objects can be used to get a communication channel with an application
|
|
* hosted by the Secure Element.
|
|
*/
|
|
function SESessionImpl() {}
|
|
|
|
SESessionImpl.prototype = {
|
|
_window: null,
|
|
|
|
_channels: [],
|
|
|
|
_isClosed: false,
|
|
|
|
_reader: null,
|
|
|
|
classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
|
|
contractID: "@mozilla.org/secureelement/session;1",
|
|
QueryInterface: XPCOMUtils.generateQI([]),
|
|
|
|
// Private function
|
|
_checkClosed: function _checkClosed() {
|
|
if (this._isClosed) {
|
|
throw new Error(SE.ERROR_BADSTATE + " Session Already Closed!");
|
|
}
|
|
},
|
|
|
|
// Chrome-only function
|
|
onChannelOpen: function onChannelOpen(channelCtx) {
|
|
this._channels.push(channelCtx);
|
|
},
|
|
|
|
// Chrome-only function
|
|
onChannelClose: function onChannelClose(channelCtx) {
|
|
let index = this._channels.indexOf(channelCtx);
|
|
if (index != -1) {
|
|
this._channels.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
initialize: function initialize(win, readerCtx) {
|
|
this._window = win;
|
|
this._reader = readerCtx;
|
|
},
|
|
|
|
openLogicalChannel: function openLogicalChannel(aid) {
|
|
this._checkClosed();
|
|
|
|
let aidLen = aid ? aid.length : 0;
|
|
if (aidLen < SE.MIN_AID_LEN || aidLen > SE.MAX_AID_LEN) {
|
|
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
|
" Invalid AID length - " + aidLen);
|
|
}
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
/**
|
|
* @params for 'SE:OpenChannel'
|
|
*
|
|
* resolverId : ID that identifies this IPC request.
|
|
* aid : AID that identifies the applet on SecureElement
|
|
* type : Reader type ('uicc' / 'eSE')
|
|
* appId : Current appId obtained from 'Principal' obj
|
|
*/
|
|
cpmm.sendAsyncMessage("SE:OpenChannel", {
|
|
resolverId: resolverId,
|
|
aid: aid,
|
|
type: this.reader.type,
|
|
appId: this._window.document.nodePrincipal.appId
|
|
});
|
|
}, this);
|
|
},
|
|
|
|
closeAll: function closeAll() {
|
|
this._checkClosed();
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
let promises = [];
|
|
for (let channel of this._channels) {
|
|
if (!channel.isClosed) {
|
|
promises.push(channel.close());
|
|
}
|
|
}
|
|
|
|
let resolver = PromiseHelpers.takePromiseResolver(resolverId);
|
|
Promise.all(promises).then(() => {
|
|
this._isClosed = true;
|
|
this._channels = [];
|
|
// Notify parent of this session instance's closure, so that its
|
|
// instance entry can be removed from the parent as well.
|
|
this._reader.onSessionClose(this.__DOM_IMPL__);
|
|
resolver.resolve();
|
|
}, (reason) => {
|
|
resolver.reject(new Error(SE.ERROR_BADSTATE +
|
|
" Unable to close all channels associated with this session"));
|
|
});
|
|
});
|
|
},
|
|
|
|
invalidate: function invlidate() {
|
|
this._isClosed = true;
|
|
this._channels.forEach(ch => ch.invalidate());
|
|
this._channels = [];
|
|
},
|
|
|
|
get reader() {
|
|
return this._reader.__DOM_IMPL__;
|
|
},
|
|
|
|
get isClosed() {
|
|
return this._isClosed;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Instance of 'SEChannelImpl' object represent an ISO/IEC 7816-4 specification
|
|
* channel opened to a secure element. It can be either a logical channel
|
|
* or basic channel.
|
|
*/
|
|
function SEChannelImpl() {}
|
|
|
|
SEChannelImpl.prototype = {
|
|
_window: null,
|
|
|
|
_channelToken: null,
|
|
|
|
_isClosed: false,
|
|
|
|
_session: null,
|
|
|
|
openResponse: [],
|
|
|
|
type: null,
|
|
|
|
classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
|
|
contractID: "@mozilla.org/secureelement/channel;1",
|
|
QueryInterface: XPCOMUtils.generateQI([]),
|
|
|
|
_checkClosed: function _checkClosed() {
|
|
if (this._isClosed) {
|
|
throw new Error(SE.ERROR_BADSTATE + " Channel Already Closed!");
|
|
}
|
|
},
|
|
|
|
// Chrome-only function
|
|
onClose: function onClose() {
|
|
this._isClosed = true;
|
|
// Notify the parent
|
|
this._session.onChannelClose(this.__DOM_IMPL__);
|
|
},
|
|
|
|
initialize: function initialize(win, channelToken, isBasicChannel,
|
|
openResponse, sessionCtx) {
|
|
this._window = win;
|
|
// Update the 'channel token' that identifies and represents this
|
|
// instance of the object
|
|
this._channelToken = channelToken;
|
|
// Update 'session' obj
|
|
this._session = sessionCtx;
|
|
this.openResponse = Cu.cloneInto(new Uint8Array(openResponse), win);
|
|
this.type = isBasicChannel ? "basic" : "logical";
|
|
},
|
|
|
|
transmit: function transmit(command) {
|
|
// TODO remove this once it will be possible to have a non-optional dict
|
|
// in the WebIDL
|
|
if (!command) {
|
|
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
|
" SECommand dict must be defined");
|
|
}
|
|
|
|
this._checkClosed();
|
|
|
|
let dataLen = command.data ? command.data.length : 0;
|
|
if (dataLen > SE.MAX_APDU_LEN) {
|
|
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
|
" Command data length exceeds max limit - 255. " +
|
|
" Extended APDU is not supported!");
|
|
}
|
|
|
|
if ((command.cla & 0x80 === 0) && ((command.cla & 0x60) !== 0x20)) {
|
|
if (command.ins === SE.INS_MANAGE_CHANNEL) {
|
|
return PromiseHelpers.rejectWithSEError(SE.ERROR_SECURITY +
|
|
", MANAGE CHANNEL command not permitted");
|
|
}
|
|
if ((command.ins === SE.INS_SELECT) && (command.p1 == 0x04)) {
|
|
// SELECT by DF Name (p1=04) is not allowed
|
|
return PromiseHelpers.rejectWithSEError(SE.ERROR_SECURITY +
|
|
", SELECT command not permitted");
|
|
}
|
|
debug("Attempting to transmit an ISO command");
|
|
} else {
|
|
debug("Attempting to transmit GlobalPlatform command");
|
|
}
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
/**
|
|
* @params for 'SE:TransmitAPDU'
|
|
*
|
|
* resolverId : Id that identifies this IPC request.
|
|
* apdu : Object containing APDU data
|
|
* channelToken: Token that identifies the current channel over which
|
|
'c-apdu' is being sent.
|
|
* appId : Current appId obtained from 'Principal' obj
|
|
*/
|
|
cpmm.sendAsyncMessage("SE:TransmitAPDU", {
|
|
resolverId: resolverId,
|
|
apdu: command,
|
|
channelToken: this._channelToken,
|
|
appId: this._window.document.nodePrincipal.appId
|
|
});
|
|
}, this);
|
|
},
|
|
|
|
close: function close() {
|
|
this._checkClosed();
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
/**
|
|
* @params for 'SE:CloseChannel'
|
|
*
|
|
* resolverId : Id that identifies this IPC request.
|
|
* channelToken: Token that identifies the current channel over which
|
|
'c-apdu' is being sent.
|
|
* appId : Current appId obtained from 'Principal' obj
|
|
*/
|
|
cpmm.sendAsyncMessage("SE:CloseChannel", {
|
|
resolverId: resolverId,
|
|
channelToken: this._channelToken,
|
|
appId: this._window.document.nodePrincipal.appId
|
|
});
|
|
}, this);
|
|
},
|
|
|
|
invalidate: function invalidate() {
|
|
this._isClosed = true;
|
|
},
|
|
|
|
get session() {
|
|
return this._session.__DOM_IMPL__;
|
|
},
|
|
|
|
get isClosed() {
|
|
return this._isClosed;
|
|
},
|
|
};
|
|
|
|
function SEResponseImpl() {}
|
|
|
|
SEResponseImpl.prototype = {
|
|
sw1: 0x00,
|
|
|
|
sw2: 0x00,
|
|
|
|
data: null,
|
|
|
|
_channel: null,
|
|
|
|
classID: Components.ID("{58bc6c7b-686c-47cc-8867-578a6ed23f4e}"),
|
|
contractID: "@mozilla.org/secureelement/response;1",
|
|
QueryInterface: XPCOMUtils.generateQI([]),
|
|
|
|
initialize: function initialize(sw1, sw2, response, channelCtx) {
|
|
// Update the status bytes
|
|
this.sw1 = sw1;
|
|
this.sw2 = sw2;
|
|
this.data = response ? response.slice(0) : null;
|
|
// Update the channel obj
|
|
this._channel = channelCtx;
|
|
},
|
|
|
|
get channel() {
|
|
return this._channel.__DOM_IMPL__;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* SEManagerImpl
|
|
*/
|
|
function SEManagerImpl() {}
|
|
|
|
SEManagerImpl.prototype = {
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
|
|
_window: null,
|
|
|
|
classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
|
|
contractID: "@mozilla.org/secureelement/manager;1",
|
|
QueryInterface: XPCOMUtils.generateQI([
|
|
Ci.nsIDOMGlobalPropertyInitializer,
|
|
Ci.nsISupportsWeakReference,
|
|
Ci.nsIObserver
|
|
]),
|
|
|
|
_readers: [],
|
|
|
|
init: function init(win) {
|
|
this._window = win;
|
|
PromiseHelpers = new PromiseHelpersSubclass(this._window);
|
|
|
|
// Add the messages to be listened to.
|
|
const messages = ["SE:GetSEReadersResolved",
|
|
"SE:OpenChannelResolved",
|
|
"SE:CloseChannelResolved",
|
|
"SE:TransmitAPDUResolved",
|
|
"SE:GetSEReadersRejected",
|
|
"SE:OpenChannelRejected",
|
|
"SE:CloseChannelRejected",
|
|
"SE:TransmitAPDURejected",
|
|
"SE:ReaderPresenceChanged"];
|
|
|
|
this.initDOMRequestHelper(win, messages);
|
|
},
|
|
|
|
// This function will be called from DOMRequestIPCHelper.
|
|
uninit: function uninit() {
|
|
// All requests that are still pending need to be invalidated
|
|
// because the context is no longer valid.
|
|
this.forEachPromiseResolver((k) => {
|
|
this.takePromiseResolver(k).reject("Window Context got destroyed!");
|
|
});
|
|
PromiseHelpers = null;
|
|
this._window = null;
|
|
},
|
|
|
|
getSEReaders: function getSEReaders() {
|
|
// invalidate previous readers on new request
|
|
if (this._readers.length) {
|
|
this._readers.forEach(r => r.invalidate());
|
|
this._readers = [];
|
|
}
|
|
|
|
return PromiseHelpers.createSEPromise((resolverId) => {
|
|
cpmm.sendAsyncMessage("SE:GetSEReaders", {
|
|
resolverId: resolverId,
|
|
appId: this._window.document.nodePrincipal.appId
|
|
});
|
|
});
|
|
},
|
|
|
|
receiveMessage: function receiveMessage(message) {
|
|
DEBUG && debug("Message received: " + JSON.stringify(message));
|
|
|
|
let result = message.data.result;
|
|
let resolver = null;
|
|
let context = null;
|
|
|
|
let promiseResolver = PromiseHelpers.takePromise(result.resolverId);
|
|
if (promiseResolver) {
|
|
resolver = promiseResolver.resolver;
|
|
// This 'context' is the instance that originated this IPC message.
|
|
context = promiseResolver.context;
|
|
}
|
|
|
|
switch (message.name) {
|
|
case "SE:GetSEReadersResolved":
|
|
let readers = new this._window.Array();
|
|
result.readers.forEach(reader => {
|
|
let readerImpl = new SEReaderImpl();
|
|
readerImpl.initialize(this._window, reader.type, reader.isPresent);
|
|
this._window.SEReader._create(this._window, readerImpl);
|
|
|
|
this._readers.push(readerImpl);
|
|
readers.push(readerImpl.__DOM_IMPL__);
|
|
});
|
|
resolver.resolve(readers);
|
|
break;
|
|
case "SE:OpenChannelResolved":
|
|
let channelImpl = new SEChannelImpl();
|
|
channelImpl.initialize(this._window,
|
|
result.channelToken,
|
|
result.isBasicChannel,
|
|
result.openResponse,
|
|
context);
|
|
this._window.SEChannel._create(this._window, channelImpl);
|
|
if (context) {
|
|
// Notify context's handler with SEChannel instance
|
|
context.onChannelOpen(channelImpl);
|
|
}
|
|
resolver.resolve(channelImpl.__DOM_IMPL__);
|
|
break;
|
|
case "SE:TransmitAPDUResolved":
|
|
let responseImpl = new SEResponseImpl();
|
|
responseImpl.initialize(result.sw1,
|
|
result.sw2,
|
|
result.response,
|
|
context);
|
|
this._window.SEResponse._create(this._window, responseImpl);
|
|
resolver.resolve(responseImpl.__DOM_IMPL__);
|
|
break;
|
|
case "SE:CloseChannelResolved":
|
|
if (context) {
|
|
// Notify context's onClose handler
|
|
context.onClose();
|
|
}
|
|
resolver.resolve();
|
|
break;
|
|
case "SE:GetSEReadersRejected":
|
|
case "SE:OpenChannelRejected":
|
|
case "SE:CloseChannelRejected":
|
|
case "SE:TransmitAPDURejected":
|
|
let error = result.error || SE.ERROR_GENERIC;
|
|
resolver.reject(error);
|
|
break;
|
|
case "SE:ReaderPresenceChanged":
|
|
debug("Reader " + result.type + " present: " + result.isPresent);
|
|
let reader = this._readers.find(r => r.type === result.type);
|
|
if (reader) {
|
|
reader.updateSEPresence(result.isPresent);
|
|
}
|
|
break;
|
|
default:
|
|
debug("Could not find a handler for " + message.name);
|
|
resolver.reject();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
|
|
SEResponseImpl, SEChannelImpl, SESessionImpl, SEReaderImpl, SEManagerImpl
|
|
]);
|