1
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is edsintegration.
17
* The Initial Developer of the Original Code is
19
* Portions created by the Initial Developer are Copyright (C) 2011
20
* the Initial Developer. All Rights Reserved.
23
* Mike Conley <mconley@mozilla.com>
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
39
var EXPORTED_SYMBOLS = [ "AuthHelper" ];
42
const Cu = Components.utils;
43
const Cc = Components.classes;
44
const Ci = Components.interfaces;
46
Cu.import("resource://gre/modules/ctypes.jsm");
47
Cu.import("resource://gre/modules/Services.jsm");
48
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
50
Cu.import("resource://edsintegration/libedataserver-ctypes.jsm");
51
Cu.import("resource://edsintegration/LibGLib.jsm");
52
Cu.import("resource://edsintegration/nsAbEDSCommon.jsm");
53
Cu.import("resource://edsintegration/LibEBookClient.jsm");
54
Cu.import("resource://edsintegration/LibESource.jsm");
55
Cu.import("resource://edsintegration/LibGCancellable.jsm");
56
Cu.import("resource://edsintegration/ReferenceService.jsm");
57
Cu.import("resource://edsintegration/LibGAsyncResult.jsm");
58
Cu.import("resource://edsintegration/LibEClient.jsm");
59
Cu.import("resource://edsintegration/LibECredentials.jsm");
62
var gAuthAnchors = {};
65
function openNewAsyncCb(aGObject, aAsyncResult, aData) {
66
LOG("Entered openNewAsyncCb");
67
if (!aData || aData.isNull()) {
68
ERROR("Could not open EClient - aData was null is openNewAsyncCb");
73
var opData = AuthHelper.getOpData(aData);
75
LOG("Could not get opData (openNewAsyncCb) - this is fine if the"
76
+ " EBookClient does not require authentication.");
80
opData.openFinished = true;
82
let client = ctypes.cast(aGObject, LibEClient.EClient.ptr);
83
let errPtr = new LibGLib.GError.ptr();
85
if (!LibEClient.openFinish(client, aAsyncResult, errPtr.address()
86
|| LibGCancellable.setErrorIfCancelled(opData.cancellable,
88
LOG("Calling finishOrRetryOpen from openNewAsyncCb");
89
AuthHelper.finishOrRetryOpen(opData, errPtr);
90
LibGLib.g_error_free(errPtr);
95
if (opData.openedCbError) {
96
AuthHelper.finishOrRetryOpen(opData, opData.openedCbError);
100
if (LibEClient.isOpened(client)) {
101
LOG("Huzzah! Apparently an EClient has been opened (uri: " + opData.asyncCbData + ")");
102
AuthHelper.openNewDone(opData);
106
opData.refs['openNewCancelledCbPtr'] = LibGLib
107
.GCallback(AuthHelper
108
.openNewCancelledCb);
110
opData.refs.signal_connect(opData.cancellable, "cancelled", opData.refs['openNewCancelledCbPtr'],
115
var openNewAsyncCbPtr = LibGAsyncResult.GAsyncReadyCallback(openNewAsyncCb);
118
ADDRESSBOOK: "addressbook",
120
newClient: function AH_newClient(aESource, aClientType, aErrPtr) {
121
if (aClientType == AuthHelper.ADDRESSBOOK) {
122
return LibEBookClient.newFromSource(aESource, aErrPtr);
127
openAndAuthESource: function AH_openAndAuthESource(aESource, aType,
135
if (gAuthLookup[aURI]) {
136
WARN("There's already an auth helper trying to open an EClient with"
137
+ " URI: " + aURI + " - cancelling this attempt.");
141
if (!aESource || aESource.isNull()) {
142
ERROR("Tried to openAndAuth an ESource that was null!");
146
let errPtr = new LibGLib.GError.ptr();
147
let client = AuthHelper.newClient(aESource, aType, errPtr.address());
148
if (!errPtr.isNull()) {
149
ERROR("Could not create a client of type " + aType + " from ESource.");
150
ERROR("Message was: " + errPtr.contents.message.readString());
154
let opData = new AsyncOpData();
155
LOG("Registering some opData at uri: " + aURI);
156
gAuthLookup[aURI] = opData;
158
let data = LibGLib.g_object_ref(aESource);
159
opData.uriPtr = LibGLib.gchar.array()(aURI);
160
opData.source = ctypes.cast(data, LibESource.ESource.ptr);
161
opData.client = client;
162
opData.openFinished = false;
163
opData.retryOpenId = 0;
164
opData.authHandler = aAuthHandler;
165
opData.authHandlerData = aAuthHandlerData;
166
opData.asyncCb = aAsyncCb;
168
opData.asyncCbData = aAsyncCbData;
170
if (aCancellable && !aCancellable.isNull())
171
opData.cancellable = aCancellable;
173
opData.cancellable = LibGCancellable.newGCancellable();
175
opData.onlyIfExists = aOnlyIfExists;
176
opData.refs = ReferenceService.register("auth:" + aURI);
178
// Register the authentication callback if one exists
180
opData.refs['openNewAuthCbPtr'] = LibGLib
181
.GBooleanCallback(AuthHelper
183
opData.refs.signal_connect(client, "authenticate", opData.refs['openNewAuthCbPtr'],
187
opData.refs['openedCbPtr'] = LibGLib.GCallback(AuthHelper.openedCb);
189
opData.refs.signal_connect(client, "opened", opData.refs['openedCbPtr'],
191
let eclient = ctypes.cast(client, LibEClient.EClient.ptr);
192
LibEClient.open(eclient, aOnlyIfExists, aCancellable,
193
openNewAsyncCbPtr, opData.uriPtr);
197
openedCb: function AH_openedCb(aEClient, aGError, aData) {
198
LOG("Entered openedCb");
199
if (!aEClient || aEClient.isNull()) {
200
ERROR("In openedCb and aEClient is null");
205
var opData = AuthHelper.getOpData(aData);
207
ERROR("Could not complete openedCb:", e);
211
if (!opData.openFinished) {
212
if (!aGError.isNull()) {
213
aGError = ctypes.cast(aGError, LibGLib.GError.ptr);
214
opData.openedCbError = LibGLib.g_error_copy(aGError);
217
LOG("Calling finishOrRetryOpen from openedCb");
218
AuthHelper.finishOrRetryOpen(opData, aGError);
220
LOG("OpenedCb exited");
225
openNewCancelledCb: function AH_openNewCancelledCb(arg1, arg2, arg3) {
229
openNewAuthCb: function AH_openNewAuthCb(aEClient, aECredentials, aData) {
230
LOG("Within openNewAuthCb");
231
if (!aEClient || aEClient.isNull()) {
232
ERROR("The EClient passed to openNewAuthCb was null.");
233
return LibGLib.FALSE;
236
if (!aECredentials || aECredentials.isNull()) {
237
ERROR("The ECredentials passed to openNewAuthCb was null.");
238
return LibGLib.FALSE;
242
var opData = AuthHelper.getOpData(aData);
244
ERROR("Could not retrieve opData (openNewAuthCb): " + e);
245
return LibGLib.FALSE;
248
if (!opData.authHandler) {
249
ERROR("There was no authHandler for EClient");
250
return LibGLib.FALSE;
253
aECredentials = ctypes.cast(aECredentials, LibECredentials.ECredentials.ptr);
255
if (opData.usedCreds) {
256
let reason = LibECredentials.peek(opData.usedCreds,
257
LibECredentials.E_CREDENTIALS_KEY_PROMPT_REASON);
259
LibECredentials.set(aECredentials, LibECredentials.E_CREDENTIALS_KEY_PROMPT_TEXT, null);
260
LibECredentials.set(aECredentials, LibECredentials.E_CREDENTIALS_KEY_PROMPT_REASON, reason);
264
aEClient = ctypes.cast(aEClient, LibEClient.EClient.ptr);
266
let handled = opData.authHandler(aEClient, aECredentials, opData.authHandlerData);
268
if (handled == LibGLib.TRUE) {
269
if (opData.usedCreds) {
270
LibECredentials.free(opData.usedCreds);
271
opData.usedCreds = null;
273
opData.usedCreds = LibECredentials.newClone(aECredentials);
279
finishOrRetryOpen: function AH_finishOrRetryOpen(aOpData, aErrPtr) {
280
LOG("Entered finishOrRetryOpen");
281
aErrPtr = ctypes.cast(aErrPtr, LibGLib.GError.ptr);
283
if (aOpData.authHandler && !aErrPtr.isNull() &&
284
LibGLib.g_error_matches(aErrPtr, LibEClient.errorQuark(),
285
LibEClient.getEnum("E_CLIENT_ERROR_AUTHENTICATION_FAILED"))) {
286
if (aOpData.usedCreds && !aOpData.usedCreds.isNull()) {
287
// TODO: Password remembering? Forgetting?
288
LibECredentials.set(aOpData.usedCreds,
289
LibECredentials.E_CREDENTIALS_KEY_PROMPT_FLAGS,
290
LibECredentials.E_CREDENTIALS_USED);
291
LibECredentials.set(aOpData.usedCreds,
292
LibECredentials.E_CREDENTIALS_KEY_PROMPT_REASON,
293
aErrPtr.contents.message.readString());
294
LOG("Old credentials have been used.");
296
let eclient = ctypes.cast(aOpData.client, LibEClient.EClient.ptr);
297
LOG("Calling LibEClient.processAuth");
298
LibEClient.processAuth(eclient, aOpData.usedCreds);
300
} else if (!aErrPtr.isNull()) {
301
LOG("Calling asyncCb");
302
aOpData.asyncCb(aOpData.client, aErrPtr, aOpData.asyncCbData);
303
AuthHelper.freeOpData(aOpData);
305
LOG("Calling openNewDone");
306
AuthHelper.openNewDone(aOpData);
310
openNewDone: function AH_openNewDone(aOpData) {
311
if (!aOpData.asyncCb) {
312
ERROR("Entered openNewDone, but opData.asyncCb was null!");
316
// The callback should probably reconnect auth handler
318
aOpData.asyncCb(aOpData.client, aOpData.openedCbError, aOpData.asyncCbData);
319
AuthHelper.freeOpData(aOpData);
322
getOpData: function AH_getOpData(aData) {
323
if (!aData || aData.isNull())
324
throw("aData was null in getOpData");
326
let uri = ctypes.cast(aData, LibGLib.gchar.ptr).readString();
328
if (!gAuthLookup[uri])
329
throw("There was no opData in gAuthLookup for URI: " + uri);
331
return gAuthLookup[uri];
334
freeOpData: function AH_freeOpData(aOpData) {
336
WARN("Could not free opData, since it was null.");
340
if (!aOpData.client || aOpData.client.isNull()) {
341
WARN("Could not free opData, since it didn't have a client.");
345
if (!aOpData.cancellable || aOpData.cancellable.isNull()) {
346
WARN("Could not free opData, since it didn't have a cancellable.");
350
// Free signal handlers;
351
LOG("Freeing signal handlers");
352
aOpData.refs.dispose();
353
LOG("Signal handlers free'd for uri:" + aOpData.uriPtr.readString());
355
if (aOpData.usedCreds) {
356
LibECredentials.free(aOpData.usedCreds);
357
aOpData.usedCreds = null;
359
if (aOpData.openError) {
360
LibGLib.g_error_free(aOpData.openError);
361
aOpData.openError = null;
363
LibGLib.g_object_unref(aOpData.cancellable);
364
LibGLib.g_object_unref(aOpData.client);
365
LibGLib.g_object_unref(aOpData.source);
367
let uri = aOpData.uriPtr.readString();
369
gAuthLookup[uri] = null;
374
var AsyncOpData = function() {
376
this.authHandler = null;
377
this.authHandlerData = null;
381
this.usedCreds = null;
383
this.asyncCbData = null;
384
this.cancellable = null;
385
this.openFinished = false;
386
this.openError = null;
387
this.onlyIfExists = false;
388
this.retryOpenId = null;
389
this.openedCbError = null;