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 12060 ee9bf9095b6e5fd4528680448292ac52f7a39d06
parent 12059 8c820d9d26126b9e3aa0a999e0ce789659dfacf5
child 12061 4468b7bdbd889e79fee38891075804ff2735530e
push idunknown
push userunknown
push dateunknown
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%
+}