Bug 195702 - attachment size should be visible in compose window; r=protz sr=bienvenu ui-r=clarkbw
☠☠ backed out by c785aae4b1d1 ☠ ☠
authorJim <squibblyflabbetydoo@gmail.com>
Fri, 19 Nov 2010 11:19:49 +0000
changeset 6723 212f044b3d861061eaff12ffa89edea9e81a9a7b
parent 6722 8fe26f626337650104b7b9503409690226b1efdf
child 6724 1b341754e61ea5850cac47bd1c00c3a62f613bec
push idunknown
push userunknown
push dateunknown
reviewersprotz, bienvenu, clarkbw
bugs195702
Bug 195702 - attachment size should be visible in compose window; r=protz sr=bienvenu ui-r=clarkbw
mail/base/content/msgHdrViewOverlay.js
mail/components/compose/content/MsgComposeCommands.js
mail/test/mozmill/composition/test-attachment.js
mail/test/mozmill/shared-modules/test-compose-helpers.js
mailnews/compose/public/nsIMsgAttachment.idl
mailnews/compose/src/nsMsgAttachment.cpp
mailnews/compose/src/nsMsgAttachment.h
mailnews/mime/src/mimedrft.cpp
--- a/mail/base/content/msgHdrViewOverlay.js
+++ b/mail/base/content/msgHdrViewOverlay.js
@@ -2191,17 +2191,17 @@ var attachmentAreaDNDObserver = {
         return;
 
       var data = new TransferData();
       if (attachment.url && attachment.displayName)
       {
         var info = attachment.url + "&type=" + attachment.contentType +
                    "&filename=" + encodeURIComponent(attachment.displayName);
         data.addDataForFlavour("text/x-moz-url",
-                               info + "\n" + attachment.displayName);
+                               info + "\n" + attachment.displayName + "\n" + attachment.size);
         data.addDataForFlavour("text/x-moz-url-data", attachment.url);
         data.addDataForFlavour("text/x-moz-url-desc", attachment.displayName);
         data.addDataForFlavour("application/x-moz-file-promise-url",
                                attachment.url);
         data.addDataForFlavour("application/x-moz-file-promise",
                                new nsFlavorDataProvider(), 0,
                                Components.interfaces.nsISupports);
       }
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -63,16 +63,19 @@ var sDictCount = 0;
 
 /* Create message window object. This is use by mail-offline.js and therefore should not be renamed. We need to avoid doing
    this kind of cross file global stuff in the future and instead pass this object as parameter when needed by function
    in the other js file.
 */
 var msgWindow = Components.classes["@mozilla.org/messenger/msgwindow;1"]
                           .createInstance(Components.interfaces.nsIMsgWindow);
 
+var gMessenger = Components.classes["@mozilla.org/messenger;1"]
+                           .createInstance(Components.interfaces.nsIMessenger)
+
 /**
  * Global variables, need to be re-initialized every time mostly because we need to release them when the window close
  */
 var gHideMenus;
 var gMsgCompose;
 var gAccountManager;
 var gIOService;
 var gPromptService;
@@ -2864,16 +2867,17 @@ function AddFileAttachment(file)
   var fileHandler = Components.classes["@mozilla.org/network/io-service;1"]
                               .getService(Components.interfaces.nsIIOService)
                               .getProtocolHandler("file")
                               .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
   var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"]
                              .createInstance(Components.interfaces.nsIMsgAttachment);
 
   attachment.url = fileHandler.getURLSpecFromFile(file);
+  attachment.size = file.fileSize;
   AddUrlAttachment(attachment);
 }
 
 /**
  * Add an attachment object as attachment. The attachment URL must be set.
  * @param attachment the nsIMsgAttachment object to add as attachment
  */
 function AddUrlAttachment(attachment)
@@ -2892,25 +2896,30 @@ function AddUrlAttachment(attachment)
   // or hostname.
   if (/^mailbox-message:|^imap-message:|^news-message:/i.test(attachment.name))
     attachment.name = bundle.getString("messageAttachmentSafeName");
   // Don't allow file or mail/news protocol uris to leak out either.
   else if (/^file:|^mailbox:|^imap:|^s?news:/i.test(attachment.name))
     attachment.name = bundle.getString("partAttachmentSafeName");
 
   var bucket = document.getElementById("attachmentBucket");
-  var item = bucket.appendItem(attachment.name, "");
+  var nameAndSize = attachment.name;
+  if (attachment.size != -1)
+    nameAndSize += " ("+gMessenger.formatFileSize(attachment.size)+")";
+  var item = bucket.appendItem(nameAndSize, "");
+
   item.attachment = attachment; // Full attachment object stored here.
   try {
     item.setAttribute("tooltiptext", decodeURI(attachment.url));
   }
   catch(e) {
     item.setAttribute("tooltiptext", attachment.url);
   }
   item.setAttribute("class", "listitem-iconic");
+  item.setAttribute("crop", "center");
 
   // For local file urls, we are better off using the full file url because
   // moz-icon will actually resolve the file url and get the right icon from
   // the file url. All other urls, we should try to extract the file name from
   // them. This fixes issues were an icon wasn't showing up if you dragged a
   // web url that had a query or reference string after the file name and for
   // mailnews urls were the filename is hidden in the url as a &filename= part.
   var url = gIOService.newURI(attachment.url, null, null);
@@ -3087,19 +3096,17 @@ function OpenSelectedAttachment()
   if (bucket.selectedItems.length == 1)
   {
     var attachmentUrl = bucket.getSelectedItem(0).attachment.url;
 
     var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
     if (messagePrefix.test(attachmentUrl))
     {
       // we must be dealing with a forwarded attachment, treat this special
-      var messenger = Components.classes["@mozilla.org/messenger;1"].createInstance();
-      messenger = messenger.QueryInterface(Components.interfaces.nsIMessenger);
-      var msgHdr = messenger.messageServiceFromURI(attachmentUrl).messageURIToMsgHdr(attachmentUrl);
+      var msgHdr = gMessenger.messageServiceFromURI(attachmentUrl).messageURIToMsgHdr(attachmentUrl);
       if (msgHdr)
         MailUtils.openMessageInNewWindow(msgHdr);
     }
     else
     {
       // turn the url into a nsIURL object then open it
 
       var url = gIOService.newURI(attachmentUrl, null, null);
@@ -3463,40 +3470,48 @@ var envelopeDragObserver = {
       var errorTitle;
       var attachment;
       var errorMsg;
 
       for (let i = 0; i < dataListLength; i++)
       {
         var item = dataList[i].first;
         var prettyName;
+        var size;
         var rawData = item.data;
 
         // We could be dropping an attachment OR an address, check and do the right thing..
 
         if (item.flavour.contentType == "text/x-moz-url" ||
             item.flavour.contentType == "text/x-moz-message" ||
             item.flavour.contentType == "application/x-moz-file")
         {
           if (item.flavour.contentType == "application/x-moz-file")
           {
             var fileHandler = Components.classes["@mozilla.org/network/io-service;1"]
                                         .getService(Components.interfaces.nsIIOService)
                                         .getProtocolHandler("file")
                                         .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
+
+            size = rawData.fileSize;
             rawData = fileHandler.getURLSpecFromFile(rawData);
           }
+          else if (item.flavour.contentType == "text/x-moz-message")
+          {
+            size = gMessenger.messageServiceFromURI(rawData)
+                             .messageURIToMsgHdr(rawData).messageSize;
+          }
           else
           {
-            var separator = rawData.indexOf("\n");
-            if (separator != -1)
-            {
-              prettyName = rawData.substr(separator+1);
-              rawData = rawData.substr(0,separator);
-            }
+            var pieces = rawData.split("\n");
+            rawData = pieces[0];
+            if (pieces.length > 1)
+              prettyName = pieces[1];
+            if (pieces.length > 2)
+              size = parseInt(pieces[2]);
           }
 
           if (DuplicateFileAlreadyAttached(rawData))
           {
             dump("Skipping file "+rawData+"; already attached!\n");
           }
           else
           {
@@ -3520,16 +3535,18 @@ var envelopeDragObserver = {
               }
             }
 
             if (isValid) {
               attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"]
                                      .createInstance(Components.interfaces.nsIMsgAttachment);
               attachment.url = rawData;
               attachment.name = prettyName;
+              if (size !== undefined)
+                attachment.size = size;
               AddUrlAttachment(attachment);
             }
           }
         }
         else if (item.flavour.contentType == "text/x-moz-address")
         {
           // process the address
           if (rawData)
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/composition/test-attachment.js
@@ -0,0 +1,181 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Messaging.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jim Porter <jvporter@wisc.edu>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cu = Components.utils;
+
+var MODULE_NAME = 'test-attachment';
+
+var RELATIVE_ROOT = '../shared-modules';
+var MODULE_REQUIRES = ['folder-display-helpers', 'compose-helpers',
+                       'window-helpers'];
+
+var messenger;
+var folder;
+var epsilon;
+
+const rawAttachment =
+  "Can't make the frug contest, Helen; stomach's upset. I'll fix you, " +
+  "Ubik! Ubik drops you back in the thick of things fast. Taken as " +
+  "directed, Ubik speeds relief to head and stomach. Remember: Ubik is " +
+  "only seconds away. Avoid prolonged use.";
+
+const b64Attachment =
+  'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAAlwS' +
+  'FlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAA' +
+  'A5SURBVCiRY/z//z8DKYCJJNXkaGBgYGD4D8NQ5zUgiTVAxeBqSLaBkVRPM0KtIhrQ3km0jwe' +
+  'SNQAAlmAY+71EgFoAAAAASUVORK5CYII=';
+const b64Size = 188;
+
+function setupModule(module) {
+  let fdh = collector.getModule('folder-display-helpers');
+  fdh.installInto(module);
+  let ch = collector.getModule("compose-helpers");
+  ch.installInto(module);
+  let wh = collector.getModule('window-helpers');
+  wh.installInto(module);
+
+  folder = create_folder('ComposeAttachmentA');
+
+  messenger = Components.classes['@mozilla.org/messenger;1']
+                        .createInstance(Components.interfaces.nsIMessenger);
+
+  /* Today's gory details (thanks to Jonathan Protzenko): libmime somehow
+   * counts the trailing newline for an attachment MIME part. Most of the time,
+   * assuming attachment has N bytes (no matter what's inside, newlines or
+   * not), libmime will return N + 1 bytes. On Linux and Mac, this always
+   * holds. However, on Windows, if the attachment is not encoded (that is, is
+   * inline text), libmime will return N + 2 bytes. Since we're dealing with
+   * forwarded message data here, the bonus byte(s) appear twice.
+   */
+  epsilon = ('@mozilla.org/windows-registry-key;1' in Components.classes) ? 4 : 2;
+
+  // create some messages that have various types of attachments
+  let messages = [
+    // raw attachment
+    { attachments: [{ body: rawAttachment,
+                      filename: 'ubik.txt',
+                      format: '' }]},
+    // b64-encoded image attachment
+    { attachments: [{ body: b64Attachment,
+                      contentType: 'image/png',
+                      filename: 'lines.png',
+                      encoding: 'base64',
+                      format: '' }]},
+    ];
+
+  for (let i=0; i<messages.length; i++) {
+    add_message_to_folder(folder, create_message(messages[i]));
+  }
+}
+
+/**
+ * Make sure that the attachment's size is what we expect
+ * @param controller the controller for the compose window
+ * @param expectedSize the expected size of the attachment, in bytes
+ */
+function check_attachment_size(controller, expectedSize) {
+  let node = controller.e('attachmentBucket', {tagName: 'listitem'});
+
+  // First, let's check that the 'attachmentSize' attribute is correct
+  let size = node.attachment.size;
+  if (Math.abs(size - expectedSize) > epsilon)
+    throw new Error('Reported attachment size ('+size+') not within epsilon ' +
+                    'of actual attachment size ('+expectedSize+')');
+
+  // Next, make sure that the formatted size in the label is correct
+  let formattedSize = /\((.*?)\)$/.exec(node.getAttribute('label'))[1];
+  let expectedFormattedSize = messenger.formatFileSize(size);
+  if (formattedSize != expectedFormattedSize)
+    throw new Error('Formatted attachment size ('+formattedSize+') does not ' +
+                    'match expected value ('+expectedFormattedSize+')');
+}
+
+/**
+ * Make sure that the attachment's size is not displayed
+ * @param controller the controller for the compose window
+ */
+function check_no_attachment_size(controller) {
+  let node = controller.e('attachmentBucket', {tagName: 'listitem'});
+
+  if (node.attachment.size != -1)
+    throw new Error('attachment.size attribute should be -1!');
+
+  if (/\((.*?)\)$/.exec(node.getAttribute('label')))
+    throw new Error('Attachment size should not be displayed!');
+}
+
+function test_file_attachment() {
+  let cwc = open_compose_new_mail();
+  let attachment = Cc["@mozilla.org/messengercompose/attachment;1"]
+                     .createInstance(Ci.nsIMsgAttachment);
+  attachment.url = "file:///some/file/here.txt";
+
+  attachment.size = 1234;
+  add_attachment(cwc, attachment);
+  check_attachment_size(cwc, attachment.size);
+}
+
+function test_webpage_attachment() {
+  let cwc = open_compose_new_mail();
+  let attachment = Cc["@mozilla.org/messengercompose/attachment;1"]
+                     .createInstance(Ci.nsIMsgAttachment);
+  attachment.url = "http://www.mozillamessaging.com/";
+
+  add_attachment(cwc, attachment);
+  check_no_attachment_size(cwc, attachment);
+}
+
+function test_forward_raw_attachment() {
+  be_in_folder(folder);
+  let curMessage = select_click_row(0);
+
+  let cwc = open_compose_with_forward();
+  check_attachment_size(cwc, rawAttachment.length);
+}
+
+function test_forward_b64_attachment() {
+  be_in_folder(folder);
+  let curMessage = select_click_row(1);
+
+  let cwc = open_compose_with_forward();
+  check_attachment_size(cwc, b64Size);
+}
+
+// XXX: Test attached emails and files pulled from other emails (this probably
+// requires better drag-and-drop support from Mozmill)
--- a/mail/test/mozmill/shared-modules/test-compose-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-compose-helpers.js
@@ -67,16 +67,17 @@ function installInto(module) {
   // Now copy helper functions
   module.open_compose_new_mail = open_compose_new_mail;
   module.open_compose_with_reply = open_compose_with_reply;
   module.open_compose_with_reply_to_list = open_compose_with_reply_to_list;
   module.open_compose_with_forward = open_compose_with_forward;
   module.open_compose_with_forward_as_attachments = open_compose_with_forward_as_attachments;
   module.open_compose_with_element_click = open_compose_with_element_click;
   module.close_compose_window = close_compose_window;
+  module.add_attachment = add_attachment;
 }
 
 /**
  * Opens the compose window by starting a new message
  *
  * @return The loaded window of type "msgcompose" wrapped in a MozmillController
  *         that is augmented using augment_controller.
  */
@@ -235,8 +236,18 @@ function wait_for_compose_window(aContro
   // need to have a little longer to try and load the initial data.
   // As I can't see a simpler way at the moment, we'll just have to make it a
   // sleep :-(
 
   aController.sleep(1000);
 
   return replyWindow;
 }
+
+/**
+ * Add an attachment to the compose window
+ * @param aComposeWindow the composition window in question
+ * @param aAttachment the nsIMsgAttachment object containing the attachment's
+ *        info
+ */
+function add_attachment(aComposeWindow, aAttachment) {
+  aComposeWindow.window.AddUrlAttachment(aAttachment);
+}
--- a/mailnews/compose/public/nsIMsgAttachment.idl
+++ b/mailnews/compose/public/nsIMsgAttachment.idl
@@ -32,17 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(98f03f72-8b29-4c49-8975-b45fc08a6a82)]
+[scriptable, uuid(908a8090-cce4-11df-bd3b-0800200c9a66)]
 interface nsIMsgAttachment : nsISupports {
 
   /**
    * name attribute
    *
    * @Attachment real name, will be sent with the attachment's header.
    * @If no name has been provided, a name will be generated using the url.
    */
@@ -99,17 +99,24 @@ interface nsIMsgAttachment : nsISupports
   /**
    * charset attribute
    *
    * @Specify the charset of the attachment. It will be added to the content-type during the
    * @send/save operation
    * @If omitted, will be determined automatically (if possible).
    */
   attribute string    charset;
-  
+
+  /**
+   * size attribute
+   *
+   * @Specify the size of the attachment.
+   */
+  attribute PRInt64   size;
+
   /**
    * macType attribute
    *
    * @Specify the Mac file type of the attachment. It will be added to the content-type during the
    * @send/save operation
    * @If omitted, will be determined automatically on Macintosh OS.
    */
   attribute string    macType;
--- a/mailnews/compose/src/nsMsgAttachment.cpp
+++ b/mailnews/compose/src/nsMsgAttachment.cpp
@@ -39,16 +39,17 @@
 #include "nsILocalFile.h"
 #include "nsNetUtil.h"
 
 NS_IMPL_ISUPPORTS1(nsMsgAttachment, nsIMsgAttachment)
 
 nsMsgAttachment::nsMsgAttachment()
 {
   mTemporary = PR_FALSE;
+  mSize = -1;
 }
 
 nsMsgAttachment::~nsMsgAttachment()
 {
   if (mTemporary)
     (void)DeleteAttachment();
 }
 
@@ -194,16 +195,30 @@ NS_IMETHODIMP nsMsgAttachment::GetMacCre
   return (*aMacCreator ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
 }
 NS_IMETHODIMP nsMsgAttachment::SetMacCreator(const char * aMacCreator)
 {
   mMacCreator = aMacCreator;
   return NS_OK;
 }
 
+/* attribute PRInt64 size; */
+NS_IMETHODIMP nsMsgAttachment::GetSize(PRInt64 *aSize)
+{
+  NS_ENSURE_ARG_POINTER(aSize);
+
+  *aSize = mSize;
+  return NS_OK;
+}
+NS_IMETHODIMP nsMsgAttachment::SetSize(PRInt64 aSize)
+{
+  mSize = aSize;
+  return NS_OK;
+}
+
 /* boolean equalsUrl (in nsIMsgAttachment attachment); */
 NS_IMETHODIMP nsMsgAttachment::EqualsUrl(nsIMsgAttachment *attachment, PRBool *_retval)
 {
   NS_ENSURE_ARG_POINTER(attachment);
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsCAutoString url;
   attachment->GetUrl(url);
--- a/mailnews/compose/src/nsMsgAttachment.h
+++ b/mailnews/compose/src/nsMsgAttachment.h
@@ -58,12 +58,13 @@ private:
   nsCString   mUrlCharset;
   PRBool      mTemporary;
   nsCString   mContentLocation;
   nsCString   mContentType;
   nsCString   mContentTypeParam;
   nsCString   mCharset;
   nsCString   mMacType;
   nsCString   mMacCreator;
+  PRInt64     mSize;
 };
 
 
 #endif /* _nsMsgAttachment_H_ */
--- a/mailnews/mime/src/mimedrft.cpp
+++ b/mailnews/mime/src/mimedrft.cpp
@@ -170,16 +170,17 @@ mime_dump_attachments ( nsMsgAttachmentD
     }
 
     printf("Desired Type      : %s\n", tmp->desired_type ? tmp->desired_type : "nsnull");
     printf("Real Type         : %s\n", tmp->real_type ? tmp->real_type : "nsnull");
     printf("Real Encoding     : %s\n", tmp->real_encoding ? tmp->real_encoding : "nsnull");
     printf("Description       : %s\n", tmp->description ? tmp->description : "nsnull");
     printf("Mac Type          : %s\n", tmp->x_mac_type ? tmp->x_mac_type : "nsnull");
     printf("Mac Creator       : %s\n", tmp->x_mac_creator ? tmp->x_mac_creator : "nsnull");
+    printf("Size in bytes     : %d\n", tmp->size);
     i++;
     tmp++;
   }
 }
 #endif
 
 nsresult CreateComposeParams(nsCOMPtr<nsIMsgComposeParams> &pMsgComposeParams,
                              nsIMsgCompFields * compFields,
@@ -213,16 +214,17 @@ nsresult CreateComposeParams(nsCOMPtr<ns
           if (NS_FAILED(rv))
             CopyASCIItoUTF16(nsDependentCString(curAttachment->real_name), nameStr);
           attachment->SetName(nameStr);
           attachment->SetUrl(spec);
           attachment->SetTemporary(PR_TRUE);
           attachment->SetContentType(curAttachment->real_type);
           attachment->SetMacType(curAttachment->x_mac_type);
           attachment->SetMacCreator(curAttachment->x_mac_creator);
+          attachment->SetSize(curAttachment->size);
           compFields->AddAttachment(attachment);
         }
       }
       curAttachment++;
     }
   }
 
   MSG_ComposeFormat format = composeFormat; // Format to actually use.
@@ -601,16 +603,18 @@ mime_draft_process_attachments(mime_draf
       NS_MsgSACopy ( &(tmp->x_mac_type), tmpFile->x_mac_type );
     }
 
     if ( tmpFile->x_mac_creator )
     {
       NS_MsgSACopy ( &(tmp->x_mac_creator), tmpFile->x_mac_creator );
     }
 
+    tmp->size = tmpFile->size;
+
     if (bodyAsAttachment && (i == 0))
       tmpFile = mdd->attachments;
     else
       tmpFile++;
   }
 
   return (attachData);
 
@@ -1878,16 +1882,17 @@ mime_decompose_file_init_fn ( void *stre
     if (tmp_value)
       NS_MsgSACat(&(newAttachment->type), tmp_value);
     newAttachment->x_mac_type = MimeHeaders_get_parameter(parm_value, "x-mac-type", NULL, NULL);
     newAttachment->x_mac_creator = MimeHeaders_get_parameter(parm_value, "x-mac-creator", NULL, NULL);
     PR_FREEIF(parm_value);
     PR_FREEIF(boundary);
     PR_FREEIF(tmp_value);
   }
+  newAttachment->size = 0;
   newAttachment->encoding = MimeHeaders_get ( headers, HEADER_CONTENT_TRANSFER_ENCODING,
                                               PR_FALSE, PR_FALSE );
   newAttachment->description = MimeHeaders_get( headers, HEADER_CONTENT_DESCRIPTION,
                                                 PR_FALSE, PR_FALSE );
   //
   // If we came up empty for description or the orig URL, we should do something about it.
   //
   if  ( ( (!newAttachment->description) || (!*newAttachment->description) ) && (workURLSpec) )
@@ -2006,25 +2011,28 @@ mime_decompose_file_output_fn (const cha
   NS_ASSERTION (mdd && buf, "missing mime draft data and/or buf");
   if (!mdd || !buf) return -1;
   if (!size) return NS_OK;
 
   if ( !mdd->tmpFileStream )
     return NS_OK;
 
   if (mdd->decoder_data) {
-    ret = MimeDecoderWrite(mdd->decoder_data, buf, size, nsnull);
+    PRInt32 outsize;
+    ret = MimeDecoderWrite(mdd->decoder_data, buf, size, &outsize);
     if (ret == -1) return -1;
+    mdd->curAttachment->size += outsize;
   }
   else
   {
     PRUint32 bytesWritten;
     mdd->tmpFileStream->Write(buf, size, &bytesWritten);
     if (bytesWritten < size)
       return MIME_ERROR_WRITING_FILE;
+    mdd->curAttachment->size += size;
   }
 
   return NS_OK;
 }
 
 nsresult
 mime_decompose_file_close_fn ( void *stream_closure )
 {