Back to index

lightning-sunbird  0.9+nobinonly
nsImapUndoTxn.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 "msgCore.h" // for precompiled headers
00040 #include "nsMsgImapCID.h"
00041 #include "nsIMsgHdr.h"
00042 #include "nsImapUndoTxn.h"
00043 #include "nsXPIDLString.h"
00044 #include "nsIIMAPHostSessionList.h"
00045 #include "nsIMsgIncomingServer.h"
00046 #include "nsIDBFolderInfo.h"
00047 
00048 nsImapMoveCopyMsgTxn::nsImapMoveCopyMsgTxn() :
00049     m_idsAreUids(PR_FALSE), m_isMove(PR_FALSE), m_srcIsPop3(PR_FALSE)
00050 {
00051 }
00052 
00053 nsresult
00054 nsImapMoveCopyMsgTxn::Init(
00055        nsIMsgFolder* srcFolder, nsMsgKeyArray* srcKeyArray, 
00056        const char* srcMsgIdString, nsIMsgFolder* dstFolder,
00057        PRBool idsAreUids, PRBool isMove,
00058        nsIEventQueue* eventQueue, nsIUrlListener* urlListener)
00059 {
00060   nsresult rv;
00061   NS_NewISupportsArray(getter_AddRefs(m_srcHdrs));
00062   m_srcMsgIdString = srcMsgIdString;
00063   m_idsAreUids = idsAreUids;
00064   m_isMove = isMove;
00065   m_srcFolder = do_GetWeakReference(srcFolder);
00066   m_dstFolder = do_GetWeakReference(dstFolder);
00067   m_eventQueue = do_QueryInterface(eventQueue, &rv);
00068   if (urlListener)
00069     m_urlListener = do_QueryInterface(urlListener, &rv);
00070   m_srcKeyArray.CopyArray(srcKeyArray);
00071   m_dupKeyArray.CopyArray(srcKeyArray);
00072   nsXPIDLCString uri;
00073   rv = srcFolder->GetURI(getter_Copies(uri));
00074   nsCString protocolType(uri);
00075   protocolType.SetLength(protocolType.FindChar(':'));
00076   // ** jt -- only do this for mailbox protocol
00077   if (protocolType.LowerCaseEqualsLiteral("mailbox"))
00078   {
00079     m_srcIsPop3 = PR_TRUE;
00080     PRUint32 i, count = m_srcKeyArray.GetSize();
00081     nsCOMPtr<nsIMsgDatabase> srcDB;
00082     rv = srcFolder->GetMsgDatabase(nsnull, getter_AddRefs(srcDB));
00083     if (NS_FAILED(rv)) return rv;
00084     nsCOMPtr<nsIMsgDBHdr> srcHdr;
00085     nsCOMPtr<nsIMsgDBHdr> copySrcHdr;
00086     nsMsgKey pseudoKey;
00087     
00088     for (i=0; i<count; i++)
00089     {
00090       rv = srcDB->GetMsgHdrForKey(m_srcKeyArray.GetAt(i),
00091         getter_AddRefs(srcHdr));
00092       if (NS_SUCCEEDED(rv))
00093       {
00094         PRUint32 msgSize;
00095         rv = srcHdr->GetMessageSize(&msgSize);
00096         if (NS_SUCCEEDED(rv))
00097           m_srcSizeArray.Add(msgSize);
00098         if (isMove)
00099         {
00100           srcDB->GetNextPseudoMsgKey(&pseudoKey);
00101           pseudoKey--;
00102           m_dupKeyArray.SetAt(i,pseudoKey);
00103           rv = srcDB->CopyHdrFromExistingHdr(pseudoKey,
00104             srcHdr, PR_FALSE,
00105             getter_AddRefs(copySrcHdr));
00106           if (NS_SUCCEEDED(rv)) 
00107           {
00108             nsCOMPtr<nsISupports> supports = do_QueryInterface(copySrcHdr);
00109             m_srcHdrs->AppendElement(supports);
00110           }
00111         }
00112       }
00113     }
00114   }
00115   return nsMsgTxn::Init();
00116 }
00117 
00118 nsImapMoveCopyMsgTxn::~nsImapMoveCopyMsgTxn()
00119 {
00120 }
00121 
00122 NS_IMPL_ADDREF_INHERITED(nsImapMoveCopyMsgTxn, nsMsgTxn)
00123 NS_IMPL_RELEASE_INHERITED(nsImapMoveCopyMsgTxn, nsMsgTxn)
00124 
00125 NS_IMETHODIMP
00126 nsImapMoveCopyMsgTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr)
00127 {
00128     if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
00129 
00130     *aInstancePtr = nsnull;
00131 
00132     if (aIID.Equals(NS_GET_IID(nsImapMoveCopyMsgTxn))) 
00133     {
00134         *aInstancePtr = NS_STATIC_CAST(nsImapMoveCopyMsgTxn*, this);
00135     }
00136 
00137     if (*aInstancePtr)
00138     {
00139         NS_ADDREF_THIS();
00140         return NS_OK;
00141     }
00142 
00143     return nsMsgTxn::QueryInterface(aIID, aInstancePtr);
00144 }
00145 
00146 NS_IMETHODIMP
00147 nsImapMoveCopyMsgTxn::UndoTransaction(void)
00148 {
00149   nsresult rv;
00150   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
00151   NS_ENSURE_SUCCESS(rv,rv);
00152 
00153   if (m_isMove || !m_dstFolder)
00154   {
00155     if (m_srcIsPop3)
00156     {
00157       rv = UndoMailboxDelete();
00158       if (NS_FAILED(rv)) return rv;
00159     }
00160     else
00161     {
00162       nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00163       if (NS_FAILED(rv) || !srcFolder) 
00164         return rv;
00165       nsCOMPtr<nsIUrlListener> srcListener =
00166         do_QueryInterface(srcFolder, &rv);
00167       if (NS_FAILED(rv)) 
00168         return rv;
00169       // ** make sure we are in the selected state; use lite select
00170       // folder so we won't hit performance hard
00171       rv = imapService->LiteSelectFolder(m_eventQueue, srcFolder,
00172         srcListener, nsnull);
00173       if (NS_FAILED(rv)) 
00174         return rv;
00175       PRBool deletedMsgs = PR_TRUE; //default is true unless imapDelete model
00176       nsMsgImapDeleteModel deleteModel;
00177       rv = GetImapDeleteModel(srcFolder, &deleteModel);
00178 
00179       // protect against a bogus undo txn without any source keys
00180       // see bug #179856 for details
00181       NS_ASSERTION(m_srcKeyArray.GetSize(), "no source keys");
00182       if (!m_srcKeyArray.GetSize())
00183         return NS_ERROR_UNEXPECTED;
00184 
00185       if (NS_SUCCEEDED(rv) && deleteModel == nsMsgImapDeleteModels::IMAPDelete)
00186         CheckForToggleDelete(srcFolder, m_srcKeyArray.GetAt(0), &deletedMsgs);
00187 
00188       if (deletedMsgs)
00189         rv = imapService->SubtractMessageFlags(
00190              m_eventQueue, srcFolder, srcListener, nsnull,
00191              m_srcMsgIdString.get(), kImapMsgDeletedFlag,
00192              m_idsAreUids);
00193       else
00194         rv = imapService->AddMessageFlags(m_eventQueue, srcFolder,
00195                                           srcListener, nsnull,
00196                                           m_srcMsgIdString.get(),
00197                                           kImapMsgDeletedFlag,
00198                                           m_idsAreUids);
00199       if (NS_FAILED(rv)) 
00200         return rv;
00201 
00202       if (deleteModel != nsMsgImapDeleteModels::IMAPDelete)
00203         rv = imapService->GetHeaders(m_eventQueue, srcFolder,
00204         srcListener, nsnull,
00205         m_srcMsgIdString.get(),
00206         PR_TRUE); 
00207     }
00208   }
00209   if (!m_dstMsgIdString.IsEmpty())
00210   {
00211     nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
00212     if (NS_FAILED(rv) || !dstFolder) return rv;
00213     
00214     nsCOMPtr<nsIUrlListener> dstListener;
00215     
00216     dstListener = do_QueryInterface(dstFolder, &rv);
00217     if (NS_FAILED(rv)) return rv;
00218     // ** make sure we are in the selected state; use lite select folder
00219     // so we won't potentially download a bunch of headers.
00220     rv = imapService->LiteSelectFolder(m_eventQueue, dstFolder,
00221       dstListener, nsnull);
00222     if (NS_FAILED(rv)) return rv;
00223     rv = imapService->AddMessageFlags(m_eventQueue, dstFolder,
00224       dstListener, nsnull,
00225       m_dstMsgIdString.get(),
00226       kImapMsgDeletedFlag,
00227       m_idsAreUids);
00228   }
00229   return rv;
00230 }
00231 
00232 NS_IMETHODIMP
00233 nsImapMoveCopyMsgTxn::RedoTransaction(void)
00234 {
00235   nsresult rv;
00236   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
00237   NS_ENSURE_SUCCESS(rv,rv);
00238   
00239   if (m_isMove || !m_dstFolder)
00240   {
00241     if (m_srcIsPop3)
00242     {
00243       rv = RedoMailboxDelete();
00244       if (NS_FAILED(rv)) return rv;
00245     }
00246     else
00247     {
00248       nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00249       if (NS_FAILED(rv) || !srcFolder) 
00250         return rv;
00251       nsCOMPtr<nsIUrlListener> srcListener =
00252         do_QueryInterface(srcFolder, &rv); 
00253       if (NS_FAILED(rv)) 
00254         return rv;
00255       
00256       PRBool deletedMsgs = PR_FALSE;  //default will be false unless imapDeleteModel;
00257       nsMsgImapDeleteModel deleteModel;
00258       rv = GetImapDeleteModel(srcFolder, &deleteModel);
00259       
00260       // protect against a bogus undo txn without any source keys
00261       // see bug #179856 for details
00262       NS_ASSERTION(m_srcKeyArray.GetSize(), "no source keys");
00263       if (!m_srcKeyArray.GetSize())
00264         return NS_ERROR_UNEXPECTED;
00265       
00266       if (NS_SUCCEEDED(rv) && deleteModel == nsMsgImapDeleteModels::IMAPDelete)
00267         rv = CheckForToggleDelete(srcFolder, m_srcKeyArray.GetAt(0), &deletedMsgs);
00268       
00269       // ** make sire we are in the selected state; use lite select
00270       // folder so we won't hit preformace hard
00271       rv = imapService->LiteSelectFolder(m_eventQueue, srcFolder,
00272         srcListener, nsnull);
00273       if (NS_FAILED(rv)) 
00274         return rv;
00275       if (deletedMsgs)
00276         rv = imapService->SubtractMessageFlags(m_eventQueue, srcFolder, 
00277                                                 srcListener, nsnull,
00278                                                 m_srcMsgIdString.get(), kImapMsgDeletedFlag,
00279                                                 m_idsAreUids);
00280       else
00281         rv = imapService->AddMessageFlags(m_eventQueue, srcFolder,
00282                                           srcListener, nsnull, m_srcMsgIdString.get(),
00283                                           kImapMsgDeletedFlag, m_idsAreUids);
00284     }
00285   }
00286   if (!m_dstMsgIdString.IsEmpty())
00287   {
00288     nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
00289     if (NS_FAILED(rv) || !dstFolder) return rv;
00290     
00291     nsCOMPtr<nsIUrlListener> dstListener;
00292     
00293     dstListener = do_QueryInterface(dstFolder, &rv); 
00294     if (NS_FAILED(rv)) 
00295       return rv;
00296     // ** make sure we are in the selected state; use lite select
00297     // folder so we won't hit preformace hard
00298     rv = imapService->LiteSelectFolder(m_eventQueue, dstFolder,
00299       dstListener, nsnull);
00300     if (NS_FAILED(rv)) 
00301       return rv;
00302     rv = imapService->SubtractMessageFlags(m_eventQueue, dstFolder,
00303       dstListener, nsnull,
00304       m_dstMsgIdString.get(),
00305       kImapMsgDeletedFlag,
00306       m_idsAreUids);
00307     if (NS_FAILED(rv)) 
00308       return rv;
00309     nsMsgImapDeleteModel deleteModel;
00310     rv = GetImapDeleteModel(dstFolder, &deleteModel);
00311     if (NS_FAILED(rv) || deleteModel == nsMsgImapDeleteModels::MoveToTrash)
00312       rv = imapService->GetHeaders(m_eventQueue, dstFolder,
00313       dstListener, nsnull,
00314       m_dstMsgIdString.get(),
00315       PR_TRUE);
00316   }
00317   return rv;
00318 }
00319 
00320 nsresult
00321 nsImapMoveCopyMsgTxn::SetCopyResponseUid(const char* aMsgIdString)
00322 {
00323   if (!aMsgIdString) return NS_ERROR_NULL_POINTER;
00324   m_dstMsgIdString = aMsgIdString;
00325   if (m_dstMsgIdString.Last() == ']')
00326   {
00327     PRInt32 len = m_dstMsgIdString.Length();
00328     m_dstMsgIdString.SetLength(len - 1);
00329   }
00330   return NS_OK;
00331 }
00332 
00333 nsresult
00334 nsImapMoveCopyMsgTxn::GetSrcKeyArray(nsMsgKeyArray& srcKeyArray)
00335 {
00336     srcKeyArray.CopyArray(&m_srcKeyArray);
00337     return NS_OK;
00338 }
00339 
00340 nsresult
00341 nsImapMoveCopyMsgTxn::AddDstKey(nsMsgKey aKey)
00342 {
00343     if (!m_dstMsgIdString.IsEmpty())
00344         m_dstMsgIdString.Append(",");
00345     m_dstMsgIdString.AppendInt((PRInt32) aKey);
00346     return NS_OK;
00347 }
00348 
00349 nsresult
00350 nsImapMoveCopyMsgTxn::UndoMailboxDelete()
00351 {
00352     nsresult rv = NS_ERROR_FAILURE;
00353     // ** jt -- only do this for mailbox protocol
00354     if (m_srcIsPop3)
00355     {
00356         nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00357         if (NS_FAILED(rv) || !srcFolder) return rv;
00358 
00359         nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
00360         if (NS_FAILED(rv) || !dstFolder) return rv;
00361 
00362         nsCOMPtr<nsIMsgDatabase> srcDB;
00363         nsCOMPtr<nsIMsgDatabase> dstDB;
00364         rv = srcFolder->GetMsgDatabase(nsnull, getter_AddRefs(srcDB));
00365         if (NS_FAILED(rv)) return rv;
00366         rv = dstFolder->GetMsgDatabase(nsnull, getter_AddRefs(dstDB));
00367         if (NS_FAILED(rv)) return rv;
00368         
00369         PRUint32 count = m_srcKeyArray.GetSize();
00370         PRUint32 i;
00371         nsCOMPtr<nsIMsgDBHdr> oldHdr;
00372         nsCOMPtr<nsIMsgDBHdr> newHdr;
00373         for (i=0; i<count; i++)
00374         {
00375            oldHdr = do_QueryElementAt(m_srcHdrs, i);
00376            NS_ASSERTION(oldHdr, "fatal ... cannot get old msg header\n");
00377            rv = srcDB->CopyHdrFromExistingHdr(m_srcKeyArray.GetAt(i),
00378                                               oldHdr,PR_TRUE,
00379                                               getter_AddRefs(newHdr));
00380            NS_ASSERTION(newHdr, "fatal ... cannot create new header\n");
00381                      
00382            if (NS_SUCCEEDED(rv) && newHdr)
00383            {
00384                       if (i < m_srcSizeArray.GetSize())
00385                 newHdr->SetMessageSize(m_srcSizeArray.GetAt(i));
00386                 srcDB->UndoDelete(newHdr);
00387                  }
00388         }
00389         srcDB->SetSummaryValid(PR_TRUE);
00390         return NS_OK; // always return NS_OK
00391     }
00392     else
00393     {
00394         rv = NS_ERROR_FAILURE;
00395     }
00396     return rv;
00397 }
00398 
00399 
00400 nsresult
00401 nsImapMoveCopyMsgTxn::RedoMailboxDelete()
00402 {
00403     nsresult rv = NS_ERROR_FAILURE;
00404     if (m_srcIsPop3)
00405     {
00406         nsCOMPtr<nsIMsgDatabase> srcDB;
00407         nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00408         if (NS_FAILED(rv) || !srcFolder) return rv;
00409         rv = srcFolder->GetMsgDatabase(nsnull, getter_AddRefs(srcDB));
00410         if (NS_SUCCEEDED(rv))
00411         {
00412             srcDB->DeleteMessages(&m_srcKeyArray, nsnull);
00413             srcDB->SetSummaryValid(PR_TRUE);
00414         }
00415         return NS_OK; // always return NS_OK
00416     }
00417     else
00418     {
00419         rv = NS_ERROR_FAILURE;
00420     }
00421     return rv;
00422 }
00423 
00424 nsresult nsImapMoveCopyMsgTxn::GetImapDeleteModel(nsIMsgFolder *aFolder, nsMsgImapDeleteModel *aDeleteModel)
00425 {
00426   nsresult rv;
00427   nsCOMPtr<nsIMsgIncomingServer> server;
00428   if (!aFolder)
00429     return NS_ERROR_NULL_POINTER;
00430   rv = aFolder->GetServer(getter_AddRefs(server));
00431   NS_ENSURE_SUCCESS(rv, rv);
00432   nsCOMPtr<nsIImapIncomingServer> imapServer = do_QueryInterface(server, &rv);
00433   if (NS_SUCCEEDED(rv) && imapServer)
00434    rv = imapServer->GetDeleteModel(aDeleteModel);
00435   return rv;
00436 }
00437 
00438 nsImapOfflineTxn::nsImapOfflineTxn(nsIMsgFolder* srcFolder, nsMsgKeyArray* srcKeyArray, 
00439        nsIMsgFolder* dstFolder, PRBool isMove, nsOfflineImapOperationType opType,
00440         nsIMsgDBHdr *srcHdr,
00441        nsIEventQueue* eventQueue, nsIUrlListener* urlListener)
00442 {
00443   Init(srcFolder, srcKeyArray, nsnull, dstFolder, PR_TRUE,
00444        isMove, eventQueue, urlListener);
00445 
00446   m_opType = opType; 
00447   m_flags = 0;
00448   m_addFlags = PR_FALSE;
00449   m_header = srcHdr;
00450   if (opType == nsIMsgOfflineImapOperation::kDeletedMsg)
00451   {
00452     nsCOMPtr <nsIMsgDatabase> srcDB;
00453     nsCOMPtr <nsIDBFolderInfo> folderInfo;
00454 
00455     nsresult rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
00456     if (NS_SUCCEEDED(rv) && srcDB)
00457     {
00458       nsMsgKey pseudoKey;
00459       nsCOMPtr <nsIMsgDBHdr> copySrcHdr;
00460 
00461       srcDB->GetNextPseudoMsgKey(&pseudoKey);
00462       pseudoKey--;
00463       m_dupKeyArray.SetAt(0, pseudoKey);
00464       rv = srcDB->CopyHdrFromExistingHdr(pseudoKey, srcHdr, PR_FALSE, getter_AddRefs(copySrcHdr));
00465       if (NS_SUCCEEDED(rv)) 
00466       {
00467         nsCOMPtr<nsISupports> supports = do_QueryInterface(copySrcHdr);
00468         m_srcHdrs->AppendElement(supports);
00469       }
00470     }
00471   }
00472 }
00473 
00474 nsImapOfflineTxn::~nsImapOfflineTxn()
00475 {
00476 }
00477 
00478 // Open the database and find the key for the offline operation that we want to
00479 // undo, then remove it from the database, we also hold on to this
00480 // data for a redo operation.
00481 NS_IMETHODIMP nsImapOfflineTxn::UndoTransaction(void)
00482 {
00483   nsresult rv;
00484   
00485   nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00486   if (NS_FAILED(rv) || !srcFolder) 
00487     return rv;
00488   nsCOMPtr <nsIMsgOfflineImapOperation> op;
00489   nsCOMPtr <nsIDBFolderInfo> folderInfo;
00490   nsCOMPtr <nsIMsgDatabase> srcDB;
00491   nsCOMPtr <nsIMsgDatabase> destDB;
00492 
00493   nsMsgKey hdrKey = nsMsgKey_None;
00494 
00495   if (m_header)
00496     m_header->GetMessageKey(&hdrKey);
00497 
00498   rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
00499   NS_ENSURE_SUCCESS(rv, rv);
00500   switch (m_opType)
00501   {
00502     case nsIMsgOfflineImapOperation::kMsgMoved:
00503     case nsIMsgOfflineImapOperation::kMsgCopy:
00504     case nsIMsgOfflineImapOperation::kAddedHeader:
00505     case nsIMsgOfflineImapOperation::kFlagsChanged:
00506       rv = srcDB->GetOfflineOpForKey(hdrKey, PR_FALSE, getter_AddRefs(op));
00507       if (NS_SUCCEEDED(rv) && op)
00508       {
00509         srcDB->RemoveOfflineOp(op);
00510         op = nsnull;
00511       }
00512       if (m_header && (m_opType == nsIMsgOfflineImapOperation::kAddedHeader))
00513       {
00514         nsCOMPtr <nsIMsgDBHdr> mailHdr;
00515         nsMsgKey msgKey;
00516         m_header->GetMessageKey(&msgKey);
00517         rv = srcDB->GetMsgHdrForKey(msgKey, getter_AddRefs(mailHdr));
00518         if (mailHdr)
00519           srcDB->DeleteHeader(mailHdr, nsnull, PR_TRUE, PR_FALSE);
00520       }
00521       break;
00522     case nsIMsgOfflineImapOperation::kDeletedMsg:
00523       {
00524         nsMsgKey msgKey;
00525         m_header->GetMessageKey(&msgKey);
00526        nsCOMPtr<nsIMsgDBHdr> undeletedHdr;
00527         m_srcHdrs->QueryElementAt(0, NS_GET_IID(nsIMsgDBHdr), getter_AddRefs(undeletedHdr));
00528         if (undeletedHdr)
00529         {
00530           nsCOMPtr <nsIMsgDBHdr> newHdr;
00531 
00532           srcDB->CopyHdrFromExistingHdr (msgKey, undeletedHdr, PR_TRUE, getter_AddRefs(newHdr));
00533         }
00534         srcDB->Close(PR_TRUE);
00535         srcFolder->SummaryChanged();
00536       }
00537       break;
00538     case nsIMsgOfflineImapOperation::kMsgMarkedDeleted:
00539       srcDB->MarkImapDeleted(hdrKey, PR_FALSE, nsnull);
00540       break;
00541     default:
00542       break;
00543   }
00544   srcDB->Close(PR_TRUE);
00545   srcFolder->SummaryChanged();
00546   return NS_OK;
00547 }
00548 
00549 NS_IMETHODIMP nsImapOfflineTxn::RedoTransaction(void)
00550 {
00551   nsresult rv;
00552   
00553   nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv);
00554   if (NS_FAILED(rv) || !srcFolder) 
00555     return rv;
00556   nsCOMPtr <nsIMsgOfflineImapOperation> op;
00557   nsCOMPtr <nsIDBFolderInfo> folderInfo;
00558   nsCOMPtr <nsIMsgDatabase> srcDB;
00559   nsCOMPtr <nsIMsgDatabase> destDB;
00560   rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB));
00561   NS_ENSURE_SUCCESS(rv, rv);
00562   nsMsgKey hdrKey = nsMsgKey_None;
00563 
00564   if (m_header)
00565     m_header->GetMessageKey(&hdrKey);
00566 
00567   switch (m_opType)
00568   {
00569   case nsIMsgOfflineImapOperation::kMsgMoved:
00570   case nsIMsgOfflineImapOperation::kMsgCopy:
00571     rv = srcDB->GetOfflineOpForKey(hdrKey, PR_FALSE, getter_AddRefs(op));
00572     if (NS_SUCCEEDED(rv) && op)
00573     {
00574       nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
00575       if (dstFolder)
00576       {
00577         nsXPIDLCString folderURI;
00578         dstFolder->GetURI(getter_Copies(folderURI));
00579 
00580 
00581         if (m_opType == nsIMsgOfflineImapOperation::kMsgMoved)
00582         {
00583           op->SetDestinationFolderURI(folderURI); // offline move
00584         }
00585         if (m_opType == nsIMsgOfflineImapOperation::kMsgCopy)
00586         {
00587           op->SetOperation(nsIMsgOfflineImapOperation::kMsgMoved);
00588           op->AddMessageCopyOperation(folderURI); // offline copy
00589         }
00590         dstFolder->SummaryChanged();
00591       }
00592     }
00593     break;
00594   case nsIMsgOfflineImapOperation::kAddedHeader:
00595     {
00596       nsCOMPtr <nsIMsgDBHdr> restoreHdr;
00597       nsMsgKey msgKey;
00598       m_header->GetMessageKey(&msgKey);
00599       nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv);
00600       rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(destDB));
00601       NS_ENSURE_SUCCESS(rv, rv);
00602       if (m_header)
00603         destDB->CopyHdrFromExistingHdr (msgKey, m_header, PR_TRUE, getter_AddRefs(restoreHdr));
00604       destDB->Close(PR_TRUE);
00605       dstFolder->SummaryChanged();
00606       rv = destDB->GetOfflineOpForKey(hdrKey, PR_TRUE, getter_AddRefs(op));
00607       if (NS_SUCCEEDED(rv) && op)
00608       {
00609         nsXPIDLCString folderURI;
00610         srcFolder->GetURI(getter_Copies(folderURI));
00611         op->SetSourceFolderURI(folderURI);
00612       }
00613       dstFolder->SummaryChanged();
00614       destDB->Close(PR_TRUE);
00615     }
00616     break;
00617   case nsIMsgOfflineImapOperation::kDeletedMsg:
00618     srcDB->DeleteMessage(hdrKey, nsnull, PR_TRUE);
00619     break;
00620   case nsIMsgOfflineImapOperation::kMsgMarkedDeleted:
00621     srcDB->MarkImapDeleted(hdrKey, PR_TRUE, nsnull);
00622     break;
00623   case nsIMsgOfflineImapOperation::kFlagsChanged:
00624     rv = srcDB->GetOfflineOpForKey(hdrKey, PR_TRUE, getter_AddRefs(op));
00625     if (NS_SUCCEEDED(rv) && op)
00626     {
00627       imapMessageFlagsType newMsgFlags;
00628       op->GetNewFlags(&newMsgFlags);
00629       if (m_addFlags)
00630         op->SetFlagOperation(newMsgFlags | m_flags);
00631       else
00632         op->SetFlagOperation(newMsgFlags & ~m_flags);
00633     }
00634     break;
00635   default:
00636     break;
00637   }
00638   srcDB->Close(PR_TRUE);
00639   srcDB = nsnull;
00640   srcFolder->SummaryChanged();
00641   return NS_OK;
00642 }
00643 
00644