Back to index

lightning-sunbird  0.9+nobinonly
nsMsgCopyService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsMsgCopyService.h"
00040 #include "nsMsgKeyArray.h"
00041 #include "nsCOMArray.h"
00042 #include "nspr.h"
00043 #include "nsIFileSpec.h"
00044 #include "nsIMsgFolderNotificationService.h"
00045 #include "nsMsgBaseCID.h"
00046 
00047 // ******************** nsCopySource ******************
00048 // 
00049 
00050 MOZ_DECL_CTOR_COUNTER(nsCopySource)
00051 
00052 nsCopySource::nsCopySource() : m_processed(PR_FALSE)
00053 {
00054   MOZ_COUNT_CTOR(nsCopySource);
00055   nsresult rv;
00056   rv = NS_NewISupportsArray(getter_AddRefs(m_messageArray));
00057 }
00058 
00059 nsCopySource::nsCopySource(nsIMsgFolder* srcFolder) :
00060     m_processed(PR_FALSE)
00061 {
00062   MOZ_COUNT_CTOR(nsCopySource);
00063   nsresult rv;
00064   rv = NS_NewISupportsArray(getter_AddRefs(m_messageArray));
00065   m_msgFolder = do_QueryInterface(srcFolder, &rv);
00066 }
00067 
00068 nsCopySource::~nsCopySource()
00069 {
00070   MOZ_COUNT_DTOR(nsCopySource);
00071 }
00072 
00073 void nsCopySource::AddMessage(nsIMsgDBHdr* aMsg)
00074 {
00075        nsCOMPtr<nsISupports> supports(do_QueryInterface(aMsg));
00076        if(supports)
00077               m_messageArray->AppendElement(supports);
00078 }
00079 
00080 // ************ nsCopyRequest *****************
00081 // 
00082 
00083 MOZ_DECL_CTOR_COUNTER(nsCopyRequest)
00084 
00085 nsCopyRequest::nsCopyRequest() :
00086     m_requestType(nsCopyMessagesType),
00087     m_isMoveOrDraftOrTemplate(PR_FALSE),
00088     m_newMsgFlags(0),
00089     m_processed(PR_FALSE)
00090 {
00091   MOZ_COUNT_CTOR(nsCopyRequest);
00092 }
00093 
00094 nsCopyRequest::~nsCopyRequest()
00095 {
00096   MOZ_COUNT_DTOR(nsCopyRequest);
00097 
00098   PRInt32 j;
00099   nsCopySource* ncs;
00100   
00101   j = m_copySourceArray.Count();
00102   while(j-- > 0)
00103   {
00104       ncs = (nsCopySource*) m_copySourceArray.ElementAt(j);
00105       delete ncs;
00106   }
00107 }
00108 
00109 nsresult
00110 nsCopyRequest::Init(nsCopyRequestType type, nsISupports* aSupport,
00111                     nsIMsgFolder* dstFolder,
00112                     PRBool bVal, PRUint32 newMsgFlags, nsIMsgCopyServiceListener* listener,
00113                     nsIMsgWindow* msgWindow, PRBool allowUndo)
00114 {
00115   nsresult rv = NS_OK;
00116   m_requestType = type;
00117   m_srcSupport = aSupport;
00118   m_dstFolder = dstFolder;
00119   m_isMoveOrDraftOrTemplate = bVal;
00120   m_allowUndo = allowUndo;
00121   m_newMsgFlags = newMsgFlags;
00122   if (listener)
00123       m_listener = listener;
00124   if (msgWindow)
00125   {
00126     m_msgWindow = msgWindow;
00127     if (m_allowUndo)
00128                      msgWindow->GetTransactionManager(getter_AddRefs(m_txnMgr));
00129        }
00130   if (type == nsCopyFoldersType)
00131   {
00132     // To support multiple copy folder operations to the same destination, we 
00133     // need to save the leaf name of the src file spec so that FindRequest() is
00134     // able to find the right request when copy finishes.
00135     nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryInterface(aSupport, &rv);
00136     NS_ENSURE_SUCCESS(rv, rv);
00137     nsXPIDLString folderName;
00138     rv = srcFolder->GetName(getter_Copies(folderName));
00139     NS_ENSURE_SUCCESS(rv, rv);
00140     m_dstFolderName = folderName;
00141   }
00142   
00143   return rv;
00144 }
00145 
00146 nsCopySource*
00147 nsCopyRequest::AddNewCopySource(nsIMsgFolder* srcFolder)
00148 {
00149   nsCopySource* newSrc = new nsCopySource(srcFolder);
00150   if (newSrc)
00151   {
00152       m_copySourceArray.AppendElement((void*) newSrc);
00153       if (srcFolder == m_dstFolder)
00154         newSrc->m_processed = PR_TRUE;
00155   }
00156   return newSrc;
00157 }
00158 
00159 // ************* nsMsgCopyService ****************
00160 // 
00161 
00162 
00163 nsMsgCopyService::nsMsgCopyService()
00164 {
00165 }
00166 
00167 nsMsgCopyService::~nsMsgCopyService()
00168 {
00169 
00170   PRInt32 i;
00171   nsCopyRequest* copyRequest;
00172   
00173   i = m_copyRequests.Count();
00174 
00175   while(i-- > 0)
00176   {
00177       copyRequest = (nsCopyRequest*) m_copyRequests.ElementAt(i);
00178       ClearRequest(copyRequest, NS_ERROR_FAILURE);
00179   }
00180 }
00181 
00182                               
00183 nsresult
00184 nsMsgCopyService::ClearRequest(nsCopyRequest* aRequest, nsresult rv)
00185 {
00186   if (aRequest)
00187   {
00188     // Send notifications to nsIGlobalMsgFolderNotificationService
00189     
00190     if (aRequest->m_requestType == nsCopyFoldersType)
00191     {
00192       nsCOMPtr <nsIMsgFolderNotificationService> notifier = do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID);
00193       if (notifier)
00194       {
00195         PRBool hasListeners;
00196         notifier->GetHasListeners(&hasListeners);
00197         if (hasListeners)
00198         {
00199           nsCOMPtr <nsISupportsArray> supportsArray = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
00200           if (supportsArray)
00201           {
00202             // Iterate over the copy sources and append their message arrays to this supports array
00203             // or in the case of folders, the source folder.
00204             PRInt32 cnt, i;
00205             cnt =  aRequest->m_copySourceArray.Count();
00206             for (i=0; i < cnt; i++)
00207             {
00208               nsCopySource *copySource = (nsCopySource*) aRequest->m_copySourceArray.ElementAt(i);
00209               supportsArray->AppendElement(copySource->m_msgFolder);
00210             }
00211             notifier->NotifyItemMoveCopyCompleted(aRequest->m_isMoveOrDraftOrTemplate, supportsArray, aRequest->m_dstFolder);
00212           }
00213         }
00214       }
00215     }
00216     
00217     // undo stuff
00218     if (aRequest->m_allowUndo && aRequest->m_copySourceArray.Count() > 1 && 
00219         aRequest->m_txnMgr)
00220         aRequest->m_txnMgr->EndBatch();
00221         
00222     m_copyRequests.RemoveElement(aRequest);
00223     if (aRequest->m_listener)
00224         aRequest->m_listener->OnStopCopy(rv);
00225     delete aRequest;
00226   }
00227   
00228   return rv;
00229 }
00230 
00231 nsresult 
00232 nsMsgCopyService::QueueRequest(nsCopyRequest* aRequest, PRBool *aCopyImmediately)
00233 {
00234   NS_ENSURE_ARG_POINTER(aRequest);
00235   NS_ENSURE_ARG_POINTER(aCopyImmediately);
00236   *aCopyImmediately = PR_TRUE;
00237   nsCopyRequest* copyRequest;
00238 
00239   PRInt32 cnt, i;
00240   cnt = m_copyRequests.Count();
00241   for (i=0; i < cnt; i++)
00242   {
00243     copyRequest = (nsCopyRequest*) m_copyRequests.ElementAt(i);
00244     if (aRequest->m_requestType == nsCopyFoldersType)
00245     {
00246       // For copy folder, see if both destination folder (root)
00247       // (ie, Local Folder) and folder name (ie, abc) are the same.
00248       if (copyRequest->m_dstFolderName == aRequest->m_dstFolderName &&
00249           copyRequest->m_dstFolder.get() == aRequest->m_dstFolder.get())
00250       {
00251         *aCopyImmediately = PR_FALSE;
00252         break;
00253       }
00254     }
00255     else if (copyRequest->m_dstFolder.get() == aRequest->m_dstFolder.get())  //if dst are same and we already have a request, we cannot copy immediately
00256     {
00257       *aCopyImmediately = PR_FALSE;
00258       break;
00259     }
00260   }
00261   return NS_OK;
00262 }
00263   
00264 nsresult 
00265 nsMsgCopyService::DoCopy(nsCopyRequest* aRequest)
00266 {
00267   NS_ENSURE_ARG(aRequest);
00268   PRBool copyImmediately;
00269   QueueRequest(aRequest, &copyImmediately);
00270   m_copyRequests.AppendElement((void*) aRequest);
00271   if (copyImmediately) // if there wasn't another request for this dest folder then we can copy immediately
00272     return DoNextCopy();
00273 
00274   return NS_OK;
00275 }
00276 
00277 nsresult
00278 nsMsgCopyService::DoNextCopy()
00279 {
00280   nsresult rv = NS_OK;
00281   nsCopyRequest* copyRequest = nsnull;
00282   nsCopySource* copySource = nsnull;
00283   PRInt32 i, j, cnt, scnt;
00284 
00285   cnt = m_copyRequests.Count();
00286   if (cnt > 0)
00287   {
00288     nsCOMArray<nsIMsgFolder> activeTargets;
00289 
00290     // ** jt -- always FIFO
00291     for (i=0; i < cnt; i++)
00292     {
00293       copyRequest = (nsCopyRequest*) m_copyRequests.ElementAt(i);
00294       copySource = nsnull;
00295       scnt = copyRequest->m_copySourceArray.Count();
00296       if (!copyRequest->m_processed)
00297       {
00298         // if the target folder of this request already has an active 
00299         // copy request, skip this request for now.
00300         if (activeTargets.IndexOfObject(copyRequest->m_dstFolder) != kNotFound)
00301         {
00302           copyRequest = nsnull;
00303           continue;
00304         }
00305         if (scnt <= 0) goto found; // must be CopyFileMessage
00306         for (j=0; j < scnt; j++)
00307         {
00308           copySource = (nsCopySource*) copyRequest->m_copySourceArray.ElementAt(j);
00309           if (!copySource->m_processed)
00310             goto found;
00311         }
00312         if (j >= scnt) // all processed set the value
00313           copyRequest->m_processed = PR_TRUE;
00314       }
00315       else // keep track of folders actively getting copied to.
00316         activeTargets.AppendObject(copyRequest->m_dstFolder);
00317     }
00318     found:
00319       if (copyRequest && !copyRequest->m_processed)
00320       {
00321           if (copyRequest->m_listener)
00322               copyRequest->m_listener->OnStartCopy();
00323           if (copyRequest->m_requestType == nsCopyMessagesType &&
00324               copySource)
00325           {
00326               copySource->m_processed = PR_TRUE;
00327               rv = copyRequest->m_dstFolder->CopyMessages
00328                   (copySource->m_msgFolder, copySource->m_messageArray,
00329                    copyRequest->m_isMoveOrDraftOrTemplate,
00330                    copyRequest->m_msgWindow, copyRequest->m_listener, PR_FALSE, copyRequest->m_allowUndo);   //isFolder operation PR_FALSE
00331                                                               
00332           }
00333           else if (copyRequest->m_requestType == nsCopyFoldersType )
00334           {
00335               copySource->m_processed = PR_TRUE;
00336               rv = copyRequest->m_dstFolder->CopyFolder
00337                   (copySource->m_msgFolder,
00338                    copyRequest->m_isMoveOrDraftOrTemplate,
00339                    copyRequest->m_msgWindow, copyRequest->m_listener);
00340               // If it's a copy folder operation and the destination
00341               // folder already exists, CopyFolder() returns an error w/o sending
00342               // a completion notification, so clear it here.
00343               if (NS_FAILED(rv))
00344                 ClearRequest(copyRequest, rv);
00345 
00346           }
00347           else if (copyRequest->m_requestType == nsCopyFileMessageType)
00348           {
00349             nsCOMPtr<nsIFileSpec> aSpec(do_QueryInterface(copyRequest->m_srcSupport, &rv));
00350             if (NS_SUCCEEDED(rv))
00351             {
00352                 // ** in case of saving draft/template; the very first
00353                 // time we may not have the original message to replace
00354                 // with; if we do we shall have an instance of copySource
00355                 nsCOMPtr<nsIMsgDBHdr> aMessage;
00356                 if (copySource)
00357                 {
00358                     aMessage = do_QueryElementAt(copySource->m_messageArray,
00359                                                  0, &rv);
00360                     copySource->m_processed = PR_TRUE;
00361                 }
00362                 copyRequest->m_processed = PR_TRUE;
00363                 rv = copyRequest->m_dstFolder->CopyFileMessage
00364                     (aSpec, aMessage,
00365                      copyRequest->m_isMoveOrDraftOrTemplate,
00366                      copyRequest->m_newMsgFlags,
00367                      copyRequest->m_msgWindow,
00368                      copyRequest->m_listener);
00369             }
00370           }
00371       }
00372     }
00373     return rv;
00374 }
00375 
00376 nsCopyRequest*
00377 nsMsgCopyService::FindRequest(nsISupports* aSupport,
00378                               nsIMsgFolder* dstFolder)
00379 {
00380   nsCopyRequest* copyRequest = nsnull;
00381   PRInt32 cnt, i;
00382 
00383   cnt = m_copyRequests.Count();
00384   for (i=0; i < cnt; i++)
00385   {
00386     copyRequest = (nsCopyRequest*) m_copyRequests.ElementAt(i);
00387     if (copyRequest->m_requestType == nsCopyFoldersType)
00388     {
00389         // If the src is different then check next request. 
00390         if (copyRequest->m_srcSupport.get() != aSupport)
00391         {
00392           copyRequest = nsnull;
00393           continue;
00394         }
00395 
00396         // See if the parent of the copied folder is the same as the one when the request was made.
00397         // Note if the destination folder is already a server folder then no need to get parent.
00398         nsCOMPtr <nsIMsgFolder> parentMsgFolder;
00399         nsresult rv = NS_OK;
00400         PRBool isServer=PR_FALSE;
00401         dstFolder->GetIsServer(&isServer);
00402         if (!isServer)
00403           rv = dstFolder->GetParentMsgFolder(getter_AddRefs(parentMsgFolder));
00404         if ((NS_FAILED(rv)) || (!parentMsgFolder && !isServer) || (copyRequest->m_dstFolder.get() != parentMsgFolder))
00405         {
00406           copyRequest = nsnull;
00407           continue;
00408         }
00409 
00410         // Now checks if the folder name is the same.
00411         nsXPIDLString folderName;
00412         rv = dstFolder->GetName(getter_Copies(folderName));
00413         if (NS_FAILED(rv))
00414         {
00415           copyRequest = nsnull;
00416           continue;
00417         }
00418 
00419         if (copyRequest->m_dstFolderName == folderName)
00420           break;
00421     }
00422     else if (copyRequest->m_srcSupport.get() == aSupport &&
00423         copyRequest->m_dstFolder.get() == dstFolder)
00424         break;
00425     else
00426         copyRequest = nsnull;
00427   }
00428 
00429   return copyRequest;
00430 }
00431 
00432 NS_IMPL_THREADSAFE_ISUPPORTS1(nsMsgCopyService, nsIMsgCopyService)
00433 
00434 NS_IMETHODIMP
00435 nsMsgCopyService::CopyMessages(nsIMsgFolder* srcFolder, /* UI src folder */
00436                                nsISupportsArray* messages,
00437                                nsIMsgFolder* dstFolder,
00438                                PRBool isMove,
00439                                nsIMsgCopyServiceListener* listener,
00440                                nsIMsgWindow* window,
00441                                PRBool allowUndo)
00442 {
00443   NS_ENSURE_ARG_POINTER(srcFolder);
00444   NS_ENSURE_ARG_POINTER(messages);
00445   NS_ENSURE_ARG_POINTER(dstFolder);
00446 
00447   nsCopyRequest* copyRequest;
00448   nsCopySource* copySource = nsnull;
00449   nsCOMPtr<nsISupportsArray> msgArray;
00450   PRUint32 cnt;
00451   nsCOMPtr<nsIMsgDBHdr> msg;
00452   nsCOMPtr<nsIMsgFolder> curFolder;
00453   nsCOMPtr<nsISupports> aSupport;
00454   nsresult rv;
00455     
00456   // XXX TODO 
00457   // JUNK MAIL RELATED
00458   // make sure dest folder exists
00459   // and has proper flags, before we start copying?
00460 
00461   copyRequest = new nsCopyRequest();
00462   if (!copyRequest) 
00463     return NS_ERROR_OUT_OF_MEMORY;
00464 
00465   aSupport = do_QueryInterface(srcFolder, &rv);
00466 
00467   rv = copyRequest->Init(nsCopyMessagesType, aSupport, dstFolder, isMove, 
00468                         0 /* new msg flags, not used */, listener, 
00469                          window, allowUndo);
00470   if (NS_FAILED(rv)) 
00471     goto done;
00472 
00473   rv = NS_NewISupportsArray(getter_AddRefs(msgArray));
00474   if (NS_FAILED(rv)) 
00475     goto done;
00476 
00477   messages->Count(&cnt);
00478 
00479   // duplicate the message array so we could sort the messages by it's
00480   // folder easily
00481   msgArray->AppendElements(messages);
00482 
00483   rv = msgArray->Count(&cnt);
00484   if (NS_FAILED(rv)) 
00485     goto done;
00486 
00487   while (cnt-- > 0)
00488   {
00489     msg = do_QueryElementAt(msgArray, cnt, &rv);
00490 
00491     if (NS_FAILED(rv)) 
00492       goto done;
00493 
00494     rv = msg->GetFolder(getter_AddRefs(curFolder));
00495 
00496     if (NS_FAILED(rv)) 
00497       goto done;
00498     if (!copySource)
00499     {
00500       copySource = copyRequest->AddNewCopySource(curFolder);
00501       if (!copySource)
00502       {
00503          rv = NS_ERROR_OUT_OF_MEMORY;
00504          goto done;
00505       }
00506     }
00507 
00508     if (curFolder == copySource->m_msgFolder)
00509     {
00510       copySource->AddMessage(msg);
00511       msgArray->RemoveElementAt(cnt);
00512     }
00513 
00514     if (cnt == 0)
00515     {
00516       rv = msgArray->Count(&cnt);
00517       if (cnt > 0)
00518         copySource = nsnull; // * force to create a new one and
00519                              // * continue grouping the messages
00520     }
00521   }
00522 
00523   // undo stuff
00524   if (NS_SUCCEEDED(rv) && copyRequest->m_allowUndo && copyRequest->m_copySourceArray.Count() > 1 &&
00525       copyRequest->m_txnMgr)
00526     copyRequest->m_txnMgr->BeginBatch();
00527 
00528 done:
00529     
00530     if (NS_FAILED(rv))
00531       delete copyRequest;
00532     else
00533       rv = DoCopy(copyRequest);
00534     
00535     msgArray->Clear();
00536 
00537     return rv;
00538 }
00539 
00540 NS_IMETHODIMP
00541 nsMsgCopyService::CopyFolders( nsISupportsArray* folders,
00542                                nsIMsgFolder* dstFolder,
00543                                PRBool isMove,
00544                                nsIMsgCopyServiceListener* listener,
00545                                nsIMsgWindow* window)
00546 {
00547   nsCopyRequest* copyRequest;
00548   nsCopySource* copySource = nsnull;
00549   nsresult rv = NS_ERROR_NULL_POINTER;
00550   PRUint32 cnt;
00551   nsCOMPtr<nsIMsgFolder> curFolder;
00552   nsCOMPtr<nsISupports> support;
00553   
00554   if (!folders || !dstFolder) return rv;
00555   
00556   rv = folders->Count(&cnt);   //if cnt is zero it cannot to get this point, will be detected earlier
00557   if ( cnt > 1)
00558     NS_ASSERTION((NS_SUCCEEDED(rv)),"More than one folders to copy");
00559   
00560   support = getter_AddRefs(folders->ElementAt(0));
00561   
00562   copyRequest = new nsCopyRequest();
00563   if (!copyRequest) return NS_ERROR_OUT_OF_MEMORY;
00564   
00565   rv = copyRequest->Init(nsCopyFoldersType, support, dstFolder, 
00566     isMove, 0 /* new msg flags, not used */ , listener, window, PR_FALSE);
00567   NS_ENSURE_SUCCESS(rv,rv);
00568   
00569   curFolder = do_QueryInterface(support, &rv);
00570   NS_ENSURE_SUCCESS(rv, rv);
00571   
00572   copySource = copyRequest->AddNewCopySource(curFolder);
00573   if (!copySource)
00574     rv = NS_ERROR_OUT_OF_MEMORY;
00575   
00576   if (NS_FAILED(rv))
00577   {
00578     delete copyRequest;
00579     NS_ENSURE_SUCCESS(rv, rv);
00580   }
00581   else
00582     rv = DoCopy(copyRequest);
00583   
00584   return rv;
00585 }
00586 
00587 NS_IMETHODIMP
00588 nsMsgCopyService::CopyFileMessage(nsIFileSpec* fileSpec,
00589                                   nsIMsgFolder* dstFolder,
00590                                   nsIMsgDBHdr* msgToReplace,
00591                                   PRBool isDraft,
00592                                   PRUint32 aMsgFlags,
00593                                   nsIMsgCopyServiceListener* listener,
00594                                   nsIMsgWindow* window)
00595 {
00596   nsresult rv = NS_ERROR_NULL_POINTER;
00597   nsCopyRequest* copyRequest;
00598   nsCopySource* copySource = nsnull;
00599   nsCOMPtr<nsISupports> fileSupport;
00600   nsCOMPtr<nsITransactionManager> txnMgr;
00601 
00602   NS_ENSURE_ARG_POINTER(fileSpec);
00603   NS_ENSURE_ARG_POINTER(dstFolder);
00604 
00605   if (window)
00606     window->GetTransactionManager(getter_AddRefs(txnMgr));
00607   copyRequest = new nsCopyRequest();
00608   if (!copyRequest) return rv;
00609   fileSupport = do_QueryInterface(fileSpec, &rv);
00610   if (NS_FAILED(rv)) goto done;
00611 
00612   rv = copyRequest->Init(nsCopyFileMessageType, fileSupport, dstFolder,
00613                          isDraft, aMsgFlags, listener, window, PR_FALSE);
00614   if (NS_FAILED(rv)) goto done;
00615 
00616   if (msgToReplace)
00617   {
00618     copySource = copyRequest->AddNewCopySource(dstFolder);
00619     if (!copySource)
00620     {
00621         rv = NS_ERROR_OUT_OF_MEMORY;
00622         goto done;
00623     }
00624     copySource->AddMessage(msgToReplace);
00625   }
00626 
00627 done:
00628     if (NS_FAILED(rv))
00629     {
00630       delete copyRequest;
00631     }
00632     else
00633     {
00634       rv = DoCopy(copyRequest);
00635     }
00636 
00637     return rv;
00638 }
00639 
00640 NS_IMETHODIMP
00641 nsMsgCopyService::NotifyCompletion(nsISupports* aSupport,
00642                                    nsIMsgFolder* dstFolder,
00643                                    nsresult result)
00644 {
00645   nsCopyRequest* copyRequest = nsnull;
00646   do
00647   {
00648     // loop for copy requests, because if we do a cross server folder copy,
00649     // we'll have a copy request for the folder copy, which will in turn
00650     // generate a copy request for the messages in the folder, which
00651     // will have the same src support.
00652     copyRequest = FindRequest(aSupport, dstFolder);
00653 
00654     if (copyRequest)
00655     {
00656       // check if this copy request is done by making sure all the
00657       // sources have been processed.
00658       nsCopySource* copySource = nsnull;
00659       PRInt32 sourceIndex, sourceCount;
00660       sourceCount = copyRequest->m_copySourceArray.Count();
00661       for (sourceIndex = 0; sourceIndex < sourceCount; sourceIndex++)
00662       {
00663         if (!((nsCopySource*)
00664             copyRequest->m_copySourceArray.ElementAt(sourceIndex))->m_processed)
00665             break;
00666       }
00667       // if all sources processed, mark the request as processed
00668       if (sourceIndex >= sourceCount) 
00669         copyRequest->m_processed = PR_TRUE;
00670     // if this request is done, or failed, clear it.
00671       if (copyRequest->m_processed || NS_FAILED(result))
00672         ClearRequest(copyRequest, result);
00673       else 
00674         break;
00675     }
00676     else
00677       break;
00678   }
00679   while (copyRequest);
00680 
00681   return DoNextCopy();
00682 }
00683