Bug 767327 - Add box.com to file link services. r=mconley

This commit is contained in:
Brian King 2012-08-14 19:23:30 -04:00
Родитель 8f66bd4ed2
Коммит cdd3eb3be4
11 изменённых файлов: 511 добавлений и 279 удалений

Просмотреть файл

@ -5,3 +5,7 @@ category cloud-files YouSendIt @mozilla.org/mail/yousendit;1
component {9a44742b-a7b1-4f44-919e-6f3b28902c1a} nsUbuntuOne.js
contract @mozilla.org/mail/ubuntuone;1 {9a44742b-a7b1-4f44-919e-6f3b28902c1a}
category cloud-files UbuntuOne @mozilla.org/mail/ubuntuone;1
component {c06a8707-7463-416c-8b39-e85044a4ff6e} nsBox.js
contract @mozilla.org/mail/box;1 {c06a8707-7463-416c-8b39-e85044a4ff6e}
category cloud-files Box @mozilla.org/mail/box;1

Просмотреть файл

@ -2,6 +2,8 @@
* 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/. */
/* Modeled on browserRequest used by the OAuth module */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
@ -9,11 +11,15 @@ const Cr = Components.results;
Cu.import("resource:///modules/http.jsm");
Cu.import("resource:///modules/gloda/log4moz.js");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const wpl = Ci.nsIWebProgressListener;
const kApiKey = "exs8m0agj1fa5728lxvn288ymz01dnzn";
const kServerUrl = "https://www.box.com/api/1.0/rest";
const kAuthUrl = "https://www.box.com/api/1.0/auth/";
const log = Log4Moz.getConfiguredLogger("BoxAuth");
var reporterListener = {
_isBusy: false,
@ -22,13 +28,9 @@ var reporterListener = {
return this.securityButton = document.getElementById("security-button");
},
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference,
Ci.nsISupports]),
onStateChange: function(/*in nsIWebProgress*/ aWebProgress,
/*in nsIRequest*/ aRequest,
@ -66,7 +68,7 @@ var reporterListener = {
wpl.STATE_SECURE_MED |
wpl.STATE_SECURE_LOW;
let browser = document.getElementById("requestFrame");
var level;
let level;
switch (aState & wpl_security_bits) {
case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
@ -82,6 +84,7 @@ var reporterListener = {
}
if (level) {
this.securityButton.setAttribute("level", level);
this.securityButton.removeAttribute("loading");
this.securityButton.hidden = false;
} else {
this.securityButton.hidden = true;
@ -92,29 +95,46 @@ var reporterListener = {
}
}
/**
* The authorization process is:
* - We load this window and immediately make a ticket request
* - With the returned ticket, we make a url and load it into the browser
* - The user logs in, and our opener listens for a redirect url
* - The redirect url contains the ticket and the auth token
* - The opener, when satisfied it has what it needs, closes this window
* - If the ticket call produces an error, we try again
*/
function onLoad()
{
document.getElementById("security-button").setAttribute("loading", "true");
let request = window.arguments[0].wrappedJSObject;
document.getElementById("headerMessage").textContent = request.promptText;
//let account = request.account;
// headerImage does not exist in the XUL. I wonder if the original intention was security-button?
// I wonder, should we set the url-bar-type url holder to have the service icon?
//if (request.iconURI != "")
// document.getElementById("headerImage").src = request.iconURI;
nsBoxAuth.getSessionTicket(function(aTicket) {
var authUrl = "https://www.box.com/api/1.0/auth/" + aTicket;
loadRequestedUrl(authUrl);
},
function (aReq) {
alert("get_ticket failed - status = " + aReq.status);
// XX TODO Handle this some way in the auth window
// Any ideas?
// OR
// Just close the window and let the opener handle the failure
// cancelRequest();
});
nsBoxAuth.numTries = 0;
setupTicketRequest();
}
function setupTicketRequest()
{
let successCallback = function (aTicket) {
let authUrl = kAuthUrl + aTicket;
loadRequestedUrl(authUrl);
};
let failureCallback = function (aReq) {
// retry
if (nsBoxAuth.numTries < 3) {
log.error("get_ticket failed, trying again - status = " + aReq.status);
setupTicketRequest();
}
else {
// give up after 3 tries
log.error("get_ticket failed, giving up - status = " + aReq.status);
cancelRequest();
}
};
nsBoxAuth.getSessionTicket(successCallback, failureCallback);
}
function cancelRequest()
@ -132,14 +152,10 @@ function reportUserClosed()
function loadRequestedUrl(aUrl)
{
let request = window.arguments[0].wrappedJSObject;
/*document.getElementById("headerMessage").textContent = request.promptText;
let account = request.account;
if (request.iconURI != "")
document.getElementById("headerImage").src = request.iconURI;*/
var browser = document.getElementById("requestFrame");
let browser = document.getElementById("requestFrame");
browser.addProgressListener(reporterListener,
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
Ci.nsIWebProgress.NOTIFY_ALL);
if (aUrl != "") {
browser.setAttribute("src", aUrl);
document.getElementById("headerMessage").textContent = aUrl;
@ -149,47 +165,63 @@ function loadRequestedUrl(aUrl)
var nsBoxAuth = {
log : Log4Moz.getConfiguredLogger("BoxAuth"),
numTries : 0,
/**
* A function for retrieving a new ticket needed for other API calls.
* The lifespan of a ticket is only a few minutes for authentication
* A function for retrieving a new ticket to use in the url for logging in
* The lifespan of a ticket is only a few minutes
*
* @param ...
* @param successCallback a callback fired if retrieving the ticket
* is successful.
* @param failureCallback a callback fired if retrieving the ticket
* fails.
*/
getSessionTicket: function(successCallback, failureCallback) {
let args = "?action=get_ticket&api_key=" + kApiKey;
let requestUrl = kServerUrl + args;
let args = "?action=get_ticket&api_key=" + kApiKey;
let requestUrl = kServerUrl + args;
// Request to get the ticket
doXHRequest(requestUrl,
null,
null,
function(aResponseText, aRequest) {
this.log.info("get_ticket request response = " + aResponseText);
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("status = " + docStatus);
if (docStatus != "get_ticket_ok") {
failureCallback(null, aResponseText, aRequest);
return;
}
var ticket = doc.getElementsByTagName("ticket")[0].firstChild.nodeValue;
this.log.info("Auth ticket = " + ticket);
successCallback(ticket);
}
else {
failureCallback("", aResponseText, aRequest);
}
}.bind(this),
function(aException, aResponseText, aRequest) {
this.log.info("Failed to acquire a ticket:" + aResponseText);
failureCallback(aException, aResponseText, aRequest);
}.bind(this),
let ticketSuccess = function(aResponseText, aRequest) {
log.info("get_ticket request response = " + aResponseText);
try {
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
log.info("status = " + docStatus);
if (docStatus != "get_ticket_ok") {
failureCallback(aRequest);
return;
}
let ticket = doc.getElementsByTagName("ticket")[0].firstChild.nodeValue;
log.info("Auth ticket = " + ticket);
successCallback(ticket);
}
else {
log.error("Failed to acquire a ticket: " + aResponseText);
failureCallback(aRequest);
}
}
catch(e) {
// most likely bad XML
log.error("Failed to parse ticket response: " + e);
log.error("Ticket response: " + aResponseText);
failureCallback(aRequest);
}
}.bind(this);
let ticketFailure = function(aException, aResponseText, aRequest) {
log.error("Ticket acquisition error: " + aResponseText);
failureCallback(aRequest);
}.bind(this)
// Request to get the ticket
doXHRequest(requestUrl,
null,
null,
ticketSuccess,
ticketFailure,
this,
"GET");
this.numTries++;
}
};

Просмотреть файл

@ -4,6 +4,8 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<!-- Modeled on browserRequest used by the OAuth module -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/browserRequest.css" type="text/css"?>
@ -14,9 +16,7 @@
buttons=","
onload="onLoad()"
onclose="reportUserClosed()"
title="&auth.title;"
width="850"
height="500">
title="&auth.title;">
<script type="application/javascript" src="chrome://messenger/content/cloudfile/Box/auth.js"/>
@ -27,15 +27,15 @@
<hbox id="header">
<hbox id="addressbox" flex="1" disabled="true">
<image id="security-button" src="chrome://messenger/skin/icons/mailicon32.png"/>
<image id="security-button"/>
<description id="headerMessage"/>
</hbox>
</hbox>
<browser type="content"
disablehistory="true"
src="chrome://messenger/content/cloudfile/Box/loader.gif"
id="requestFrame"
<browser type="content"
disablehistory="true"
src="about:blank"
id="requestFrame"
flex="1"/>
</window>

Двоичные данные
mail/components/cloudfile/content/Box/loader.gif

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Просмотреть файл

@ -12,7 +12,6 @@ messenger.jar:
content/messenger/cloudfile/Box/management.js (content/Box/management.js)
content/messenger/cloudfile/Box/auth.xul (content/Box/auth.xul)
content/messenger/cloudfile/Box/auth.js (content/Box/auth.js)
content/messenger/cloudfile/Box/loader.gif (content/Box/loader.gif)
content/messenger/cloudfile/UbuntuOne/management.js (content/UbuntuOne/management.js)
content/messenger/cloudfile/UbuntuOne/management.xhtml (content/UbuntuOne/management.xhtml)
content/messenger/cloudfile/UbuntuOne/settings.js (content/UbuntuOne/settings.js)

Просмотреть файл

@ -17,6 +17,8 @@ Cu.import("resource:///modules/cloudFileAccounts.js");
Cu.import("resource:///modules/http.jsm");
var gServerUrl = "https://www.box.com/api/1.0/rest";
var gUploadUrl = "https://upload.box.net/api/1.0/upload/";
var gSharingUrl = "https://www.box.com/shared/";
const kApiKey = "exs8m0agj1fa5728lxvn288ymz01dnzn";
@ -51,9 +53,6 @@ nsBox.prototype = {
_loggedIn: false,
_userInfo: null,
_file : null,
_requestDate: null,
_successCallback: null,
_request: null,
_maxFileSize : -1,
_fileSpaceUsed : -1,
_totalStorage : -1,
@ -88,29 +87,32 @@ nsBox.prototype = {
},
/**
* Private function for retrieving or creating folder
* on the Box website for uploading file.
* Private function for assigning the folder id from a cached version
* If the folder doesn't exist, set in motion the creation
*
* @param aCallback called if folder is ready.
*/
_initFolder: function nsBox__initFolder(aCallback) {
this.log.info('_initFolder');
this.log.info('_initFolder, cached folder id = ' + this._cachedFolderId);
let saveFolderId = function(aFolderId) {
this.log.info('saveFolderId');
this._folderId = aFolderId;
this.log.info('saveFolderId : ' + aFolderId);
this._cachedFolderId = this._folderId = aFolderId;
if (aCallback)
aCallback();
}.bind(this);
let createThunderbirdFolder = function(aParentFolderId) {
this._createFolder("Thunderbird", aParentFolderId, saveFolderId);
let createThunderbirdFolder = function() {
this._createFolder("Thunderbird", saveFolderId);
}.bind(this);
if (this._folderId == "")
if (this._cachedFolderId == "")
createThunderbirdFolder();
else
this.createThunderbirdFolder(saveFolderId);
else {
this._folderId = this._cachedFolderId;
if (aCallback)
aCallback();
}
},
/**
@ -221,9 +223,9 @@ nsBox.prototype = {
if (!this._uploader) {
this._uploader = new nsBoxFileUploader(this, aFile,
this._uploaderCallback
.bind(this),
aCallback);
this._uploaderCallback
.bind(this),
aCallback);
this._uploads.unshift(this._uploader);
}
@ -260,63 +262,74 @@ nsBox.prototype = {
* fails.
*/
_getUserInfo: function nsBox__getUserInfo(successCallback, failureCallback) {
let args = "?action=get_account_info&api_key=" + kApiKey
let args = "?action=get_account_info&api_key=" + kApiKey
+ "&auth_token=" + this._cachedAuthToken;
let requestUrl = gServerUrl + args;
this.log.info("requestUrl = " + requestUrl);
this.log.info("get_account_info requestUrl = " + requestUrl);
if (!successCallback)
successCallback = function() {
this.requestObserver
.onStopRequest(null, null,
this._loggedIn ? Cr.NS_OK : Ci.nsIMsgCloudFileProvider.authErr);
}.bind(this);
}.bind(this);
if (!failureCallback)
failureCallback = function () {
this.requestObserver
.onStopRequest(null, null, Ci.nsIMsgCloudFileProvider.authErr);
}.bind(this);
}.bind(this);
let accountInfoSuccess = function(aResponseText, aRequest) {
this.log.info("get_account_info request response = " + aResponseText);
try {
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("get_account_info status = " + docStatus);
if (docStatus != "get_account_info_ok") {
this.failureCallback();
return;
}
this._userInfo = aResponseText;
this._totalStorage = doc.getElementsByTagName("space_amount")[0].firstChild.nodeValue;
this._fileSpaceUsed = doc.getElementsByTagName("space_used")[0].firstChild.nodeValue;
this._maxFileSize = doc.getElementsByTagName("max_upload_size")[0].firstChild.nodeValue;
this.log.info("storage total = " + this._totalStorage);
this.log.info("storage used = " + this._fileSpaceUsed);
this.log.info("max file size = " + this._maxFileSize);
successCallback();
}
else {
failureCallback();
}
}
catch(e) {
// most likely bad XML
this.log.error("Failed to parse account info response: " + e);
this.log.error("Account info response: " + aResponseText);
failureCallback();
}
}.bind(this);
let accountInfoFailure = function(aException, aResponseText, aRequest) {
this.log.info("Failed to acquire user info:" + aResponseText);
this.log.error("user info failed, status = " + aRequest.status);
this.log.error("response text = " + aResponseText);
this.log.error("exception = " + aException);
failureCallback();
}.bind(this)
// Request to get user info
doXHRequest(requestUrl,
doXHRequest(requestUrl,
null,
null,
function(aResponseText, aRequest) {
this.log.info("get_account_info request response = " + aResponseText);
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("get_account_info status = " + docStatus);
if (docStatus != "get_account_info_ok") {
this.failureCallback();
return;
}
this._userInfo = aResponseText;
this._totalStorage = doc.getElementsByTagName("space_amount")[0].firstChild.nodeValue;
this._fileSpaceUsed = doc.getElementsByTagName("space_used")[0].firstChild.nodeValue;
this._maxFileSize = doc.getElementsByTagName("max_upload_size")[0].firstChild.nodeValue;
this.log.info("storage total = " + this._totalStorage);
this.log.info("storage used = " + this._fileSpaceUsed);
this.log.info("max file size = " + this._maxFileSize);
successCallback();
}
else {
failureCallback();
}
}.bind(this),
function(aException, aResponseText, aRequest) {
this.log.info("Failed to acquire user info:" + aResponseText);
this.log.error("user info failed, status = " + aRequest.status);
this.log.error("response text = " + aResponseText);
this.log.error("exception = " + aException);
failureCallback();
}.bind(this),
this,
"GET");
accountInfoSuccess,
accountInfoFailure,
this,
"GET");
},
/**
@ -392,50 +405,54 @@ nsBox.prototype = {
*/
_createFolder: function nsBox__createFolder(aName,
aSuccessCallback) {
this.log.info("Create folder: " + aName);
this.log.info("Creating folder: " + aName);
if (Services.io.offline)
throw Ci.nsIMsgCloudFileProvider.offlineErr;
let args = "?action=create_folder&api_key=" + kApiKey
+ "&auth_token=" + this._cachedAuthToken
+ "&parent_id=0&name" + aName
+ "&share=1";
let requestUrl = gServerUrl + args;
let args = "?action=create_folder&api_key=" + kApiKey
+ "&auth_token=" + this._cachedAuthToken
+ "&parent_id=0&name=" + aName
+ "&share=1";
let requestUrl = gServerUrl + args;
this.log.info("create_folder requestUrl = " + requestUrl);
// Request to get the ticket
doXHRequest(requestUrl,
null,
null,
function(aResponseText, aRequest) {
this.log.info("create_folder request response = " + aResponseText);
let createSuccess = function(aResponseText, aRequest) {
this.log.info("create_folder request response = " + aResponseText);
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("create_folder status = " + docStatus);
if (docStatus != "create_ok") {
// This means the folder likely exists
// How do we get the id?
//failureCallback(null, aResponseText, aRequest);
return;
}
let folderId = doc.getElementsByTagName("folder_id")[0].firstChild.nodeValue;
this.log.info("new folder id = " + folderId);
successCallback(folderId);
}
else {
// This means the folder likely exists
// How do we get the id?
//failureCallback("", aResponseText, aRequest);
}
}.bind(this),
function(aException, aResponseText, aRequest) {
this.log.info("Failed to create a new folder:" + aResponseText);
// This means the folder likely exists
// How do we get the id?
//failureCallback(aException, aResponseText, aRequest);
}.bind(this),
try {
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
if (docStatus != "create_ok" && docStatus != "s_folder_exists") {
this._lastErrorText = "Create folder failure";
this._lastErrorStatus = docStatus;
return;
}
let folderId = doc.getElementsByTagName("folder_id")[0].firstChild.nodeValue;
this.log.info("folder id = " + folderId);
aSuccessCallback(folderId);
}
else {
this._lastErrorText = "Create folder failure";
this._lastErrorStatus = "";
}
}
catch(e) {
// most likely bad XML
this.log.error("Failed to create a new folder");
}
}.bind(this);
let createFailure = function(aException, aResponseText, aRequest) {
this.log.error("Failed to create a new folder: " + aRequest.status);
}.bind(this);
// Request to create the folder
doXHRequest(requestUrl,
null,
null,
createSuccess,
createFailure,
this,
"GET");
},
@ -468,7 +485,6 @@ nsBox.prototype = {
* @param aError an error to get the URL for.
*/
providerUrlForError: function nsBox_providerUrlForError(aError) {
// XX TODO Identify other errors we need to worry about, and the resulting error page
if (aError == Ci.nsIMsgCloudFileProvider.uploadWouldExceedQuota)
return "https://www.box.com/pricing/";
return "";
@ -509,41 +525,53 @@ nsBox.prototype = {
throw Cr.NS_ERROR_FAILURE;
}
let args = "?action=delete&api_key=" + kApiKey
+ "&auth_token=" + this._cachedAuthToken
+ "&target=file&target_id" + uploadInfo.fileId;
let requestUrl = gServerUrl + args;
let args = "?action=delete&api_key=" + kApiKey
+ "&auth_token=" + this._cachedAuthToken
+ "&target=file&target_id=" + uploadInfo.fileId;
let requestUrl = gServerUrl + args;
this.log.info("delete requestUrl = " + requestUrl);
// Request to get the ticket
doXHRequest(requestUrl,
null,
null,
function(aResponseText, aRequest) {
this.log.info("delete request response = " + aResponseText);
let deleteSuccess = function(aResponseText, aRequest) {
this.log.info("delete request response = " + aResponseText);
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("status = " + docStatus);
if (docStatus != "s_delete_node") {
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
return;
}
this.log.info("Delete was successful!");
// Success!
aCallback.onStopRequest(null, null, Cr.NS_OK);
}
else {
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
}
}.bind(this),
function(aException, aResponseText, aRequest) {
this.log.info("Failed to delete file:" + aResponseText);
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
}.bind(this),
try {
let doc = aRequest.responseXML;
let docResponse = doc.documentElement;
if (docResponse && docResponse.nodeName == "response") {
let docStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("delete status = " + docStatus);
if (docStatus != "s_delete_node") {
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
return;
}
this.log.info("Delete was successful!");
// Success!
aCallback.onStopRequest(null, null, Cr.NS_OK);
}
else {
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
}
}
catch(e) {
// most likely bad XML
this.log.error("Failed to parse delete response: " + e);
this.log.error("Delete response: " + aResponseText);
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
}
}.bind(this);
let deleteFailure = function(aException, aResponseText, aRequest) {
this.log.error("Failed to delete file:" + aResponseText);
aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
}.bind(this);
// Request to delete a file
doXHRequest(requestUrl,
null,
null,
deleteSuccess,
deleteFailure,
this,
"GET");
"GET");
},
_getUrlParameter: function nsBox_getAuthParameter(aUrl, aName)
@ -582,75 +610,77 @@ nsBox.prototype = {
failureCallback();
return;
}
//let aSuccessCallback = successCallback
this._browserRequest = {
promptText : "box auth prompt",
account: this,
_active: true,
iconURI : this.iconClass,
successCallback : successCallback,
failureCallback : failureCallback,
cancelled: function() {
if (!this._active)
return;
this.account.log.info("auth cancelled");
this._finishLogonRequest();
this.failureCallback();
//this.account.connectFailureCallback();
// ### auth cancelled.
},
loaded: function(aWindow, aWebProgress) {
if (!this._active)
return;
this._browserRequest = {
promptText : "Box",
account: this,
_active: true,
iconURI : this.iconClass,
successCallback : successCallback,
failureCallback : failureCallback,
cancelled: function() {
if (!this._active)
return;
this.account.log.info("auth cancelled");
this.account._finishLogonRequest();
this.failureCallback();
},
loaded: function(aWindow, aWebProgress) {
if (!this._active)
return;
this._listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
_cleanUp: function() {
this.webProgress.removeProgressListener(this);
this.window.close();
delete this.window;
},
_checkForRedirect: function(aURL) {
if (aURL.indexOf(this._parent.completionURI) != 0)
return;
this._listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
_cleanUp: function() {
this.webProgress.removeProgressListener(this);
this.window.close();
delete this.window;
},
_checkForRedirect: function(aURL) {
if (aURL.indexOf(this._parent.completionURI) != 0)
return;
let ticket = this._parent._getUrlParameter(aURL, "ticket");
this._parent._cachedAuthToken = this._parent._getUrlParameter(aURL, "auth_token");
this._parent.log.info("Box auth redirect : " + aURL + "| ticket = " + ticket + " | Auth token = " + this._parent._cachedAuthToken);
let ticket = this._parent._getUrlParameter(aURL, "ticket");
this._parent._cachedAuthToken = this._parent._getUrlParameter(aURL, "auth_token");
this._parent.log.info("Box auth redirect : "
+ aURL
+ "| ticket = "
+ ticket
+ " | Auth token = "
+ this._parent._cachedAuthToken);
this._parent._loggedIn = true;
this._loggedIn = true;
this.successCallback();
this._parent._finishLogonRequest();
},
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
const wpl = Ci.nsIWebProgressListener;
if (aStateFlags & (wpl.STATE_START | wpl.STATE_IS_NETWORK))
this._checkForRedirect(aRequest.name);
},
onLocationChange: function(aWebProgress, aRequest, aLocation) {
this._checkForRedirect(aLocation.spec);
},
onProgressChange: function() {},
onStatusChange: function() {},
onSecurityChange: function() {},
this._parent._loggedIn = true;
this._loggedIn = true;
this.successCallback();
this._parent._finishLogonRequest();
},
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
const wpl = Ci.nsIWebProgressListener;
if (aStateFlags & (wpl.STATE_START | wpl.STATE_IS_NETWORK))
this._checkForRedirect(aRequest.name);
},
onLocationChange: function(aWebProgress, aRequest, aLocation) {
this._checkForRedirect(aLocation.spec);
},
onProgressChange: function() {},
onStatusChange: function() {},
onSecurityChange: function() {},
window: aWindow,
webProgress: aWebProgress,
_parent: this.account,
successCallback : this.successCallback
};
window: aWindow,
webProgress: aWebProgress,
_parent: this.account,
successCallback : this.successCallback
};
aWebProgress.addProgressListener(this._listener,
Ci.nsIWebProgress.NOTIFY_ALL);
},
},
};
this.wrappedJSObject = this._browserRequest;
Services.ww.openWindow(null,
"chrome://messenger/content/cloudfile/Box/auth.xul",
null, "chrome,centerscreen,width=980px,height=600px", this);
"chrome://messenger/content/cloudfile/Box/auth.xul",
null, "chrome,centerscreen,width=1100px,height=600px", this);
},
get _cachedAuthToken() {
@ -673,10 +703,11 @@ nsBox.prototype = {
},
get _cachedFolderId() {
let folderId = this._prefBranch.getCharPref("folderid");
if (!folderId)
return "";
let folderId = "";
try {
folderId = this._prefBranch.getCharPref("folderid");
}
catch(e) { } // pref does not exist
return folderId;
},
@ -703,32 +734,179 @@ nsBoxFileUploader.prototype = {
box : null,
file : null,
callback : null,
_request : null,
request : null,
/**
* Kicks off the upload request for the file associated with this Uploader.
* Do the upload of the file to Box.
*/
uploadFile: function nsDFU_uploadFile() {
return Cr.NS_ERROR_NOT_IMPLEMENTED;
uploadFile: function nsBox_uploadFile() {
this.requestObserver.onStartRequest(null, null);
let args = this.box._cachedAuthToken + "/" + this.box._folderId + "?new_copy=1&share=1";
let requestUrl = gUploadUrl + args;
this.box._uploadInfo[this.file.path] = {};
this.box._uploadInfo[this.file.path].uploadUrl = requestUrl;
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
let curDate = Date.now().toString();
this.log.info("upload url = " + requestUrl);
this.request = req;
req.open("POST", requestUrl, true);
req.onload = function() {
this.cleanupTempFile();
if (req.status >= 200 && req.status < 400) {
try {
this.log.info("upload response = " + req.responseText);
let doc = req.responseXML;
let uploadResponse = doc.documentElement;
if (uploadResponse && uploadResponse.nodeName == "response") {
let uploadStatus = doc.getElementsByTagName("status")[0].firstChild.nodeValue;
this.log.info("upload status = " + uploadStatus);
if (uploadStatus != "upload_ok") {
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
this.box._cachedFolderId = ""; // flush the folder id for a new attempt
return;
}
let file = doc.getElementsByTagName("file")[0];
let pn = file.getAttribute("public_name");
this.log.info("public_name = " + pn);
this.box._uploadInfo[this.file.path].fileId = file.getAttribute("id");
this.box._urlsForFiles[this.file.path] = gSharingUrl + pn;
this.callback(this.requestObserver, Cr.NS_OK);
}
else {
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
}
} catch (ex) {
this.log.error(ex);
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
}
}
else {
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
}
}.bind(this);
req.onerror = function () {
this.cleanupTempFile();
if (this.callback)
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
}.bind(this);
req.setRequestHeader("Date", curDate);
let boundary = "------" + curDate;
let contentType = "multipart/form-data; boundary="+ boundary;
req.setRequestHeader("Content-Type", contentType);
let fileName = encodeURIComponent(this.file.leafName);
let fileContents = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"fname\"; filename=\"" +
fileName + "\"\r\nContent-Type: application/octet-stream" +
"\r\n\r\n";
// Since js doesn't like binary data in strings, we're going to create
// a temp file consisting of the message preamble, the file contents, and
// the post script, and pass a stream based on that file to
// nsIXMLHttpRequest.send().
try {
this._tempFile = this.getTempFile(this.file.leafName);
let ostream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
ostream.init(this._tempFile, -1, -1, 0);
ostream.write(fileContents, fileContents.length);
this._fstream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
let sstream = Cc["@mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
this._fstream.init(this.file, -1, 0, 0);
sstream.init(this._fstream);
// This blocks the UI which is less than ideal. But it's a local
// file operations so probably not the end of the world.
while (sstream.available() > 0) {
let bytes = sstream.readBytes(sstream.available());
ostream.write(bytes, bytes.length);
}
fileContents = "\r\n--" + boundary + "--\r\n";
ostream.write(fileContents, fileContents.length);
ostream.close();
this._fstream.close();
sstream.close();
// defeat fstat caching
this._tempFile = this._tempFile.clone();
this._fstream.init(this._tempFile, -1, 0, 0);
this._fstream.close();
// I don't trust re-using the old fstream.
this._fstream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
this._fstream.init(this._tempFile, -1, 0, 0);
this._bufStream = Cc["@mozilla.org/network/buffered-input-stream;1"]
.createInstance(Ci.nsIBufferedInputStream);
this._bufStream.init(this._fstream, this._tempFile.fileSize);
// nsIXMLHttpRequest's nsIVariant handling requires that we QI
// to nsIInputStream.
req.send(this._bufStream.QueryInterface(Ci.nsIInputStream));
} catch (ex) {
this.cleanupTempFile();
this.log.error(ex);
throw ex;
}
},
/**
* Cancels the upload request for the file associated with this Uploader.
*/
cancel: function nsDFU_cancel() {
return Cr.NS_ERROR_NOT_IMPLEMENTED;
cancel: function nsBox_cancel() {
this.log.info("in uploader cancel");
this.callback(this.requestObserver, Ci.nsIMsgCloudFileProvider.uploadCanceled);
delete this.callback;
if (this.request) {
this.log.info("cancelling upload request");
let req = this.request;
if (req.channel) {
this.log.info("cancelling upload channel");
req.channel.cancel(Cr.NS_BINDING_ABORTED);
}
this.request = null;
}
},
/**
* Private function that attempts to retrieve the sharing URL for the file
* uploaded with this Uploader.
*
* @param aFile ...
* @param aCallback an nsIRequestObserver for monitoring the starting and
* ending states of the URL retrieval request.
* Creates and returns a temporary file on the local file system.
*/
_getShareUrl: function nsDFU__getShareUrl(aFile, aCallback) {
return Cr.NS_ERROR_NOT_IMPLEMENTED;
getTempFile: function nsBox_getTempFile(leafName) {
let tempfile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
tempfile.append(leafName)
tempfile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8));
// do whatever you need to the created file
return tempfile.clone()
},
/**
* Cleans up any temporary files that this nsBoxFileUploader may have
* created.
*/
cleanupTempFile: function nsBox_cleanupTempFile() {
if (this._bufStream)
this._bufStream.close();
if (this._fstream)
this._fstream.close();
if (this._tempFile)
this._tempFile.remove(false);
},
};

Просмотреть файл

@ -2,4 +2,5 @@
- 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/. -->
<!-- Note to localizers, Box is a brand from box.com -->
<!ENTITY auth.title "Box Authentication">

Просмотреть файл

@ -2,4 +2,5 @@
- 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/. -->
<!-- Note to localizers, Box is a brand from box.com -->
<!ENTITY boxSettings.needAnAccount "Get a Box account…">

Просмотреть файл

@ -18,6 +18,12 @@
background-image: url("chrome://messenger/skin/icons/insecure.png");
}
#security-button[loading="true"] {
margin-top: 5px;
margin-left: 4px;
background-image: url("chrome://global/skin/icons/loading_16.png");
}
#header {
border-bottom: 1px solid black;
overflow: hidden;

Просмотреть файл

@ -17,6 +17,12 @@
#security-button[level="broken"] {
background-image: url("chrome://messenger/skin/icons/insecure.png");
}
#security-button[loading="true"] {
margin-top: 3px;
margin-left: 4px;
background-image: url("chrome://global/skin/icons/loading_16.png");
}
/*
#header {
overflow: hidden;

Просмотреть файл

@ -17,6 +17,11 @@
background-image: url("chrome://messenger/skin/icons/insecure.png");
}
#security-button[loading="true"] {
margin-left: 4px;
background-image: url("chrome://global/skin/icons/loading_16.png");
}
#header {
overflow: hidden;
border-bottom: 1px solid black;