make copy local messages check the size of the messages to be copied to make sure they won't make the folder exceed the 4GB limit, r=bienvenu,sr=neil 387502
authorchiaki ishikawa <ishikawa@yk.rim.or.jp>
Thu, 06 Aug 2009 14:40:44 -0700
changeset 3247 ee6e556064d0a485d771261b5ee51450f7948768
parent 3246 4344cc9a28a79af2fa2ef41eafa97cb3ba840891
child 3248 516661265fc83bdcc5279c3aaf89654ce350d666
push idunknown
push userunknown
push dateunknown
reviewersbienvenu, neil
bugs387502
make copy local messages check the size of the messages to be copied to make sure they won't make the folder exceed the 4GB limit, r=bienvenu,sr=neil 387502
mailnews/local/src/nsLocalMailFolder.cpp
--- a/mailnews/local/src/nsLocalMailFolder.cpp
+++ b/mailnews/local/src/nsLocalMailFolder.cpp
@@ -1412,16 +1412,18 @@ NS_IMETHODIMP nsMsgLocalMailFolder::GetS
   nsresult rv = NS_OK;
   if (!mFolderSize)
   {
     nsCOMPtr <nsILocalFile> file;
     rv = GetFilePath(getter_AddRefs(file));
     NS_ENSURE_SUCCESS(rv, rv);
     PRInt64 folderSize;
     rv = file->GetFileSize(&folderSize);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     mFolderSize = (PRUint32) folderSize;
   }
   *aSize = mFolderSize;
   return rv;
 }
 
 nsresult
 nsMsgLocalMailFolder::GetTrashFolder(nsIMsgFolder** result)
@@ -1656,64 +1658,82 @@ nsMsgLocalMailFolder::CopyMessages(nsIMs
   if (NS_SUCCEEDED(rv) && isServer)
   {
     NS_ASSERTION(0, "Destination is the root folder. Cannot move/copy here");
     if (isMove)
       srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
     return OnCopyCompleted(srcSupport, PR_FALSE);
   }
 
-  PRBool mailboxTooLarge;
-
-  (void) WarnIfLocalFileTooBig(msgWindow, &mailboxTooLarge);
-  if (mailboxTooLarge)
-  {
-    if (isMove)
-      srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
-    return OnCopyCompleted(srcSupport, PR_FALSE);
-  }
-
   if (!(mFlags & (nsMsgFolderFlags::Trash|nsMsgFolderFlags::Junk)))
     SetMRUTime();
 
   nsCString protocolType;
   rv = srcFolder->GetURI(protocolType);
   protocolType.SetLength(protocolType.FindChar(':'));
 
 #ifdef MOZILLA_INTERNAL_API
-  if (WeAreOffline() && (protocolType.LowerCaseEqualsLiteral("imap") || 
-                         protocolType.LowerCaseEqualsLiteral("news")))
+  PRBool needOfflineBody = (WeAreOffline() &&
+    (protocolType.LowerCaseEqualsLiteral("imap") ||
+     protocolType.LowerCaseEqualsLiteral("news")));
 #else
-  if (WeAreOffline() && (protocolType.Equals("imap", CaseInsensitiveCompare) || 
-                         protocolType.Equals("news", CaseInsensitiveCompare)))
+  PRBool needOfflineBody  = (WeAreOffline() &&
+    (protocolType.Equals("imap", CaseInsensitiveCompare) ||
+     protocolType.Equals("news", CaseInsensitiveCompare)));
 #endif
+  PRInt64 totalMsgSize = 0;
+  PRUint32 numMessages = 0;
+  messages->GetLength(&numMessages);
+  for (PRUint32 i = 0; i < numMessages; i++)
   {
-    PRUint32 numMessages = 0;
-    messages->GetLength(&numMessages);
-    for (PRUint32 i = 0; i < numMessages; i++)
+    nsCOMPtr<nsIMsgDBHdr> message(do_QueryElementAt(messages, i, &rv));
+    if (NS_SUCCEEDED(rv) && message)
     {
-      nsCOMPtr<nsIMsgDBHdr> message;
-      messages->QueryElementAt(i, NS_GET_IID(nsIMsgDBHdr),(void **)getter_AddRefs(message));
-      if(NS_SUCCEEDED(rv) && message)
+      nsMsgKey key;
+      PRUint32 msgSize;
+      message->GetMessageSize(&msgSize);
+
+      /* 200 is a per-message overhead to account for any extra data added
+         to the message.
+      */
+      totalMsgSize += msgSize + 200;
+
+      if (needOfflineBody)
       {
-        nsMsgKey key;
         PRBool hasMsgOffline = PR_FALSE;
         message->GetMessageKey(&key);
         srcFolder->HasMsgOffline(key, &hasMsgOffline);
         if (!hasMsgOffline)
         {
           if (isMove)
             srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
           ThrowAlertMsg("cantMoveMsgWOBodyOffline", msgWindow);
           return OnCopyCompleted(srcSupport, PR_FALSE);
         }
       }
     }
   }
 
+  PRInt64 sizeOnDisk;
+
+  nsCOMPtr <nsILocalFile> filePath;
+  rv = GetFilePath(getter_AddRefs(filePath));
+  if (NS_SUCCEEDED(rv))
+    rv = filePath->GetFileSize(&sizeOnDisk);
+
+  // check if the folder size + the size of the messages will be > 4GB or so.
+  // If so, warn, and return an error.
+  if (NS_FAILED(rv) || sizeOnDisk + totalMsgSize > 0xFFC00000)
+  {
+    ThrowAlertMsg("mailboxTooLarge", msgWindow);
+    if (isMove)
+      srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
+    return OnCopyCompleted(srcSupport, PR_FALSE);
+  }
+
   // don't update the counts in the dest folder until it is all over
   EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_FALSE /*dbBatching*/);  //dest folder doesn't need db batching
 
   // sort the message array by key
   PRUint32 numMsgs = 0;
   messages->GetLength(&numMsgs);
   nsTArray<nsMsgKey> keyArray(numMsgs);
   if (numMsgs > 1)
@@ -3834,16 +3854,21 @@ nsMsgLocalMailFolder::WarnIfLocalFileToo
     const nsInt64 kMaxFolderSize = 0xFFF00000;
     nsInt64 folderSize(sizeOnDisk);
     if (folderSize > kMaxFolderSize)
     {
       ThrowAlertMsg("mailboxTooLarge", aWindow);
       *aTooBig = PR_TRUE;
     }
   }
+  else
+  {
+      // We are failing to obtain the size in the first place!
+      NS_ERROR( "WarnIfLocalFileTooBig: call to GetFileSize failed");
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgLocalMailFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
                                                  PRBool aLocalOnly, nsIUrlListener *aUrlListener,
                                                  PRBool *aAsyncResults)
 {
   NS_ENSURE_ARG_POINTER(aKeysToFetch);