fix bug 763008, update to YSI v3 API and add custom upgrade UI, r=bienvenu, ur-r=bwinton
authorMaxim Baz <mbaz@codeminders.com>
Tue, 19 Jun 2012 13:34:33 -0700
changeset 12542 ee9bf9095b6e5fd4528680448292ac52f7a39d06
parent 12541 8c820d9d26126b9e3aa0a999e0ce789659dfacf5
child 12543 4468b7bdbd889e79fee38891075804ff2735530e
push id81
push usermconley@mozilla.com
push dateFri, 22 Jun 2012 13:28:44 +0000
treeherdertry-comm-central@92c43d8187ac [default view] [failures only]
reviewersbienvenu
bugs763008
fix bug 763008, update to YSI v3 API and add custom upgrade UI, r=bienvenu, ur-r=bwinton
mail/components/cloudfile/content/YouSendIt/fileExceeds2GB.xul
mail/components/cloudfile/content/YouSendIt/fileExceedsLimit.js
mail/components/cloudfile/content/YouSendIt/fileExceedsLimit.xul
mail/components/cloudfile/content/YouSendIt/fileExceedsQuota.js
mail/components/cloudfile/content/YouSendIt/fileExceedsQuota.xul
mail/components/cloudfile/content/YouSendIt/settings.xhtml
mail/components/cloudfile/jar.mn
mail/components/cloudfile/nsIMsgCloudFileProvider.idl
mail/components/cloudfile/nsYouSendIt.js
mail/components/compose/content/MsgComposeCommands.js
mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceeds2GB.dtd
mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceedsLimit.dtd
mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceedsQuota.dtd
mail/locales/en-US/chrome/messenger/messengercompose/composeMsgs.properties
mail/locales/jar.mn
mail/test/mozmill/shared-modules/test-cloudfile-yousendit-helpers.js
mail/themes/gnomestripe/jar.mn
mail/themes/gnomestripe/mail/cloudfile/YouSendIt/fileExceedsLimit.css
mail/themes/gnomestripe/mail/cloudfile/YouSendIt/settings.css
mail/themes/pinstripe/jar.mn
mail/themes/pinstripe/mail/cloudfile/YouSendIt/fileExceedsLimit.css
mail/themes/pinstripe/mail/cloudfile/YouSendIt/settings.css
mail/themes/qute/jar.mn
mail/themes/qute/mail/cloudfile/YouSendIt/fileExceedsLimit.css
mail/themes/qute/mail/cloudfile/YouSendIt/settings.css
new file mode 100644
--- /dev/null
+++ b/mail/components/cloudfile/content/YouSendIt/fileExceeds2GB.xul
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % fileExceeds2GBDTD SYSTEM "chrome://messenger/locale/cloudfile/YouSendIt/fileExceeds2GB.dtd" >
+%fileExceeds2GBDTD;
+]>
+
+<!-- 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/.  -->
+<?xml-stylesheet href="chrome://global/skin/"?>
+<?xml-stylesheet href="chrome://messenger/skin/preferences/preferences.css" type="text/css"?>
+
+<dialog id="fileExceeds2GB"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttons="cancel"
+        buttonlabelcancel="&fileExceeds2GB.cancel;"
+        title="&fileExceeds2GB.title;">
+
+  <description>&fileExceeds2GB.description;</description>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/mail/components/cloudfile/content/YouSendIt/fileExceedsLimit.js
@@ -0,0 +1,22 @@
+/* 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/. */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+let fileExceedsLimit = {
+  onOK: function AAD_onOK() {
+    let href = "https://www.yousendit.com/prosignup?p_code=pro&s=4001636&cid=pm-4001636";
+    gProtocolService.loadUrl(Services.io.newURI(href, "UTF-8", null));
+  },
+}
+
+XPCOMUtils.defineLazyServiceGetter(this, "gProtocolService",
+                                   "@mozilla.org/uriloader/external-protocol-service;1",
+                                   "nsIExternalProtocolService");
new file mode 100644
--- /dev/null
+++ b/mail/components/cloudfile/content/YouSendIt/fileExceedsLimit.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % fileExceedsLimitDTD SYSTEM "chrome://messenger/locale/cloudfile/YouSendIt/fileExceedsLimit.dtd" >
+%fileExceedsLimitDTD;
+]>
+
+<!-- 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/.  -->
+<?xml-stylesheet href="chrome://global/skin/"?>
+<?xml-stylesheet href="chrome://messenger/skin/preferences/preferences.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/cloudfile/YouSendIt/fileExceedsLimit.css" type="text/css"?>
+
+<dialog id="fileExceedsLimit"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttons="accept,cancel"
+        buttonlabelaccept="&fileExceedsLimit.accept;"
+        buttonlabelcancel="&fileExceedsLimit.cancel;"
+        ondialogaccept="return fileExceedsLimit.onOK();"
+        title="&fileExceedsLimit.title;">
+
+  <script type="text/javascript;version=1.8"
+          src="chrome://messenger/content/cloudfile/YouSendIt/fileExceedsLimit.js"/>
+
+  <description id="title">&fileExceedsLimit.thatsBigFile;</description>
+  <description id="title2">&fileExceedsLimit.thatsBigFile2;</description>
+  <description id="proIncludes">&fileExceedsLimit.proIncludes;</description>
+  <description>
+    <image src="chrome://messenger/skin/cloudfile/YouSendIt/check.png"/><label>&fileExceedsLimit.pros1;</label>
+  </description>
+  <description>
+    <image src="chrome://messenger/skin/cloudfile/YouSendIt/check.png"/><label>&fileExceedsLimit.pros2;</label>
+  </description>
+  <description>
+    <image src="chrome://messenger/skin/cloudfile/YouSendIt/check.png"/><label>&fileExceedsLimit.pros3;</label>
+  </description>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/mail/components/cloudfile/content/YouSendIt/fileExceedsQuota.js
@@ -0,0 +1,31 @@
+/* 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/. */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+document.addEventListener("DOMContentLoaded", function() {
+  if ("wrappedJSObject" in window.arguments[0]) {
+    let storage = parseInt(window.arguments[0].wrappedJSObject.storage);
+    storage = (storage / 1024 / 1024 / 1024).toFixed(2);
+    let currentStorage = document.getElementById('currentStorage');
+    currentStorage.textContent = currentStorage.textContent.replace('#XXX', storage);
+  }
+});
+
+let fileExceedsQuota = {
+  onOK: function AAD_onOK() {
+    let href = "https://www.yousendit.com/prosignup?p_code=pro&s=4001637&cid=pm-4001637";
+    gProtocolService.loadUrl(Services.io.newURI(href, "UTF-8", null));
+  },
+}
+
+XPCOMUtils.defineLazyServiceGetter(this, "gProtocolService",
+                                   "@mozilla.org/uriloader/external-protocol-service;1",
+                                   "nsIExternalProtocolService");
new file mode 100644
--- /dev/null
+++ b/mail/components/cloudfile/content/YouSendIt/fileExceedsQuota.xul
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % fileExceedsQuotaDTD SYSTEM "chrome://messenger/locale/cloudfile/YouSendIt/fileExceedsQuota.dtd" >
+%fileExceedsQuotaDTD;
+]>
+
+<!-- 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/.  -->
+<?xml-stylesheet href="chrome://global/skin/"?>
+<?xml-stylesheet href="chrome://messenger/skin/preferences/preferences.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/cloudfile/YouSendIt/fileExceedsLimit.css" type="text/css"?>
+
+<dialog id="fileExceedsQuota"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttons="accept,cancel"
+        buttonlabelaccept="&fileExceedsQuota.accept;"
+        buttonlabelcancel="&fileExceedsQuota.cancel;"
+        ondialogaccept="return fileExceedsQuota.onOK();"
+        title="&fileExceedsQuota.title;">
+
+  <script type="text/javascript;version=1.8"
+          src="chrome://messenger/content/cloudfile/YouSendIt/fileExceedsQuota.js"/>
+
+  <description id="title">&fileExceedsQuota.storageLimitReached;</description>
+  <description id="currentStorage">&fileExceedsQuota.description;</description>
+  <description>&fileExceedsQuota.description2;</description>
+  <description>&fileExceedsQuota.description3;</description>
+</dialog>
--- a/mail/components/cloudfile/content/YouSendIt/settings.xhtml
+++ b/mail/components/cloudfile/content/YouSendIt/settings.xhtml
@@ -18,13 +18,13 @@
   <body id="provider-settings">
     <form id="provider-form" onsubmit="return false;">
       <label for="username">&youSendItSettings.username;</label>
       <input id="username" type="text" required="true"/>
       <div id="learn-more" class="float-right">
         <a href="https://www.yousendit.com/thunderbird-about-yousendit?s=4001583&amp;cid=pm-4001583">&youSendItSettings.learnMore;</a>
       </div>
       <div>
-        <a href="https://www.yousendit.com/litesignup?s=4001583&amp;id=pm-4001583">&youSendItSettings.needAnAccount;</a>
+        <a href="https://www.yousendit.com/litesignup?s=4001583&amp;cid=pm-4001583">&youSendItSettings.needAnAccount;</a>
       </div>
     </form>
   </body>
 </html>
--- a/mail/components/cloudfile/jar.mn
+++ b/mail/components/cloudfile/jar.mn
@@ -10,8 +10,13 @@ messenger.jar:
     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)
     content/messenger/cloudfile/UbuntuOne/settings.xhtml (content/UbuntuOne/settings.xhtml)
     content/messenger/cloudfile/YouSendIt/management.xhtml (content/YouSendIt/management.xhtml)
     content/messenger/cloudfile/YouSendIt/management.js (content/YouSendIt/management.js)
     content/messenger/cloudfile/YouSendIt/settings.js (content/YouSendIt/settings.js)
     content/messenger/cloudfile/YouSendIt/settings.xhtml (content/YouSendIt/settings.xhtml)
+    content/messenger/cloudfile/YouSendIt/fileExceedsLimit.xul (content/YouSendIt/fileExceedsLimit.xul)
+    content/messenger/cloudfile/YouSendIt/fileExceedsLimit.js (content/YouSendIt/fileExceedsLimit.js)
+    content/messenger/cloudfile/YouSendIt/fileExceedsQuota.xul (content/YouSendIt/fileExceedsQuota.xul)
+    content/messenger/cloudfile/YouSendIt/fileExceedsQuota.js (content/YouSendIt/fileExceedsQuota.js)
+    content/messenger/cloudfile/YouSendIt/fileExceeds2GB.xul (content/YouSendIt/fileExceeds2GB.xul)
--- a/mail/components/cloudfile/nsIMsgCloudFileProvider.idl
+++ b/mail/components/cloudfile/nsIMsgCloudFileProvider.idl
@@ -130,9 +130,10 @@ interface nsIMsgCloudFileProvider : nsIS
   // but it really doesn't matter as long as we only return these
   // errors.
   const unsigned long offlineErr = 0x80550014; // NS_MSG_ERROR_OFFLINE
   const unsigned long authErr = 0x8055001e; // NS_MSG_USER_NOT_AUTHENTICATED
   const unsigned long uploadErr = 0x8055311a; // NS_MSG_ERROR_ATTACHING_FILE
   const unsigned long uploadWouldExceedQuota = 0x8055311b;
   const unsigned long uploadExceedsFileLimit = 0x8055311c;
   const unsigned long uploadCanceled = 0x8055311d;
+  const unsigned long uploadExceedsFileNameLimit = 0x8055311e;
 };
--- a/mail/components/cloudfile/nsYouSendIt.js
+++ b/mail/components/cloudfile/nsYouSendIt.js
@@ -16,19 +16,21 @@ Cu.import("resource:///modules/gloda/log
 Cu.import("resource:///modules/cloudFileAccounts.js");
 
 var gServerUrl = "https://dpi.yousendit.com"; // Production url
 // test url var gServerUrl = "https://test2-api.yousendit.com";
 
 const kApiKey = "7spvjdt7m4kycr7jyhywrdn2";
 const kAuthPath = "/dpi/v1/auth";
 const kUserInfoPath = "/dpi/v2/user";
-const kItemPath = "/dpi/v1/item/";
-const kItemSendPath = kItemPath + "send";
-const kItemCommitPath = kItemPath + "commit";
+const kFolderPath = "/dpi/v1/folder/";
+const kFolderFilePath = "/dpi/v1/folder/file/";
+const kFolderInitUploadPath = kFolderPath + "file/initUpload";
+const kFolderCommitUploadPath = kFolderPath + "file/commitUpload";
+const kUrlTail = "s=4001583&cid=pm-4001583";
 
 function nsYouSendIt() {
   this.log = Log4Moz.getConfiguredLogger("YouSendIt");
 }
 
 nsYouSendIt.prototype = {
   /* nsISupports */
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMsgCloudFileProvider]),
@@ -46,16 +48,17 @@ nsYouSendIt.prototype = {
 
   _accountKey: false,
   _prefBranch: null,
   _userName: "",
   _password: "",
   _loggedIn: false,
   _userInfo: null,
   _file : null,
+  _folderId: "",
   _requestDate: null,
   _successCallback: null,
   _request: null,
   _maxFileSize : -1,
   _fileSpaceUsed : -1,
   _availableStorage : -1,
   _totalStorage : -1,
   _lastErrorStatus : 0,
@@ -85,16 +88,55 @@ nsYouSendIt.prototype = {
     this._accountKey = aAccountKey;
     this._prefBranch = Services.prefs.getBranch("mail.cloud_files.accounts." +
                                                 aAccountKey + ".");
     this._userName = this._prefBranch.getCharPref("username");
     this._loggedIn = this._cachedAuthToken != "";
   },
 
   /**
+   * Private function for retrieving or creating folder
+   * on YouSendIt website for uploading file.
+   *
+   * @param aCallback called if folder is ready.
+   */
+  _initFolder: function nsYouSendIt__initFolder(aCallback) {
+    this.log.info('_initFolder');
+    
+    let saveFolderId = function(aFolderId) {
+      this.log.info('saveFolderId');
+      this._folderId = aFolderId;
+      if (aCallback)
+        aCallback();
+    }.bind(this);
+
+    let createThunderbirdFolder = function(aParentFolderId) {
+      this._createFolder("Mozilla Thunderbird", aParentFolderId, saveFolderId);
+    }.bind(this);
+
+    let createAppsFolder = function(aParentFolderId) {
+      this._createFolder("Apps", aParentFolderId, createThunderbirdFolder);
+    }.bind(this);
+
+    let findThunderbirdFolder = function(aParentFolderId) {
+      this._findFolder("Mozilla Thunderbird", aParentFolderId,
+                       createThunderbirdFolder, saveFolderId);
+    }.bind(this);
+
+    let findAppsFolder = function() {
+      this._findFolder("Apps", 0, createAppsFolder, findThunderbirdFolder);
+    }.bind(this);
+
+    if (this._folderId == "")
+      findAppsFolder();
+    else
+      this._checkFolderExist(this._folderId, aCallback, findAppsFolder);
+  },
+
+  /**
    * Private callback function passed to, and called from
    * nsYouSendItFileUploader.
    *
    * @param aRequestObserver a request observer for monitoring the start and
    *                         stop states of a request.
    * @param aStatus the status of the request.
    */
   _uploaderCallback: function nsYouSendIt__uploaderCallback(aRequestObserver,
@@ -130,93 +172,122 @@ nsYouSendIt.prototype = {
   uploadFile: function nsYouSendIt_uploadFile(aFile, aCallback) {
     if (Services.io.offline)
       throw Ci.nsIMsgCloudFileProvider.offlineErr;
 
     this.log.info("Preparing to upload a file");
 
     // if we're uploading a file, queue this request.
     if (this._uploadingFile && this._uploadingFile != aFile) {
+      this.log.info("Adding file to queue");
       let uploader = new nsYouSendItFileUploader(this, aFile,
                                                  this._uploaderCallback
                                                      .bind(this),
                                                  aCallback);
       this._uploads.push(uploader);
       return;
     }
 
     this._uploadingFile = aFile;
     this._urlListener = aCallback;
 
-    this.log.info("Checking to see if we're logged in");
+    let finish = function() {
+      this._finishUpload(aFile, aCallback);
+    }.bind(this);
 
     let onGetUserInfoSuccess = function() {
-      this._finishUpload(aFile, aCallback);
+      this._initFolder(finish);
     }.bind(this);
 
     let onAuthFailure = function() {
       this._urlListener.onStopRequest(null, null,
                                       Ci.nsIMsgCloudFileProvider.authErr);
     }.bind(this);
 
+    this.log.info("Checking to see if we're logged in");
+    
     if (!this._loggedIn) {
       let onLoginSuccess = function() {
         this._getUserInfo(onGetUserInfoSuccess, onAuthFailure);
       }.bind(this);
 
       return this.logon(onLoginSuccess, onAuthFailure, true);
     }
 
     if (!this._userInfo)
       return this._getUserInfo(onGetUserInfoSuccess, onAuthFailure);
 
-    this._finishUpload(aFile, aCallback);
+    onGetUserInfoSuccess();
   },
 
   /**
    * A private function called when we're almost ready to kick off the upload
    * for a file. First, ensures that the file size is not too large, and that
    * we won't exceed our storage quota, and then kicks off the upload.
    *
    * @param aFile the nsILocalFile to upload
    * @param aCallback the nsIRequestObserver for monitoring the start and stop
    *                  states of the upload procedure.
    */
   _finishUpload: function nsYouSendIt__finishUpload(aFile, aCallback) {
-    let exceedsLimit = Ci.nsIMsgCloudFileProvider.uploadExceedsFileLimit;
-    let exceedsQuota = Ci.nsIMsgCloudFileProvider.uploadWouldExceedQuota;
-
+    if (aFile.fileSize > 2147483648)
+      return this._fileExceedsLimit(aCallback, '2GB', 0);
     if (aFile.fileSize > this._maxFileSize)
-      return aCallback.onStopRequest(null, null, exceedsLimit);
+      return this._fileExceedsLimit(aCallback, 'Limit', 0);
     if (aFile.fileSize > this._availableStorage)
-      return aCallback.onStopRequest(null, null, exceedsQuota);
+      return this._fileExceedsLimit(aCallback, 'Quota', 
+                                    aFile.fileSize + this._fileSpaceUsed);
 
     delete this._userInfo; // force us to update userInfo on every upload.
 
     if (!this._uploader) {
       this._uploader = new nsYouSendItFileUploader(this, aFile,
                                                    this._uploaderCallback
                                                        .bind(this),
                                                    aCallback);
       this._uploads.unshift(this._uploader);
     }
 
     this._uploadingFile = aFile;
     this._uploader.startUpload();
   },
 
   /**
+   * A private function called when upload exceeds file limit.
+   *
+   * @param aCallback the nsIRequestObserver for monitoring the start and stop
+   *                  states of the upload procedure.
+   */
+  _fileExceedsLimit: function nsYouSendIt__fileExceedsLimit(aCallback, aType, aStorageSize) {
+    let cancel = Ci.nsIMsgCloudFileProvider.uploadCanceled;
+
+    let args = {storage: aStorageSize};
+    args.wrappedJSObject = args;
+    let ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                    .getService(Components.interfaces.nsIWindowWatcher);
+    ww.openWindow(null, 
+                  "chrome://messenger/content/cloudfile/YouSendIt/"
+                  + "fileExceeds" + aType + ".xul",
+                  "YouSendIt", "chrome,centerscreen,dialog,modal,resizable=yes", 
+                  args).focus(); 
+                  
+    return aCallback.onStopRequest(null, null, cancel);
+  },
+
+  /**
    * Cancels an in-progress file upload.
    *
    * @param aFile the nsILocalFile being uploaded.
    */
   cancelFileUpload: function nsYouSendIt_cancelFileUpload(aFile) {
     this.log.info("in cancel upload");
-    if (this._uploadingFile.equals(aFile))
+    if (this._uploadingFile != null && this._uploader != null && 
+        this._uploadingFile.equals(aFile)) {
       this._uploader.cancel();
+    }
     else {
       for (let i = 0; i < this._uploads.length; i++)
         if (this._uploads[i].file.equals(aFile)) {
           this._uploads[i].requestObserver.onStopRequest(
             null, null, Ci.nsIMsgCloudFileProvider.uploadCanceled);
           this._uploads.splice(i, 1);
           return;
         }
@@ -251,33 +322,33 @@ nsYouSendIt.prototype = {
    *
    * @param successCallback a callback fired if retrieving profile information
    *                        is successful.
    * @param failureCallback a callback fired if retrieving profile information
    *                        fails.
    */
   _getUserInfo: function nsYouSendIt_userInfo(successCallback, failureCallback) {
     this.log.info("getting user info");
-    let args = "?email=" + this._userName;
+    let args = "?email=" + this._userName + "&";
 
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
-    req.open("GET", gServerUrl + kUserInfoPath + args, true);
+    req.open("GET", gServerUrl + kUserInfoPath + args + kUrlTail, true);
 
     req.onload = function() {
-      if (req.status >= 200 && req.status <= 400) {
+      if (req.status >= 200 && req.status < 400) {
         this.log.info("request status = " + req.status +
                       " response = " + req.responseText);
         let docResponse = JSON.parse(req.responseText);
         this.log.info("user info response parsed = " + docResponse);
         if (docResponse.errorStatus)
           this.log.info("error status = " + docResponse.errorStatus.code);
 
         if (docResponse.errorStatus && docResponse.errorStatus.code > 200) {
-          if (docResponse.errorStatus.code >= 400) {
+          if (docResponse.errorStatus.code > 400) {
             // Our token has gone stale
             this.log.info("Our token has gone stale - requesting a new one.");
 
             let retryGetUserInfo = function() {
               this._getUserInfo(successCallback, failureCallback);
             }.bind(this);
 
             this._handleStaleToken(retryGetUserInfo, failureCallback);
@@ -286,30 +357,28 @@ nsYouSendIt.prototype = {
 
           failureCallback();
           return;
         }
         this._userInfo = docResponse;
         let account = docResponse.account;
         let storage = docResponse.storage;
         if (storage) {
-          this._fileSpaceUsed = storage.currentUsage;
-          this._availableStorage = storage.storageQuota - this._fileSpaceUsed;
+          this._fileSpaceUsed = parseInt(storage.currentUsage);
+          this._availableStorage = parseInt(storage.storageQuota) - this._fileSpaceUsed;
         }
-        else {
-          this._availableStorage = account.availableStorage;
-        }
+        else
+          this._availableStorage = parseInt(account.availableStorage);
 
-        this._maxFileSize = account.maxFileSize;
+        this._maxFileSize = docResponse.type == "BAS" ? 52428800 : (parseInt(account.maxFileSize));
         this.log.info("available storage = " + this._availableStorage + " max file size = " + this._maxFileSize);
         successCallback();
       }
-      else {
+      else
         failureCallback();
-      }
     }.bind(this);
 
     req.onerror = function() {
       this.log.info("getUserInfo failed - status = " + req.status);
       failureCallback();
     }.bind(this);
     // Add a space at the end because http logging looks for two
     // spaces in the X-Auth-Token header to avoid putting passwords
@@ -377,22 +446,22 @@ nsYouSendIt.prototype = {
    */
   createNewAccount: function nsYouSendIt_createNewAccount(aEmailAddress, aPassword,
                                                           aFirstName, aLastName,
                                                           aRequestObserver) {
     if (Services.io.offline)
       throw Ci.nsIMsgCloudFileProvider.offlineErr;
 
     let args = "?email=" + aEmailAddress + "&password=" + aPassword + "&firstname="
-               + aFirstName + "&lastname=" + aLastName;
+               + aFirstName + "&lastname=" + aLastName + "&";
 
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
 
-    req.open("POST", gServerUrl + kUserInfoPath + args, true);
+    req.open("POST", gServerUrl + kUserInfoPath + args + kUrlTail, true);
 
     req.onload = function() {
       if (req.status >= 200 &&
           req.status < 400) {
         this.log.info("request status = " + req + " response = " +
                       req.responseText);
         aRequestObserver.onStopRequest(null, null, Cr.NS_OK);
       }
@@ -413,16 +482,152 @@ nsYouSendIt.prototype = {
     // in the log, and crashes if there aren't two spaces.
     req.setRequestHeader("X-Auth-Token", this._cachedAuthToken + " ");
     req.setRequestHeader("X-Api-Key", kApiKey);
     req.setRequestHeader("Accept", "application/json");
     req.send();
   },
 
   /**
+   * Attempt to find folder by name on YSI website.
+   *
+   * @param aFolderName name of folder
+   * @param aParentFolderId id of folder where we are looking
+   * @param aNotFoundCallback called if folder is not found
+   * @param aFoundCallback called if folder is found
+   */
+  _findFolder: function nsYouSendIt__findFolder(aFolderName,
+                                                aParentFolderId,
+                                                aNotFoundCallback,
+                                                aFoundCallback) {
+    
+    this.log.info("Find folder: " + aFolderName);
+    
+    let checkChildFolders = function(folders) {
+      this.log.info("Looking for a child folder");
+      let folderId = 0;
+      let folder = folders.folder;
+      for (let i in folder) {
+        if (folder[i].name == aFolderName) {
+          folderId = folder[i].id;
+          break;
+        }
+      }
+
+      if (!folderId && aNotFoundCallback)
+        aNotFoundCallback(aParentFolderId);
+
+      if (folderId && aFoundCallback)
+        aFoundCallback(folderId);
+    }.bind(this);
+
+    this._checkFolderExist(aParentFolderId, checkChildFolders);
+  },
+
+  /**
+   * Attempt to find folder by id on YSI website.
+   *
+   * @param aFolderId id of folder
+   * @param aNotFoundCallback called if folder is not found
+   * @param aFoundCallback called if folder is found
+   */
+  _checkFolderExist: function nsYouSendIt__checkFolderExist(aFolderId,
+                                                            aFoundCallback,
+                                                            aNotFoundCallback) {
+    this.log.info('checkFolderExist');
+    if (Services.io.offline)
+      throw Ci.nsIMsgCloudFileProvider.offlineErr;
+
+    let args = "?includeFiles=false&includeFolders=true&";
+
+    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+
+    req.open("GET",
+             gServerUrl + kFolderPath + aFolderId + args + kUrlTail,
+             true);
+
+    req.onload = function() {
+      let docResponse = JSON.parse(req.responseText);
+      if (req.status >= 200 && req.status < 400) {
+        this.log.info("request status = " + req + " response = " +
+                      req.responseText);
+		
+        if (aFoundCallback && docResponse.folders)
+          aFoundCallback(docResponse.folders);
+      }
+      else {
+        this._lastErrorText = docResponse.errorStatus.message;
+        this._lastErrorStatus = docResponse.errorStatus.code;
+        if (this._lastErrorStatus == 400 && this._lastErrorText == "Not Found" && aNotFoundCallback)
+          aNotFoundCallback();
+      }
+    }.bind(this);
+
+    req.onerror = function() {
+      this.log.info("_checkFolderExist failed - status = " + req.status);
+    }.bind(this);
+    // Add a space at the end because http logging looks for two
+    // spaces in the X-Auth-Token header to avoid putting passwords
+    // in the log, and crashes if there aren't two spaces.
+    req.setRequestHeader("X-Auth-Token", this._cachedAuthToken + " ");
+    req.setRequestHeader("X-Api-Key", kApiKey);
+    req.setRequestHeader("Accept", "application/json");
+    req.send();
+  },
+
+  /**
+   * Private function for creating folder on YSI website.
+   *
+   * @param aName name of folder
+   * @param aParent id of parent folder
+   * @param aSuccessCallback called when folder is created
+   */
+  _createFolder: function nsYouSendIt__createFolder(aName,
+                                                    aParent,
+                                                    aSuccessCallback) {
+    this.log.info("Create folder: " + aName);
+    if (Services.io.offline)
+      throw Ci.nsIMsgCloudFileProvider.offlineErr;
+
+    let args = "?name=" + aName + "&parentId=" + aParent + "&";
+
+    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+
+    req.open("POST", gServerUrl + kFolderPath.replace(/\/$/, '') + args + kUrlTail, true);
+
+    req.onload = function() {
+      let docResponse = JSON.parse(req.responseText);
+      if (req.status >= 200 && req.status < 400) {
+        this.log.info("request status = " + req + " response = " +
+                      req.responseText);
+		
+        if (aSuccessCallback)
+          aSuccessCallback(docResponse.id)
+      }
+      else {
+        this._lastErrorText = docResponse.errorStatus.message;
+        this._lastErrorStatus = docResponse.errorStatus.code;
+      }
+    }.bind(this);
+
+    req.onerror = function() {
+      this.log.info("createFolder failed - status = " + req.status);
+    }.bind(this);
+    // Add a space at the end because http logging looks for two
+    // spaces in the X-Auth-Token header to avoid putting passwords
+    // in the log, and crashes if there aren't two spaces.
+    req.setRequestHeader("X-Auth-Token", this._cachedAuthToken + " ");
+    req.setRequestHeader("X-Api-Key", kApiKey);
+    req.setRequestHeader("Accept", "application/json");
+    req.send();
+  },
+
+  /**
    * If a the user associated with this account key already has an account,
    * allows them to log in.
    *
    * @param aRequestObserver an nsIRequestObserver for monitoring the start and
    *                         stop states of the login procedure.
    */
   createExistingAccount: function nsYouSendIt_createExistingAccount(aRequestObserver) {
      // XXX: replace this with a better function
@@ -484,80 +689,71 @@ nsYouSendIt.prototype = {
     let uploadInfo = this._uploadInfo[aFile.path];
     if (!uploadInfo) {
       this.log.error("Could not find a record for the file to be deleted.");
       throw Cr.NS_ERROR_FAILURE;
     }
 
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
-    let resource = kItemPath + uploadInfo.itemId;
 
-    req.open("DELETE", gServerUrl + resource, true);
+    let args = kFolderFilePath + uploadInfo.fileId + "?";
 
-    this.log.info("Sending request to: " + gServerUrl + resource);
+    req.open("DELETE", gServerUrl + args + kUrlTail, true);
+    this.log.info("Sending request to: " + gServerUrl + args);
 
-    req.onerror = function() {
-      this._lastErrorStatus = req.status;
-      this._lastErrorText = req.responseText;
+    req.onerror = function() {    
+      let response = JSON.parse(req.responseText);
+      this._lastErrorStatus = response.errorStatus.status;
+      this._lastErrorText = response.errorStatus.message;
       this.log.error("There was a problem deleting: " + this._lastErrorText);
       aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
     }.bind(this);
 
     req.onload = function() {
-      let response = req.responseText.replace(/<\?xml[^>]*\?>/, "");
-
-      if (req.status >= 200 && req.status < 400) {
-        this.log.info("Got back deletion response: " + response);
-        let docResponse = new XML(response);
-        this.log.info("docResponse = " + docResponse);
-
-        if ("errorStatus" in docResponse) {
-          // Argh - for some reason, on deletion, the error code for a stale
-          // token is 401 instead of 500.
-          if (docResponse.errorStatus.code == 401) {
+      // Response is the URL.
+      let response = req.responseText;
+      this.log.info("delete response = " + response);
+      let deleteInfo = JSON.parse(response);
 
-            this.log.warn("Token has gone stale! Will attempt to reauth.");
-            // Our token has gone stale
-            let onTokenRefresh = function() {
-              this.deleteFile(aFile, aCallback);
-            }.bind(this);
+      if (deleteInfo.errorStatus) {
+        // Argh - for some reason, on deletion, the error code for a stale
+        // token is 401 instead of 500.
+        if (deleteInfo.errorStatus.code == 401) {
+          this.log.warn("Token has gone stale! Will attempt to reauth.");
+          // Our token has gone stale
+          let onTokenRefresh = function() {
+            this.deleteFile(aFile, aCallback);
+          }.bind(this);
 
-            let onTokenRefreshFailure = function() {
-              aCallback.onStopRequest(null, null,
-                                      Ci.nsIMsgCloudFileProvider.authErr);
-            }
-            this._handleStaleToken(onTokenRefresh, onTokenRefreshFailure);
-            return;
+          let onTokenRefreshFailure = function() {
+            aCallback.onStopRequest(null, null,
+                                    Ci.nsIMsgCloudFileProvider.authErr);
           }
-
-          this.log.error("Server has returned a failure on our delete request.");
-          this.log.error("Error code: " + docResponse.errorStatus.code);
-          this.log.error("Error message: " + docResponse.errorStatus.message);
-          aCallback.onStopRequest(null, null,
-                                  Ci.nsIMsgCloudFileProvider.uploadErr);
+          this._handleStaleToken(onTokenRefresh, onTokenRefreshFailure);
           return;
         }
 
-        this.log.info("Delete was successful!");
-        // Success!
-        aCallback.onStopRequest(null, null, Cr.NS_OK);
+        this.log.error("Server has returned a failure on our delete request.");
+        this.log.error("Error code: " + deleteInfo.errorStatus.code);
+        this.log.error("Error message: " + deleteInfo.errorStatus.message);
+        //aCallback.onStopRequest(null, null,
+        //                        Ci.nsIMsgCloudFileProvider.uploadErr);
+        return;
       }
-      else {
-        this._lastErrorText = response;
-        this.log.error("Delete was not successful: " + this._lastErrorText);
-        this._lastErrorStatus = req.status;
-        aCallback.onStopRequest(null, null, Cr.NS_ERROR_FAILURE);
-      }
+
+      this.log.info("Delete was successful!");
+      // Success!
+      aCallback.onStopRequest(null, null, Cr.NS_OK);
     }.bind(this);
 
-    this.log.info("Sending delete request...");
     req.setRequestHeader("X-Auth-Token", this._cachedAuthToken + " ");
     req.setRequestHeader("X-Api-Key", kApiKey);
     req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+    req.setRequestHeader("Accept", "application/json");
     req.send();
   },
 
   /**
    * Returns the saved password for this account if one exists, or prompts
    * the user for a password. Returns the empty string on failure.
    *
    * @param aUsername the username associated with the account / password.
@@ -580,17 +776,17 @@ nsYouSendIt.prototype = {
     }
     if (aNoPrompt)
       return "";
 
     // OK, let's prompt for it.
     let win = Services.wm.getMostRecentWindow(null);
 
     let authPrompter = Services.ww.getNewAuthPrompter(win);
-    var password = { value: "" };
+    let password = { value: "" };
     // Use the service name in the prompt text
     let serverUrl = gServerUrl;
     let userPos = gServerUrl.indexOf("//") + 2;
     let userNamePart = encodeURIComponent(this._userName) + '@';
     serverUrl = gServerUrl.substr(0, userPos) + userNamePart + gServerUrl.substr(userPos);
     let messengerBundle = Services.strings.createBundle(
       "chrome://messenger/locale/messenger.properties");
     let promptString = messengerBundle.formatStringFromName("passwordPrompt",
@@ -600,17 +796,17 @@ nsYouSendIt.prototype = {
 
     if (authPrompter.promptPassword(this.displayName, promptString, serverUrl,
                                     authPrompter.SAVE_PASSWORD_PERMANENTLY,
                                     password))
       return password.value;
 
     return "";
   },
-
+ 
   /**
    * Clears any saved YouSendIt passwords for this instance's account.
    */
   clearPassword: function nsYouSendIt_clearPassword() {
     let logins = Services.logins.findLogins({}, gServerUrl, null, gServerUrl);
     for each (let loginInfo in logins)
       if (loginInfo.username == this._userName)
         Services.logins.removeLogin(loginInfo);
@@ -623,23 +819,23 @@ nsYouSendIt.prototype = {
    * @param failureCallback the callback to be fired if loggong on fails
    * @aparam aWithUI a boolean for whether or not we should prompt for a password
    *                 if no auth token is currently stored.
    */
   logon: function nsYouSendIt_login(successCallback, failureCallback, aWithUI) {
     this.log.info("Logging in, aWithUI = " + aWithUI);
     if (this._password == undefined || !this._password)
       this._password = this.getPassword(this._userName, !aWithUI);
-    let args = "?email=" + this._userName + "&password=" + this._password;
+    let args = "?email=" + this._userName + "&password=" + this._password + "&";
     this.log.info("Sending login information...");
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
     let curDate = Date.now().toString();
 
-    req.open("POST", gServerUrl + kAuthPath + args, true);
+    req.open("POST", gServerUrl + kAuthPath + args + kUrlTail, true);
     req.onerror = function() {
       this.log.info("logon failure");
       failureCallback();
     }.bind(this);
 
     req.onload = function() {
       if (req.status >= 200 && req.status < 400) {
         this.log.info("auth token response = " + req.responseText);
@@ -707,16 +903,17 @@ nsYouSendItFileUploader.prototype = {
   callback : null,
   _request : null,
 
   /**
    * Kicks off the upload procedure for this uploader.
    */
   startUpload: function nsYSIFU_startUpload() {
     let curDate = Date.now().toString();
+
     this.requestObserver.onStartRequest(null, null);
 
     let onSuccess = function() {
       this._uploadFile();
     }.bind(this);
 
     let onFailure = function() {
       this.callback(this.requestObserver, Ci.nsIMsgCloudFileProvider.uploadErr);
@@ -729,35 +926,31 @@ nsYouSendItFileUploader.prototype = {
    * Communicates with YSI to get the URL that we will send the upload
    * request to.
    *
    * @param successCallback the callback fired if getting the URL is successful
    * @param failureCallback the callback fired if getting the URL fails
    */
   _prepareToSend: function nsYSIFU__prepareToSend(successCallback,
                                                   failureCallback) {
-    let args = "?email=" + this.youSendIt._userName + "&recipients=" +
-               encodeURIComponent(this.youSendIt._userName) +
-               "&secureUrl=true";
-
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
 
-    req.open("POST", gServerUrl + kItemSendPath + args, true);
+    req.open("POST", gServerUrl + kFolderInitUploadPath + "?" + kUrlTail, true);
 
     req.onerror = failureCallback;
 
     req.onload = function() {
       let response = req.responseText;
       if (req.status >= 200 && req.status < 400) {
         this._urlInfo = JSON.parse(response);
         this.youSendIt._uploadInfo[this.file.path] = this._urlInfo;
         this.log.info("in prepare to send response = " + response);
-        this.log.info("urlInfo = " + this._urlInfo);
-        this.log.info("upload url = " + this._urlInfo.uploadUrl);
+        this.log.info("file id = " + this._urlInfo.fileId);
+        this.log.info("upload url = " + this._urlInfo.uploadUrl[0]);
         successCallback();
       }
       else {
         this.log.error("Preparing to send failed!");
         this.log.error("Response was: " + response);
         this.youSendIt._lastErrorText = req.responseText;
         this.youSendIt._lastErrorStatus = req.status;
         failureCallback();
@@ -766,32 +959,31 @@ nsYouSendItFileUploader.prototype = {
 
     // Add a space at the end because http logging looks for two
     // spaces in the X-Auth-Token header to avoid putting passwords
     // in the log, and crashes if there aren't two spaces.
     req.setRequestHeader("X-Auth-Token", this.youSendIt._cachedAuthToken + " ");
     req.setRequestHeader("X-Api-Key", kApiKey);
     req.setRequestHeader("Accept", "application/json");
     req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-    this.log.info("Sending prepare request with args: " + args);
     req.send();
   },
 
   /**
    * Once we've got the URL to upload the file to, this function actually does
    * the upload of the file to YouSendIt.
    */
   _uploadFile: function nsYSIFU__uploadFile() {
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
 
     let curDate = Date.now().toString();
-    this.log.info("upload url = " + this._urlInfo.uploadUrl);
+    this.log.info("upload url = " + this._urlInfo.uploadUrl[0]);
     this.request = req;
-    req.open("POST", this._urlInfo.uploadUrl, true);
+    req.open("POST", this._urlInfo.uploadUrl[0] + "?" + kUrlTail, true);
     req.onload = function() {
       this.cleanupTempFile();
       if (req.status >= 200 && req.status < 400) {
         try {
           let response = req.responseText.replace(/<\?xml[^>]*\?>/, "");
           this.log.info("upload response = " + response);
           let docResponse = new XML(response);
           this.log.info("docResponse = " + docResponse);
@@ -802,37 +994,36 @@ nsYouSendItFileUploader.prototype = {
           this.log.info("ysi error = " + ysiError);
           let errorCode = docResponse['error-code'];
           this.log.info("error code = " + errorCode);
           this._commitSend();
         } catch (ex) {
           this.log.error(ex);
         }
       }
-      else {
+      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 fileContents = "--" + boundary +
       "\r\nContent-Disposition: form-data; name=\"bid\"\r\n\r\n" +
-       this._urlInfo.itemId;
+       this._urlInfo.fileId;
 
     fileContents += "\r\n--" + boundary +
       "\r\nContent-Disposition: form-data; name=\"fname\"; filename=\"" +
       this.file.leafName + "\"\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
@@ -905,48 +1096,96 @@ nsYouSendItFileUploader.prototype = {
       this.request = null;
     }
   },
   /**
    * Once the file is uploaded, if we want to get a sharing URL back, we have
    * to send a "commit" request - which this function does.
    */
   _commitSend: function nsYSIFU__commitSend() {
+    this.log.info("commit sending file " + this._urlInfo.fileId);
+    
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
-    let resource = kItemCommitPath + "/" + this._urlInfo.itemId;
-    // Not quite sure how we're going to not have expiration.
-    let args = "?sendEmailNotifications=false&expiration=0";  // &expiration=4000000
-    let curDate = Date.now().toString();
+    let args = "?name=" + this.file.leafName +
+               "&fileId=" + this._urlInfo.fileId +
+               "&parentId=" + this.youSendIt._folderId + "&";
 
-    this.log.info("in commit send resource = " + resource);
-
-    req.open("POST", gServerUrl + resource + args, true);
+    req.open("POST", gServerUrl + kFolderCommitUploadPath + args + kUrlTail, true);
 
     req.onerror = function() {
       this.log.info("error in commit send");
       this.callback(this.requestObserver,
                     Ci.nsIMsgCloudFileProvider.uploadErr);
     }.bind(this);
 
     req.onload = function() {
       // Response is the URL.
       let response = req.responseText;
       this.log.info("commit response = " + response);
       let uploadInfo = JSON.parse(response);
 
-      if (uploadInfo.downloadUrl != null) {
-        this.youSendIt._urlsForFiles[this.file.path] = uploadInfo.downloadUrl;
-        // Success!
+      let succeed = function() {
         this.callback(this.requestObserver, Cr.NS_OK);
-        return;
+      }.bind(this);
+
+      let failed = function() {
+        this.callback(this.requestObserver, this.file.leafName.length > 120 
+                      ? Ci.nsIMsgCloudFileProvider.uploadExceedsFileNameLimit
+                      : Ci.nsIMsgCloudFileProvider.uploadErr);
+      }.bind(this);
+
+      if (uploadInfo.errorStatus) {
+        this.youSendIt._lastErrorText = uploadInfo.errorStatus.message;
+        this.youSendIt._lastErrorStatus = uploadInfo.errorStatus.code;
+        failed();
+      }
+      else if (uploadInfo.clickableDownloadUrl) {
+        this.youSendIt._urlsForFiles[this.file.path] = uploadInfo.clickableDownloadUrl;
+        succeed();
       }
-      this.youSendIt._lastErrorText = uploadInfo.errorStatus.message;
-      this.youSendIt._lastErrorStatus = uploadInfo.errorStatus.code;
-      this.callback(this.requestObserver, Ci.nsIMsgCloudFileProvider.uploadErr);
+      else
+        this._findDownloadUrl(uploadInfo.id, succeed, failed);
+    }.bind(this);
+
+    req.setRequestHeader("X-Auth-Token", this.youSendIt._cachedAuthToken + " ");
+    req.setRequestHeader("X-Api-Key", kApiKey);
+    req.setRequestHeader("Accept", "application/json");
+    req.send();
+  },
+
+  /**
+   * Attempt to find download url for file.
+   *
+   * @param aFileId id of file
+   * @param aSuccessCallback called if url is found
+   * @param aFailureCallback called if url is not found
+   */
+  _findDownloadUrl: function nsYSIFU__findDownloadUrl(aFileId, aSuccessCallback, aFailureCallback) {
+    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+
+    req.open("GET", gServerUrl + kFolderFilePath + aFileId, true);
+
+    req.onerror = function() {
+      this.log.info("error in findDownloadUrl");
+      aFailureCallback();
+    }.bind(this);
+
+    req.onload = function() {
+      let response = req.responseText;
+      this.log.info("findDownloadUrl response = " + response);
+      let fileInfo = JSON.parse(response);
+
+      if (fileInfo.errorStatus)
+        aFailureCallback();
+      else {
+        this.youSendIt._urlsForFiles[this.file.path] = fileInfo.clickableDownloadUrl;
+        aSuccessCallback();
+      }
     }.bind(this);
 
     req.setRequestHeader("X-Auth-Token", this.youSendIt._cachedAuthToken + " ");
     req.setRequestHeader("X-Api-Key", kApiKey);
     req.setRequestHeader("Accept", "application/json");
     req.send();
   },
 
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -1039,16 +1039,22 @@ uploadListener.prototype = {
                                          this.attachment.name]);
         break;
       case this.cloudProvider.uploadWouldExceedQuota:
         title = bundle.getString("errorCloudFileQuota.title");
         msg = bundle.getFormattedString("errorCloudFileQuota.message",
                                         [displayName,
                                          this.attachment.name]);
         break;
+      case this.cloudProvider.uploadExceedsFileNameLimit:
+        title = bundle.getString("errorCloudFileNameLimit.title");
+        msg = bundle.getFormattedString("errorCloudFileNameLimit.message",
+                                        [displayName,
+                                         this.attachment.name]);
+        break;
       case this.cloudProvider.uploadExceedsFileLimit:
         title = bundle.getString("errorCloudFileLimit.title");
         msg = bundle.getFormattedString("errorCloudFileLimit.message",
                                         [displayName,
                                          this.attachment.name]);
         break;
       case this.cloudProvider.uploadCanceled:
         displayError = false;
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceeds2GB.dtd
@@ -0,0 +1,6 @@
+<!-- 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/.  -->
+<!ENTITY fileExceeds2GB.title   "YouSendIt">
+<!ENTITY fileExceeds2GB.cancel "OK">
+<!ENTITY fileExceeds2GB.description "Sending files over 2GB is not supported.">
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceedsLimit.dtd
@@ -0,0 +1,13 @@
+<!-- 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/.  -->
+<!ENTITY fileExceedsLimit.title   "YouSendIt">
+<!ENTITY fileExceedsLimit.thatsBigFile   "Sending files larger than 50 MB">
+<!ENTITY fileExceedsLimit.thatsBigFile2   "is a premium feature.">
+<!ENTITY fileExceedsLimit.accept "Upgrade">
+<!ENTITY fileExceedsLimit.cancel "Cancel">
+<!ENTITY fileExceedsLimit.style "width: 40em; min-height: 20em;">
+<!ENTITY fileExceedsLimit.proIncludes "Upgrade now to send this file plus:">
+<!ENTITY fileExceedsLimit.pros1 "Send files and folders up to 2GB">
+<!ENTITY fileExceedsLimit.pros2 "Store unlimited files online">
+<!ENTITY fileExceedsLimit.pros3 "Access and share files from anywhere">
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/cloudfile/YouSendIt/fileExceedsQuota.dtd
@@ -0,0 +1,11 @@
+<!-- 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/.  -->
+<!ENTITY fileExceedsQuota.title   "YouSendIt">
+<!ENTITY fileExceedsQuota.storageLimitReached   "Storage limit reached">
+<!ENTITY fileExceedsQuota.accept "Upgrade">
+<!ENTITY fileExceedsQuota.cancel "Cancel">
+<!ENTITY fileExceedsQuota.description "You have reached your account storage limit of 2GB.">
+<!ENTITY fileExceedsQuota.description1 "Your current storage usage is #XXX GB.">
+<!ENTITY fileExceedsQuota.description2 "Upgrade today to Pro Plus account to get unlimited storage!">
+<!ENTITY fileExceedsQuota.description3 "You can also choose to delete files in your account to create more space.">
--- a/mail/locales/en-US/chrome/messenger/messengercompose/composeMsgs.properties
+++ b/mail/locales/en-US/chrome/messenger/messengercompose/composeMsgs.properties
@@ -393,16 +393,21 @@ errorCloudFileUpload.title=Upload Error
 ## %1$S is the name of the online storage service that uploading failed against.
 ## %2$S is the name of the file that failed to upload.
 errorCloudFileUpload.message=Unable to upload %2$S to %1$S.
 errorCloudFileQuota.title=Quota Error
 ## LOCALIZATION NOTE(errorCloudFileQuota.message):
 ## %1$S is the name of the online storage service being uploaded to.
 ## %2$S is the name of the file that could not be uploaded due to exceeding the storage limit.
 errorCloudFileQuota.message=Uploading %2$S to %1$S would exceed your space quota.
+errorCloudFileNameLimit.title=File Name Error
+## LOCALIZATION NOTE(errorCloudFileNameLimit.message):
+## %1$S is the name of the online storage service being uploaded to.
+## %2$S is the name of the file that could not be uploaded due to the excess file name length
+errorCloudFileNameLimit.message=Uploading %2$S to %1$S contains has more than 120 characters in its name. Please rename the file to have 120 characters or less in its name and upload again.
 errorCloudFileLimit.title=File Size Error
 ## LOCALIZATION NOTE(errorCloudFileLimit.message):
 ## %1$S is the name of the online storage service being uploaded to.
 ## %2$S is the name of the file that could not be uploaded due to size restrictions.
 errorCloudFileLimit.message=%2$S exceeds the maximum size for %1$S.
 errorCloudFileOther.title=Unknown Error
 ## LOCALIZATION NOTE(errorCloudFileOther.message):
 ## %1$S is the name of the online storage service that cannot be communicated with.
--- a/mail/locales/jar.mn
+++ b/mail/locales/jar.mn
@@ -126,16 +126,19 @@
   locale/@AB_CD@/messenger/addressbook/pref-directory-add.dtd           (%chrome/messenger/addressbook/pref-directory-add.dtd)
   locale/@AB_CD@/messenger/addressbook/replicationProgress.properties   (%chrome/messenger/addressbook/replicationProgress.properties)
   locale/@AB_CD@/messenger/cloudfile/addAccountDialog.dtd               (%chrome/messenger/cloudfile/addAccountDialog.dtd)
   locale/@AB_CD@/messenger/cloudfile/management.dtd                     (%chrome/messenger/cloudfile/management.dtd)
   locale/@AB_CD@/messenger/cloudfile/UbuntuOne/management.dtd           (%chrome/messenger/cloudfile/UbuntuOne/management.dtd)
   locale/@AB_CD@/messenger/cloudfile/UbuntuOne/settings.dtd             (%chrome/messenger/cloudfile/UbuntuOne/settings.dtd)
   locale/@AB_CD@/messenger/cloudfile/YouSendIt/management.dtd           (%chrome/messenger/cloudfile/YouSendIt/management.dtd)
   locale/@AB_CD@/messenger/cloudfile/YouSendIt/settings.dtd             (%chrome/messenger/cloudfile/YouSendIt/settings.dtd)
+  locale/@AB_CD@/messenger/cloudfile/YouSendIt/fileExceedsLimit.dtd     (%chrome/messenger/cloudfile/YouSendIt/fileExceedsLimit.dtd)
+  locale/@AB_CD@/messenger/cloudfile/YouSendIt/fileExceedsQuota.dtd     (%chrome/messenger/cloudfile/YouSendIt/fileExceedsQuota.dtd)
+  locale/@AB_CD@/messenger/cloudfile/YouSendIt/fileExceeds2GB.dtd       (%chrome/messenger/cloudfile/YouSendIt/fileExceeds2GB.dtd)
   locale/@AB_CD@/messenger/messengercompose/messengercompose.dtd        (%chrome/messenger/messengercompose/messengercompose.dtd)
   locale/@AB_CD@/messenger/messengercompose/addressingWidgetOverlay.dtd (%chrome/messenger/messengercompose/addressingWidgetOverlay.dtd)
   locale/@AB_CD@/messenger/messengercompose/askSendFormat.dtd           (%chrome/messenger/messengercompose/askSendFormat.dtd)
   locale/@AB_CD@/messenger/messengercompose/askSendFormat.properties    (%chrome/messenger/messengercompose/askSendFormat.properties)
   locale/@AB_CD@/messenger/messengercompose/sendProgress.dtd            (%chrome/messenger/messengercompose/sendProgress.dtd)
   locale/@AB_CD@/messenger/messengercompose/sendProgress.properties     (%chrome/messenger/messengercompose/sendProgress.properties)
   locale/@AB_CD@/messenger/messengercompose/composeMsgs.properties      (%chrome/messenger/messengercompose/composeMsgs.properties)
   locale/@AB_CD@/messenger/messengercompose/mailComposeEditorOverlay.dtd (%chrome/messenger/messengercompose/mailComposeEditorOverlay.dtd)
--- a/mail/test/mozmill/shared-modules/test-cloudfile-yousendit-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-cloudfile-yousendit-helpers.js
@@ -17,21 +17,21 @@ Cu.import('resource://gre/modules/Servic
 Cu.import('resource:///modules/cloudFileAccounts.js');
 
 const kDefaultServerPort = 4444;
 const kServerRoot = "http://localhost:" + kDefaultServerPort;
 const kServerPath = "";
 const kServerURL = kServerRoot + kServerPath;
 const kAuthPath = "/dpi/v1/auth";
 const kUserInfoPath = "/dpi/v2/user";
-const kFilePreparePath = "/dpi/v1/item/send";
+const kFolderPath = "/dpi/v1/folder/";
+const kFolderInitUploadPath = kFolderPath + "file/initUpload";
+const kFolderCommitUploadPath = kFolderPath + "file/commitUpload";
+const kDeletePath = kFolderPath + "file";
 const kDefaultFileUploadPath = "/uploads";
-const kCommitPath = "/dpi/v1/item/commit";
-const kDeletePath = "/dpi/v1/item";
-
 const kDownloadURLPrefix = "http://www.example.com/downloads";
 
 const kAuthResult = {
   authToken: "someAuthToken",
   errorStatus: null,
 }
 
 const kDefaultConfig = {
@@ -74,25 +74,25 @@ const kDefaultUser = {
     currentUsage: 1045,
     storageQuota: 2147483648
   },
   status: null,
   errorStatus: null,
 };
 
 const kDefaultFilePrepare = {
-  itemId: "",
+  fileId: "",
   uploadUrl: [
   ],
   status: null,
   errorStatus: null,
 }
 
 const kDefaultCommitReturn = {
-  downloadUrl: "",
+  clickableDownloadUrl: "",
   errorStatus: null,
 }
 
 function installInto(module) {
   module.MockYouSendItServer = MockYouSendItServer;
   module.MockYouSendItAuthCounter = MockYouSendItAuthCounter;
   module.MockYouSendItDeleterStaleToken = MockYouSendItDeleterStaleToken;
   module.remember_ysi_credentials = remember_ysi_credentials;
@@ -305,44 +305,76 @@ MockYouSendItItemIdRegistry.prototype = 
 function MockYouSendItPrepareSimple(aYouSendIt) {
   this._server = null;
   this._ysi = aYouSendIt;
 }
 
 MockYouSendItPrepareSimple.prototype = {
   init: function(aServer) {
     this._server = aServer;
-    this._server.registerPathHandler(kFilePreparePath,
+    this._server.registerPathHandler(kFolderInitUploadPath,
                                      this._prepare.bind(this));
+    
+    this._foldersId = {
+      root: 0,
+      Apps: this._ysi.registry.createItemId(),
+      "Mozilla Thunderbird" : this._ysi.registry.createItemId()
+    };
+    
+    // Set up folders info
+    for (let i in this._foldersId) {
+      this._server.registerPathHandler(kFolderPath + this._foldersId[i],
+                                       this._getFolderInfo.bind(this));
+    }
   },
 
   shutdown: function() {
-    this._server.registerPathHandler(kFilePreparePath, null);
+    this._server.registerPathHandler(kFolderInitUploadPath, null);
+    for (let i in this._foldersId) {
+      this._server.registerPathHandler(kFolderPath + this._foldersId[i],
+                                       null);
+    }
     this._server = null;
   },
 
+  _getFolderInfo: function(aRequest, aResponse) {
+    let folderId = aRequest.path.substring(kFolderPath.length);
+    let nextFolder = folderId == (this._foldersId.root + "")
+                        ? "Apps" 
+                        : "Mozilla Thunderbird";
+    let response = {
+      folders: {
+        folder: [{name: nextFolder, id: this._foldersId[nextFolder]}]
+      },
+      status: 200
+    }
+    aResponse.setStatusLine(null, 200, "OK");
+    aResponse.setHeader("Content-Type", "application/json");
+    aResponse.write(JSON.stringify(response));
+  },
+
   _prepare: function(aRequest, aResponse) {
-    let itemId = this._ysi.registry.createItemId();
-    let uploadPath = kDefaultFileUploadPath + "/" + itemId;
+    let fileId = this._ysi.registry.createItemId();
+    let uploadPath = kDefaultFileUploadPath + "/" + fileId;
 
     let injectedData = {
-      itemId: itemId,
+      fileId: fileId,
       uploadUrl: [
         kServerURL + uploadPath,
       ]
     }
 
     // Set up the path that will accept an uploaded file
     this._server.registerPathHandler(uploadPath,
                                      this._ysi.receiver.receiveUpload
                                                        .bind(this._ysi.receiver));
 
     // Set up the path that will accept file deletion
 
-    let deletePath = kDeletePath + "/" + itemId;
+    let deletePath = kDeletePath + "/" + fileId;
 
     this._server.registerPathHandler(deletePath,
                                      this._ysi.deleter.receiveDelete
                                                       .bind(this._ysi.deleter));
 
     let data = overrideDefault(kDefaultFilePrepare, injectedData);
     aResponse.setStatusLine(null, 200, "OK");
     aResponse.setHeader("Content-Type", "application/json");
@@ -393,17 +425,16 @@ MockYouSendItReceiverSimple.prototype = 
     Services.obs.notifyObservers(null, "cloudfile:uploadFile",
                                  filename);
 
     this._expectedFiles.splice(filenameIndex, 1);
 
     let itemId = formData['bid'];
     // Tell the committer how to map the uuid to the filename
     this._ysi.registry.setMapping(itemId, filename);
-    this._ysi.committer.expectCommit(filename);
 
     // De-register this URL...
     this._server.registerPathHandler(aRequest.path, null);
 
     if (filename in this._mSeconds) {
       let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       let timerEvent = {
         notify: function(aTimer) {
@@ -436,66 +467,64 @@ function MockYouSendItCommitterSimple(aY
   this._ysi = aYouSendIt;
   this._itemIdMap = {};
   this._filenameURLMap = {};
 }
 
 MockYouSendItCommitterSimple.prototype = {
   init: function(aServer) {
     this._server = aServer;
+    // Since fileId is in query, we need to register path only once.
+    this._server.registerPathHandler(kFolderCommitUploadPath, 
+                                     this.commit.bind(this));
   },
 
   shutdown: function() {
+    this._server.registerPathHandler(kFolderCommitUploadPath, 
+                                     null);
     this._server = null;
     this._itemIdMap = {};
     this._filenameURLMap = {};
   },
 
-  expectCommit: function(aFilename) {
-    let itemId = this._ysi.registry.lookupItemId(aFilename);
-    let commitPath = kCommitPath + "/" + itemId;
-    this._server.registerPathHandler(commitPath, this.commit.bind(this));
-  },
-
   prepareDownloadURL: function(aFilename, aURL) {
     this._filenameURLMap[aFilename] = aURL;
   },
 
   commit: function(aRequest, aResponse) {
-    let itemId = aRequest.path.substring(kCommitPath.length + 1);
+    let fileId = aRequest.queryString;
+    fileId = fileId.substring(fileId.indexOf("fileId=") + 7);
+    fileId = fileId.substring(0, fileId.indexOf("&"));
 
-    if (!this._ysi.registry.hasItemId(itemId)) {
+    if (!this._ysi.registry.hasItemId(fileId)) {
       aResponse.setStatusLine(null, 500, "Bad request");
-      aResponse.write("The item ID " + itemId + " did not map to an item we "
+      aResponse.write("The item ID " + fileId + " did not map to an item we "
                       + "were prepared for committing");
       return;
     }
 
-    let filename = this._ysi.registry.lookupFilename(itemId);
+    let filename = this._ysi.registry.lookupFilename(fileId);
     let url;
-
+    
     if (filename in this._filenameURLMap)
       url = this._filenameURLMap[filename];
     else
       url = kDownloadURLPrefix + "/" + filename;
-
+    
     let injectedData = {
-      downloadUrl: url,
+      clickableDownloadUrl: url,
     }
     let data = overrideDefault(kDefaultCommitReturn, injectedData);
-
+    
     // Return the default share URL
     aResponse.setStatusLine(null, 200, "OK");
     aResponse.setHeader("Content-Type", "application/json");
     aResponse.write(JSON.stringify(data));
-
+    
     Services.obs.notifyObservers(null, "cloudfile:getFileURL", filename);
-
-    // Unregister this commit URL
-    this._server.registerPathHandler(aRequest.path, null);
   },
 };
 
 function MockYouSendItDeleterSimple(aYouSendIt) {
   this._server = null;
   this._ysi = aYouSendIt;
   this._expectDelete = [];
 }
@@ -509,40 +538,40 @@ MockYouSendItDeleterSimple.prototype = {
   receiveDelete: function(aRequest, aResponse) {
     if (aRequest.method != "DELETE") {
       aResponse.setStatusLine(null, 500, "Bad request");
       aResponse.write("Expected a DELETE for deleting.");
       return;
     }
 
 
-    let itemId = aRequest.path.substring(kDeletePath.length + 1);
+    let fileId = aRequest.path.substring(kDeletePath.length + 1);
 
-    if (!this._ysi.registry.hasItemId(itemId)) {
+    if (!this._ysi.registry.hasItemId(fileId)) {
       aResponse.setStatusLine(null, 500, "Bad request");
-      aResponse.write("The item ID " + itemId + " did not map to an item "
+      aResponse.write("The item ID " + fileId + " did not map to an item "
                       + "we were prepared for deleting");
       return;
     }
 
-    let filename = this._ysi.registry.lookupFilename(itemId);
+    let filename = this._ysi.registry.lookupFilename(fileId);
     let itemIndex = this._expectDelete.indexOf(filename);
     if (itemIndex == -1) {
       aResponse.setStatusLine(null, 500, "Bad request");
-      aRespones.write("Not prepared to delete file with filename: "
+      aResponse.write("Not prepared to delete file with filename: "
                       + filename);
       return;
     }
 
     this._expectDelete.splice(itemIndex, 1);
 
-    let response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><delete><status>OK</status></delete>';
+    let response = {status: 200};
     aResponse.setStatusLine(null, 200, "OK");
-    aResponse.setHeader("Content-Type", "application/xml");
-    aResponse.write(response);
+    aResponse.setHeader("Content-Type", "application/json");
+    aResponse.write(JSON.stringify(response));
 
     Services.obs.notifyObservers(null, "cloudfile:deleteFile", filename);
     this._server.registerPathHandler(aRequest.path, null);
   },
   prepareForDelete: function(aFilename) {
     this._expectDelete.push(aFilename);
   },
 };
@@ -555,21 +584,21 @@ function MockYouSendItDeleterStaleToken(
 MockYouSendItDeleterStaleToken.prototype = {
   init: function(aServer) {
     this._server = aServer;
   },
 
   shutdown: function() {},
 
   receiveDelete: function(aRequest, aResponse) {
-    let data = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><delete><errorStatus><code>401</code><message>Invalid auth token</message></errorStatus></delete>';
+    let data = { errorStatus: { code: 401, message: "Invalid auth token" } };
 
-    aResponse.setStatusLine(null, 200, "OK");
+    aResponse.setStatusLine(null, 401, "Invalid auth token");
     aResponse.setHeader("Content-Type", "application/json");
-    aResponse.write(data);
+    aResponse.write(JSON.stringify(data));
   },
 
   prepareForDelete: function(aFilename) {},
 };
 
 function MockYouSendItAuthCounter(aYouSendIt) {
   this._server = null;
   this._ysi = aYouSendIt;
@@ -686,21 +715,21 @@ function parseHeaders(data, start)
 }
 
 function parseMultipartForm(request)
 {
   let boundary = null;
   // See if this is a multipart/form-data request, and if so, find the
   // boundary string
   if (request.hasHeader("Content-Type")) {
-    var contenttype = request.getHeader("Content-Type");
-    var bits = contenttype.split(";");
+    let contenttype = request.getHeader("Content-Type");
+    let bits = contenttype.split(";");
     if (bits[0] == "multipart/form-data") {
-      for (var i = 1; i < bits.length; i++) {
-        var b = bits[i].trimLeft();
+      for (let i = 1; i < bits.length; i++) {
+        let b = bits[i].trimLeft();
         if (b.indexOf("boundary=") == 0) {
           // grab everything after boundary=
           boundary = "--" + b.substring(9);
           break;
         }
       }
     }
   }
--- a/mail/themes/gnomestripe/jar.mn
+++ b/mail/themes/gnomestripe/jar.mn
@@ -85,16 +85,19 @@ classic.jar:
   skin/classic/messenger/addressbook/icons/contact-generic-tiny.png        (mail/addrbook/contact-generic-tiny.png)
   skin/classic/messenger/addressbook/icons/addressbook-toolbar.png         (mail/addrbook/addressbook-toolbar.png)
   skin/classic/messenger/addressbook/icons/addressbook-toolbar-small.png   (mail/addrbook/addressbook-toolbar-small.png)
   skin/classic/messenger/addressbook/icons/abcard-large.png   (mail/addrbook/abcard-large.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook.png (mail/addrbook/remote-addrbook.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook-error.png      (mail/addrbook/remote-addrbook-error.png)
   skin/classic/messenger/addressbook/icons/secure-remote-addrbook.png     (mail/addrbook/secure-remote-addrbook.png)
   skin/classic/messenger/cloudfile/addAccountDialog.css       (mail/cloudfile/addAccountDialog.css)
+  skin/classic/messenger/cloudfile/YouSendIt/settings.css               (mail/cloudfile/YouSendIt/settings.css)
+  skin/classic/messenger/cloudfile/YouSendIt/fileExceedsLimit.css       (mail/cloudfile/YouSendIt/fileExceedsLimit.css)
+  skin/classic/messenger/cloudfile/YouSendIt/check.png                  (mail/cloudfile/YouSendIt/check.png)
   skin/classic/messenger/messengercompose/messengercompose.css (mail/compose/messengercompose.css)
   skin/classic/messenger/messengercompose/editorOverlay.css    (mail/compose/editorOverlay.css)
   skin/classic/messenger/messengercompose/compose-toolbar.png  (mail/compose/compose-toolbar.png)
   skin/classic/messenger/messengercompose/compose-toolbar-small.png   (mail/compose/compose-toolbar-small.png)
   skin/classic/messenger/messengercompose/format-buttons.png  (mail/compose/format-buttons.png)
 % skin messenger-newsblog classic/1.0 %skin/classic/messenger-newsblog/
   skin/classic/messenger-newsblog/feed-subscriptions.css      (mail/newsblog/feed-subscriptions.css)
   skin/classic/messenger-newsblog/icons/rss-feed.png          (mail/newsblog/rss-feed.png)
new file mode 100644
--- /dev/null
+++ b/mail/themes/gnomestripe/mail/cloudfile/YouSendIt/fileExceedsLimit.css
@@ -0,0 +1,36 @@
+/* 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/. */
+
+html, body {
+  font: message-box;
+  margin: 0;
+}
+
+#fileExceedsLimit {
+  padding-left: 15px;
+  padding-right: 13px;
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+
+#proIncludes {
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+#title {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+}
+
+#title2 {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+  margin-top: -10px;
+  margin-bottom: 10px;
+}
+
+description {
+  font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
+}
new file mode 100644
--- /dev/null
+++ b/mail/themes/gnomestripe/mail/cloudfile/YouSendIt/settings.css
@@ -0,0 +1,9 @@
+/* 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/. */
+
+#username.hint {
+  color: gray;
+  font-style:italic;
+  font-size:95%
+}
--- a/mail/themes/pinstripe/jar.mn
+++ b/mail/themes/pinstripe/jar.mn
@@ -78,16 +78,19 @@ classic.jar:
   skin/classic/messenger/addressbook/icons/addressbook-toolbar.png         (mail/addrbook/addressbook-toolbar.png)
   skin/classic/messenger/addressbook/icons/abcard.png            (mail/addrbook/abcard.png)
   skin/classic/messenger/addressbook/icons/ablist.png            (mail/addrbook/ablist.png)
   skin/classic/messenger/addressbook/icons/addrbook.png          (mail/addrbook/addrbook.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook-error.png      (mail/addrbook/remote-addrbook-error.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook.png   (mail/addrbook/remote-addrbook.png)
   skin/classic/messenger/addressbook/icons/secure-remote-addrbook.png     (mail/addrbook/secure-remote-addrbook.png)
   skin/classic/messenger/cloudfile/addAccountDialog.css          (mail/cloudfile/addAccountDialog.css)
+  skin/classic/messenger/cloudfile/YouSendIt/settings.css               (mail/cloudfile/YouSendIt/settings.css)
+  skin/classic/messenger/cloudfile/YouSendIt/fileExceedsLimit.css       (mail/cloudfile/YouSendIt/fileExceedsLimit.css)
+  skin/classic/messenger/cloudfile/YouSendIt/check.png                  (mail/cloudfile/YouSendIt/check.png)
   skin/classic/messenger/messengercompose/messengercompose.css    (mail/compose/messengercompose.css)
   skin/classic/messenger/messengercompose/attachmentnotification.png     (mail/compose/attachmentnotification.png)
   skin/classic/messenger/messengercompose/compose-toolbar.png     (mail/compose/compose-toolbar.png)
   skin/classic/messenger/messengercompose/emoticon_cool.png       (mail/compose/emoticon_cool.png)
   skin/classic/messenger/messengercompose/emoticon_cry.png        (mail/compose/emoticon_cry.png)
   skin/classic/messenger/messengercompose/emoticon_embarrassed.png         (mail/compose/emoticon_embarrassed.png)
   skin/classic/messenger/messengercompose/emoticon_foot_in_mouth.png       (mail/compose/emoticon_foot_in_mouth.png)
   skin/classic/messenger/messengercompose/emoticon_frown.png      (mail/compose/emoticon_frown.png)
new file mode 100644
--- /dev/null
+++ b/mail/themes/pinstripe/mail/cloudfile/YouSendIt/fileExceedsLimit.css
@@ -0,0 +1,36 @@
+/* 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/. */
+
+html, body {
+  font: message-box;
+  margin: 0;
+}
+
+#fileExceedsLimit {
+  padding-left: 15px;
+  padding-right: 13px;
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+
+#proIncludes {
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+#title {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+}
+
+#title2 {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+  margin-top: -10px;
+  margin-bottom: 10px;
+}
+
+description {
+  font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
+}
new file mode 100644
--- /dev/null
+++ b/mail/themes/pinstripe/mail/cloudfile/YouSendIt/settings.css
@@ -0,0 +1,9 @@
+/* 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/. */
+
+#username.hint {
+  color: gray;
+  font-style:italic;
+  font-size:95%
+}
--- a/mail/themes/qute/jar.mn
+++ b/mail/themes/qute/jar.mn
@@ -119,16 +119,19 @@ classic.jar:
   skin/classic/messenger/addressbook/icons/contact-generic-tiny.png        (mail/addrbook/contact-generic-tiny.png)
   skin/classic/messenger/addressbook/icons/addressbook-toolbar.png         (mail/addrbook/addressbook-toolbar.png)
   skin/classic/messenger/addressbook/icons/addressbook-toolbar-small.png   (mail/addrbook/addressbook-toolbar-small.png)
   skin/classic/messenger/addressbook/icons/abcard-large.png   (mail/addrbook/abcard-large.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook.png (mail/addrbook/remote-addrbook.png)
   skin/classic/messenger/addressbook/icons/remote-addrbook-error.png      (mail/addrbook/remote-addrbook-error.png)
   skin/classic/messenger/addressbook/icons/secure-remote-addrbook.png     (mail/addrbook/secure-remote-addrbook.png)
   skin/classic/messenger/cloudfile/addAccountDialog.css       (mail/cloudfile/addAccountDialog.css)
+  skin/classic/messenger/cloudfile/YouSendIt/settings.css               (mail/cloudfile/YouSendIt/settings.css)
+  skin/classic/messenger/cloudfile/YouSendIt/fileExceedsLimit.css       (mail/cloudfile/YouSendIt/fileExceedsLimit.css)
+  skin/classic/messenger/cloudfile/YouSendIt/check.png                  (mail/cloudfile/YouSendIt/check.png)
   skin/classic/messenger/messengercompose/messengercompose.css (mail/compose/messengercompose.css)
   skin/classic/messenger/messengercompose/compose-toolbar.png  (mail/compose/compose-toolbar.png)
   skin/classic/messenger/messengercompose/compose-toolbar-small.png   (mail/compose/compose-toolbar-small.png)
   skin/classic/messenger/messengercompose/format-buttons.png  (mail/compose/format-buttons.png)
   skin/classic/messenger/preferences/alwaysAsk.png            (mail/preferences/alwaysAsk.png)
   skin/classic/messenger/preferences/application.png          (mail/preferences/application.png)
   skin/classic/messenger/preferences/preferences.css          (mail/preferences/preferences.css)
   skin/classic/messenger/preferences/general.png              (mail/preferences/general.png)
@@ -365,16 +368,19 @@ classic.jar:
   skin/classic/aero/messenger/addressbook/icons/contact-generic.png             (mail/addrbook/contact-generic.png)
   skin/classic/aero/messenger/addressbook/icons/contact-generic-tiny.png        (mail/addrbook/contact-generic-tiny.png)
   skin/classic/aero/messenger/addressbook/icons/addressbook-toolbar.png         (mail/addrbook/addressbook-toolbar-aero.png)
   skin/classic/aero/messenger/addressbook/icons/abcard-large.png   (mail/addrbook/abcard-large.png)
   skin/classic/aero/messenger/addressbook/icons/remote-addrbook.png (mail/addrbook/remote-addrbook-aero.png)
   skin/classic/aero/messenger/addressbook/icons/remote-addrbook-error.png      (mail/addrbook/remote-addrbook-error.png)
   skin/classic/aero/messenger/addressbook/icons/secure-remote-addrbook.png     (mail/addrbook/secure-remote-addrbook-aero.png)
 * skin/classic/aero/messenger/cloudfile/addAccountDialog.css       (mail/cloudfile/addAccountDialog-aero.css)
+  skin/classic/aero/messenger/cloudfile/YouSendIt/settings.css               (mail/cloudfile/YouSendIt/settings.css)
+  skin/classic/aero/messenger/cloudfile/YouSendIt/fileExceedsLimit.css       (mail/cloudfile/YouSendIt/fileExceedsLimit.css)
+  skin/classic/aero/messenger/cloudfile/YouSendIt/check.png                  (mail/cloudfile/YouSendIt/check.png)
   skin/classic/aero/messenger/messengercompose/messengercompose.css (mail/compose/messengercompose-aero.css)
   skin/classic/aero/messenger/messengercompose/compose-toolbar.png  (mail/compose/compose-toolbar-aero.png)
   skin/classic/aero/messenger/messengercompose/format-buttons.png  (mail/compose/format-buttons-aero.png)
   skin/classic/aero/messenger/preferences/alwaysAsk.png            (mail/preferences/alwaysAsk.png)
   skin/classic/aero/messenger/preferences/application.png          (mail/preferences/application.png)
 * skin/classic/aero/messenger/preferences/preferences.css          (mail/preferences/preferences-aero.css)
   skin/classic/aero/messenger/preferences/general.png              (mail/preferences/general-aero.png)
   skin/classic/aero/messenger/preferences/display.png              (mail/preferences/display-aero.png)
new file mode 100644
--- /dev/null
+++ b/mail/themes/qute/mail/cloudfile/YouSendIt/fileExceedsLimit.css
@@ -0,0 +1,36 @@
+/* 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/. */
+
+html, body {
+  font: message-box;
+  margin: 0;
+}
+
+#fileExceedsLimit {
+  padding-left: 15px;
+  padding-right: 13px;
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+
+#proIncludes {
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+#title {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+}
+
+#title2 {
+  font-size: 20pt;
+  color: rgb(141,198,63);
+  margin-top: -10px;
+  margin-bottom: 10px;
+}
+
+description {
+  font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
+}
new file mode 100644
--- /dev/null
+++ b/mail/themes/qute/mail/cloudfile/YouSendIt/settings.css
@@ -0,0 +1,9 @@
+/* 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/. */
+
+#username.hint {
+  color: gray;
+  font-style:italic;
+  font-size:95%
+}