Back to index

lightning-sunbird  0.9+nobinonly
nsImapMailFolder.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  *   Seth Spitzer <sspitzer@netscape.com>
00025  *   Lorenzo Colitti <lorenzo@colitti.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "msgCore.h"
00042 
00043 #include "nsMsgImapCID.h"
00044 #include "nsImapMailFolder.h"
00045 #include "nsIEnumerator.h"
00046 #include "nsILocalFile.h"
00047 #include "nsIFolderListener.h"
00048 #include "nsCOMPtr.h"
00049 #include "nsAutoPtr.h"
00050 #include "nsIRDFService.h"
00051 #include "nsIRDFDataSource.h"
00052 #include "nsRDFCID.h"
00053 #include "nsFileStream.h"
00054 #include "nsMsgDBCID.h"
00055 #include "nsMsgFolderFlags.h"
00056 #include "nsLocalFolderSummarySpec.h"
00057 #include "nsImapFlagAndUidState.h"
00058 #include "nsIEventQueueService.h"
00059 #include "nsIImapUrl.h"
00060 #include "nsImapUtils.h"
00061 #include "nsMsgUtils.h"
00062 #include "nsIMsgMailSession.h"
00063 #include "nsMsgBaseCID.h"
00064 #include "nsMsgLocalCID.h"
00065 #include "nsImapUndoTxn.h"
00066 #include "nsIIMAPHostSessionList.h"
00067 #include "nsIMsgCopyService.h"
00068 #include "nsICopyMsgStreamListener.h"
00069 #include "nsImapStringBundle.h"
00070 #include "nsIMsgFolderCacheElement.h"
00071 #include "nsTextFormatter.h"
00072 #include "nsIPrefBranch.h"
00073 #include "nsIPrefService.h"
00074 #include "nsMsgI18N.h"
00075 #include "nsICacheSession.h"
00076 #include "nsEscape.h"
00077 #include "nsIDOMWindowInternal.h"
00078 #include "nsIMsgFilter.h"
00079 #include "nsImapMoveCoalescer.h"
00080 #include "nsIPrompt.h"
00081 #include "nsIPromptService.h"
00082 #include "nsIDocShell.h"
00083 #include "nsIInterfaceRequestor.h"
00084 #include "nsIInterfaceRequestorUtils.h"
00085 #include "nsSpecialSystemDirectory.h"
00086 #include "nsXPIDLString.h"
00087 #include "nsReadableUtils.h"
00088 #include "nsUnicharUtils.h"
00089 #include "nsIImapFlagAndUidState.h"
00090 #include "nsIImapHeaderXferInfo.h"
00091 #include "nsIMessenger.h"
00092 #include "nsIMsgSearchAdapter.h"
00093 #include "nsIImapMockChannel.h"
00094 #include "nsIProgressEventSink.h"
00095 #include "nsIMsgWindow.h"
00096 #include "nsIMsgFolder.h" // TO include biffState enum. Change to bool later...
00097 #include "nsIMsgOfflineImapOperation.h"
00098 #include "nsImapOfflineSync.h"
00099 #include "nsIMsgAccountManager.h"
00100 #include "nsQuickSort.h"
00101 #include "nsIImapMockChannel.h"
00102 #include "nsIWebNavigation.h"
00103 #include "nsNetUtil.h"
00104 #include "nsIMAPNamespace.h"
00105 #include "nsHashtable.h"
00106 #include "nsIMsgFolderCompactor.h"
00107 #include "nsMsgMessageFlags.h"
00108 #include "nsIMimeHeaders.h"
00109 #include "nsIMsgMdnGenerator.h"
00110 #include "nsISpamSettings.h"
00111 #include "nsInt64.h"
00112 #include <time.h>
00113 #include "nsIMsgMailNewsUrl.h"
00114 #include "nsEmbedCID.h"
00115 #include "nsIMsgComposeService.h"
00116 #include "nsMsgCompCID.h"
00117 #include "nsICacheEntryDescriptor.h"
00118 #include "nsDirectoryServiceDefs.h"
00119 #include "nsIMsgIdentity.h"
00120 #include "nsIMsgFolderNotificationService.h"
00121 
00122 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00123 static NS_DEFINE_CID(kCMailDB, NS_MAILDB_CID);
00124 static NS_DEFINE_CID(kCImapDB, NS_IMAPDB_CID);
00125 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00126 static NS_DEFINE_CID(kParseMailMsgStateCID, NS_PARSEMAILMSGSTATE_CID);
00127 static NS_DEFINE_CID(kCImapHostSessionList, NS_IIMAPHOSTSESSIONLIST_CID);
00128 
00129 nsIAtom* nsImapMailFolder::mImapHdrDownloadedAtom=nsnull;
00130 
00131 #define FOUR_K 4096
00132 #define MAILNEWS_CUSTOM_HEADERS "mailnews.customHeaders"
00133 
00134 /*
00135     Copies the contents of srcDir into destDir.
00136     destDir will be created if it doesn't exist.
00137 */
00138 
00139 static
00140 nsresult RecursiveCopy(nsIFile* srcDir, nsIFile* destDir)
00141 {
00142   nsresult rv;
00143   PRBool isDir;
00144   
00145   rv = srcDir->IsDirectory(&isDir);
00146   if (NS_FAILED(rv)) return rv;
00147   if (!isDir) return NS_ERROR_INVALID_ARG;
00148   
00149   PRBool exists;
00150   rv = destDir->Exists(&exists);
00151   if (NS_SUCCEEDED(rv) && !exists)
00152     rv = destDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
00153   if (NS_FAILED(rv)) return rv;
00154   
00155   PRBool hasMore = PR_FALSE;
00156   nsCOMPtr<nsISimpleEnumerator> dirIterator;
00157   rv = srcDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
00158   if (NS_FAILED(rv)) return rv;
00159   
00160   rv = dirIterator->HasMoreElements(&hasMore);
00161   if (NS_FAILED(rv)) return rv;
00162   
00163   nsCOMPtr<nsIFile> dirEntry;
00164   
00165   while (hasMore)
00166   {
00167     rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
00168     if (NS_SUCCEEDED(rv))
00169     {
00170       rv = dirEntry->IsDirectory(&isDir);
00171       if (NS_SUCCEEDED(rv))
00172       {
00173         if (isDir)
00174         {
00175           nsCOMPtr<nsIFile> destClone;
00176           rv = destDir->Clone(getter_AddRefs(destClone));
00177           if (NS_SUCCEEDED(rv))
00178           {
00179             nsCOMPtr<nsILocalFile> newChild(do_QueryInterface(destClone));
00180             nsAutoString leafName;
00181             dirEntry->GetLeafName(leafName);
00182             newChild->AppendRelativePath(leafName);
00183             rv = newChild->Exists(&exists);
00184             if (NS_SUCCEEDED(rv) && !exists)
00185               rv = newChild->Create(nsIFile::DIRECTORY_TYPE, 0775);
00186             rv = RecursiveCopy(dirEntry, newChild);
00187           }
00188         }
00189         else
00190           rv = dirEntry->CopyTo(destDir, EmptyString());
00191       }
00192       
00193     }
00194     rv = dirIterator->HasMoreElements(&hasMore);
00195     if (NS_FAILED(rv)) return rv;
00196   }
00197   
00198   return rv;
00199 }
00200 
00201 nsImapMailFolder::nsImapMailFolder() :
00202     m_initialized(PR_FALSE),m_haveDiscoveredAllFolders(PR_FALSE),
00203     m_haveReadNameFromDB(PR_FALSE), 
00204     m_curMsgUid(0), m_nextMessageByteLength(0),
00205     m_urlRunning(PR_FALSE),
00206   m_verifiedAsOnlineFolder(PR_FALSE),
00207   m_explicitlyVerify(PR_FALSE),
00208   m_folderIsNamespace(PR_FALSE),
00209     m_folderNeedsSubscribing(PR_FALSE),
00210     m_folderNeedsAdded(PR_FALSE),
00211     m_folderNeedsACLListed(PR_TRUE),
00212     m_performingBiff(PR_FALSE),
00213     m_folderQuotaCommandIssued(PR_FALSE),
00214     m_folderQuotaDataIsValid(PR_FALSE),
00215     m_updatingFolder(PR_FALSE),
00216     m_downloadMessageForOfflineUse(PR_FALSE),
00217     m_downloadingFolderForOfflineUse(PR_FALSE),
00218     m_folderQuotaUsedKB(0),
00219     m_folderQuotaMaxKB(0)
00220 {
00221   MOZ_COUNT_CTOR(nsImapMailFolder); // double count these for now.
00222 
00223   if (mImapHdrDownloadedAtom == nsnull)
00224     mImapHdrDownloadedAtom = NS_NewAtom("ImapHdrDownloaded");
00225   m_appendMsgMonitor = nsnull;  // since we're not using this (yet?) make it null.
00226   // if we do start using it, it should be created lazily
00227   
00228   nsresult rv;
00229   
00230   // Get current thread envent queue
00231   nsCOMPtr<nsIEventQueueService> pEventQService = 
00232     do_GetService(kEventQueueServiceCID, &rv); 
00233   if (NS_SUCCEEDED(rv) && pEventQService)
00234     pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
00235     getter_AddRefs(m_eventQueue));
00236   m_moveCoalescer = nsnull;
00237   m_boxFlags = 0;
00238   m_uidValidity = kUidUnknown;
00239   m_numStatusRecentMessages = 0;
00240   m_numStatusUnseenMessages = 0;
00241   m_hierarchyDelimiter = kOnlineHierarchySeparatorUnknown;
00242   m_pathName = nsnull;
00243   m_folderACL = nsnull;
00244   m_aclFlags = 0;
00245   m_supportedUserFlags = 0;
00246   m_namespace = nsnull;
00247   m_numFilterClassifyRequests = 0; 
00248 }
00249 
00250 nsImapMailFolder::~nsImapMailFolder()
00251 {
00252   MOZ_COUNT_DTOR(nsImapMailFolder);
00253     if (m_appendMsgMonitor)
00254         PR_DestroyMonitor(m_appendMsgMonitor);
00255 
00256   // I think our destructor gets called before the base class...
00257   if (mInstanceCount == 1)
00258     NS_IF_RELEASE(mImapHdrDownloadedAtom);
00259   NS_IF_RELEASE(m_moveCoalescer);
00260   delete m_pathName;
00261   delete m_folderACL;
00262 }
00263 
00264 NS_IMPL_ADDREF_INHERITED(nsImapMailFolder, nsMsgDBFolder)
00265 NS_IMPL_RELEASE_INHERITED(nsImapMailFolder, nsMsgDBFolder)
00266 NS_IMPL_QUERY_HEAD(nsImapMailFolder)
00267     NS_IMPL_QUERY_BODY(nsIMsgImapMailFolder)
00268     NS_IMPL_QUERY_BODY(nsICopyMessageListener)
00269     NS_IMPL_QUERY_BODY(nsIImapMailFolderSink)
00270     NS_IMPL_QUERY_BODY(nsIImapMessageSink)
00271     NS_IMPL_QUERY_BODY(nsIUrlListener)
00272     NS_IMPL_QUERY_BODY(nsIMsgFilterHitNotify)
00273     NS_IMPL_QUERY_BODY(nsIJunkMailClassificationListener)
00274 NS_IMPL_QUERY_TAIL_INHERITING(nsMsgDBFolder)
00275 
00276 
00277 NS_IMETHODIMP nsImapMailFolder::Enumerate(nsIEnumerator* *result)
00278 {
00279 #if 0
00280     nsresult rv = NS_OK;
00281     nsIEnumerator* folders;
00282     nsIEnumerator* messages;
00283     rv = GetSubFolders(&folders);
00284     if (NS_FAILED(rv)) return rv;
00285     rv = GetMessages(nsnull, &messages);
00286     if (NS_FAILED(rv)) return rv;
00287     return NS_NewConjoiningEnumerator(folders, messages, 
00288                                       (nsIBidirectionalEnumerator**)result);
00289 #endif
00290   NS_ASSERTION(PR_FALSE, "obsolete, right?");
00291   return NS_ERROR_FAILURE;
00292 }
00293 
00294 nsresult nsImapMailFolder::AddDirectorySeparator(nsFileSpec &path)
00295 {
00296   nsresult rv = NS_OK;
00297   if (mURI.Equals(kImapRootURI)) 
00298   {
00299       // don't concat the full separator with .sbd
00300   }
00301   else 
00302   {
00303       nsAutoString sep;
00304       rv = nsGetMailFolderSeparator(sep);
00305       if (NS_FAILED(rv)) return rv;
00306 
00307       // see if there's a dir with the same name ending with .sbd
00308       // unfortunately we can't just say:
00309       //          path += sep;
00310       // here because of the way nsFileSpec concatenates
00311       nsCAutoString str(path.GetNativePathCString());
00312       LossyAppendUTF16toASCII(sep, str); 
00313       path = str.get();
00314     }
00315 
00316   return rv;
00317 }
00318 
00319 static PRBool
00320 nsShouldIgnoreFile(nsString& name)
00321 {
00322     PRInt32 len = name.Length();
00323     if (len > 4 && name.RFind(".msf", PR_TRUE) == len -4)
00324     {
00325         name.SetLength(len-4); // truncate the string
00326         return PR_FALSE;
00327     }
00328     return PR_TRUE;
00329 }
00330 
00331 // this is only called for virtual folders, currently.
00332 NS_IMETHODIMP nsImapMailFolder::AddSubfolder(const nsAString& aName,
00333                                    nsIMsgFolder** aChild)
00334 {
00335   NS_ENSURE_ARG_POINTER(aChild);
00336   
00337   PRInt32 flags = 0;
00338   nsresult rv;
00339   nsCOMPtr<nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00340   NS_ENSURE_SUCCESS(rv,rv);
00341   
00342   nsCAutoString uri(mURI);
00343   uri.Append('/');
00344   
00345   // If AddSubFolder starts getting called for folders other than virtual folders, 
00346   // we'll have to do convert those names to modified utf-7. For now, the account manager code
00347   // that loads the virtual folders for each account, expects utf8 not modified utf-7. 
00348   nsCAutoString escapedName;
00349   rv = NS_MsgEscapeEncodeURLPath(aName, escapedName);
00350   NS_ENSURE_SUCCESS(rv, rv);
00351   
00352   uri += escapedName.get();
00353   
00354   nsCOMPtr <nsIMsgFolder> msgFolder;
00355   rv = GetChildWithURI(uri.get(), PR_FALSE/*deep*/, PR_TRUE /*case Insensitive*/, getter_AddRefs(msgFolder));  
00356   if (NS_SUCCEEDED(rv) && msgFolder)
00357     return NS_MSG_FOLDER_EXISTS;
00358   
00359   nsCOMPtr<nsIRDFResource> res;
00360   rv = rdf->GetResource(uri, getter_AddRefs(res));
00361   if (NS_FAILED(rv))
00362     return rv;
00363   
00364   nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(res, &rv));
00365   if (NS_FAILED(rv))
00366     return rv;
00367 
00368   nsFileSpec path;
00369   nsMsgDBFolder *dbFolder = NS_STATIC_CAST(nsMsgDBFolder *, NS_STATIC_CAST(nsIMsgFolder *, folder.get()));
00370   rv = dbFolder->CreateDirectoryForFolder(path);
00371   NS_ENSURE_SUCCESS(rv, rv);
00372 
00373   folder->GetFlags((PRUint32 *)&flags);
00374   
00375   flags |= MSG_FOLDER_FLAG_MAIL;
00376   
00377   folder->SetParent(this);
00378   
00379   folder->SetFlags(flags);
00380   
00381   nsCOMPtr<nsISupports> supports = do_QueryInterface(folder);
00382   if(folder)
00383     mSubFolders->AppendElement(supports);
00384   NS_ADDREF(*aChild = folder);
00385   
00386   nsCOMPtr <nsIMsgImapMailFolder> imapChild = do_QueryInterface(*aChild);
00387   if (imapChild)
00388   {
00389     NS_LossyConvertUTF16toASCII folderCName(aName);
00390     imapChild->SetOnlineName(folderCName.get());
00391     imapChild->SetHierarchyDelimiter(m_hierarchyDelimiter);
00392   }
00393   return rv;
00394 }
00395 
00396 NS_IMETHODIMP nsImapMailFolder::AddSubfolderWithPath(nsAString& name, nsIFileSpec *dbPath, 
00397                                              nsIMsgFolder **child)
00398 {
00399   if(!child)
00400     return NS_ERROR_NULL_POINTER;
00401 
00402   nsresult rv = NS_OK;
00403   nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv)); 
00404 
00405   if(NS_FAILED(rv))
00406     return rv;
00407 
00408   PRInt32 flags = 0;
00409 
00410   nsCAutoString uri = mURI + NS_LITERAL_CSTRING("/");
00411   AppendUTF16toUTF8(name, uri);
00412 
00413   //will make sure mSubFolders does not have duplicates because of bogus msf files.
00414 
00415   nsCOMPtr <nsIMsgFolder> msgFolder;
00416   rv = GetChildWithURI(uri.get(), PR_FALSE/*deep*/, PR_FALSE /*case Insensitive*/, getter_AddRefs(msgFolder));  
00417   if (NS_SUCCEEDED(rv) && msgFolder)
00418   {
00419     return NS_MSG_FOLDER_EXISTS;
00420   }
00421   
00422   nsCOMPtr<nsIRDFResource> res;
00423   rv = rdf->GetResource(uri, getter_AddRefs(res));
00424   if (NS_FAILED(rv))
00425     return rv;
00426 
00427   nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(res, &rv));
00428   if (NS_FAILED(rv))
00429     return rv;        
00430 
00431   folder->SetPath(dbPath);
00432     nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(folder);
00433 
00434     folder->GetFlags((PRUint32 *)&flags);
00435 
00436     folder->SetParent(this);
00437 
00438   flags |= MSG_FOLDER_FLAG_MAIL;
00439 
00440    PRBool isServer;
00441    rv = GetIsServer(&isServer);
00442 
00443    PRInt32 pFlags;
00444    GetFlags ((PRUint32 *) &pFlags);
00445    PRBool isParentInbox = pFlags & MSG_FOLDER_FLAG_INBOX;
00446  
00447    //Only set these if these are top level children or parent is inbox
00448 
00449   if(NS_SUCCEEDED(rv))
00450   {
00451     if(isServer &&
00452        name.LowerCaseEqualsLiteral("inbox"))
00453       flags |= MSG_FOLDER_FLAG_INBOX;
00454     else if(isServer || isParentInbox) 
00455     {
00456       nsAutoString trashName;
00457       GetTrashFolderName(trashName);
00458       if (name.Equals(trashName))
00459         flags |= MSG_FOLDER_FLAG_TRASH;
00460     }
00461 #if 0
00462     else if(name.LowerCaseEqualsLiteral("sent"))
00463       folder->SetFlag(MSG_FOLDER_FLAG_SENTMAIL);
00464     else if(name.LowerCaseEqualsLiteral("drafts"))
00465       folder->SetFlag(MSG_FOLDER_FLAG_DRAFTS);
00466     else if (name.LowerCaseEqualsLiteral("templates"))
00467       folder->SetFlag(MSG_FOLDER_FLAG_TEMPLATES);
00468 #endif
00469   }
00470 
00471     folder->SetFlags(flags);
00472   //at this point we must be ok and we don't want to return failure in case GetIsServer failed.
00473   rv = NS_OK;
00474 
00475   nsCOMPtr <nsISupports> supports = do_QueryInterface(folder);
00476   NS_ASSERTION(supports, "couldn't get isupports from imap folder");
00477   if (supports)
00478     mSubFolders->AppendElement(supports);
00479   *child = folder;
00480   NS_IF_ADDREF(*child);
00481   return rv;
00482 }
00483 
00484 nsresult nsImapMailFolder::CreateSubFolders(nsFileSpec &path)
00485 {
00486   nsresult rv = NS_OK;
00487   nsAutoString currentFolderNameStr;    // online name
00488   nsAutoString currentFolderDBNameStr;  // possibly munged name
00489   nsCOMPtr<nsIMsgFolder> child;
00490   nsCOMPtr<nsIMsgIncomingServer> server;
00491   nsCOMPtr<nsIImapIncomingServer> imapServer;
00492 
00493   if (NS_SUCCEEDED(GetServer(getter_AddRefs(server))) && server)
00494     imapServer = do_QueryInterface(server);
00495 
00496   PRBool isServer;
00497   rv = GetIsServer(&isServer);
00498 
00499   nsCAutoString folderName;
00500   for (nsDirectoryIterator dir(path, PR_FALSE); dir.Exists(); dir++) 
00501   {
00502     nsFileSpec currentFolderPath = dir.Spec();
00503     folderName.Adopt(currentFolderPath.GetLeafName());
00504     currentFolderNameStr.AssignWithConversion(folderName);
00505     if (isServer && imapServer)
00506     {
00507       PRBool isPFC;
00508       imapServer->GetIsPFC(folderName.get(), &isPFC);
00509       if (isPFC)
00510       {
00511         nsCOMPtr <nsIMsgFolder> pfcFolder;
00512         imapServer->GetPFC(PR_TRUE, getter_AddRefs(pfcFolder));
00513         continue;
00514       }
00515       // should check if this is the PFC
00516     }
00517     if (nsShouldIgnoreFile(currentFolderNameStr))
00518       continue;
00519 
00520     // OK, here we need to get the online name from the folder cache if we can.
00521     // If we can, use that to create the sub-folder
00522 
00523     nsCOMPtr <nsIMsgFolderCacheElement> cacheElement;
00524     nsCOMPtr <nsIFileSpec> curFolder;
00525     nsCOMPtr <nsIFileSpec> dbFile;
00526 
00527     NS_NewFileSpecWithSpec(currentFolderPath, getter_AddRefs(dbFile));
00528     // don't strip off the .msf in currentFolderPath.
00529     currentFolderPath.SetLeafName(folderName.get());
00530     rv = NS_NewFileSpecWithSpec(currentFolderPath, getter_AddRefs(curFolder));
00531 
00532     currentFolderDBNameStr = currentFolderNameStr;
00533     nsAutoString utf7LeafName = currentFolderNameStr;
00534 
00535     if (NS_SUCCEEDED(rv) && curFolder)
00536     {
00537       rv = GetFolderCacheElemFromFileSpec(dbFile, getter_AddRefs(cacheElement));
00538 
00539       if (NS_SUCCEEDED(rv) && cacheElement)
00540       {
00541         nsXPIDLString unicodeName;
00542         nsXPIDLCString onlineFullUtf7Name;
00543 
00544         PRUint32 folderFlags;
00545         rv = cacheElement->GetInt32Property("flags", (PRInt32 *) &folderFlags);
00546         if (NS_SUCCEEDED(rv) && folderFlags & MSG_FOLDER_FLAG_VIRTUAL) //ignore virtual folders
00547           continue;
00548         PRInt32 hierarchyDelimiter;
00549         rv = cacheElement->GetInt32Property("hierDelim", &hierarchyDelimiter);
00550         if (NS_SUCCEEDED(rv) && hierarchyDelimiter == kOnlineHierarchySeparatorUnknown)
00551         {
00552           currentFolderPath.Delete(PR_FALSE);
00553           continue; // blow away .msf files for folders with unknown delimiter.
00554         }
00555         rv = cacheElement->GetStringProperty("onlineName", getter_Copies(onlineFullUtf7Name));
00556         if (NS_SUCCEEDED(rv) && onlineFullUtf7Name.get() && strlen(onlineFullUtf7Name.get()))
00557         {
00558           // Call ConvertFolderName() and HideFolderName() to do special folder name
00559           // mapping and hiding, if configured to do so. For example, need to hide AOL's
00560           // 'RECYCLE_OUT' & convert a few AOL folder names. Regular imap accounts
00561           // will do no-op in the calls
00562           if (imapServer)
00563           {
00564             PRBool hideFolder;
00565             rv = imapServer->HideFolderName(onlineFullUtf7Name.get(), &hideFolder);
00566             if (hideFolder)
00567               continue;     // skip this folder
00568             else
00569             {
00570               rv = imapServer->ConvertFolderName(onlineFullUtf7Name.get(), getter_Copies(unicodeName));
00571               if (NS_FAILED(rv)) {
00572                 rv = CopyMUTF7toUTF16(onlineFullUtf7Name, unicodeName);
00573                 if (NS_FAILED(rv))  // XXX Does this make sense? 
00574                   CopyASCIItoUTF16(onlineFullUtf7Name, unicodeName);
00575               }
00576             }
00577           }
00578 
00579           currentFolderNameStr.Assign(unicodeName);
00580 
00581           PRUnichar delimiter = 0;
00582           GetHierarchyDelimiter(&delimiter);
00583           PRInt32 leafPos = currentFolderNameStr.RFindChar(delimiter);
00584           if (leafPos > 0)
00585             currentFolderNameStr.Cut(0, leafPos + 1);
00586 
00587           // take the utf7 full online name, and determine the utf7 leaf name
00588           CopyASCIItoUTF16(onlineFullUtf7Name, utf7LeafName);
00589           leafPos = utf7LeafName.RFindChar(delimiter);
00590           if (leafPos > 0)
00591             utf7LeafName.Cut(0, leafPos + 1);
00592         }
00593       }
00594     }
00595       // make the imap folder remember the file spec it was created with.
00596     nsCAutoString leafName; leafName.AssignWithConversion(currentFolderDBNameStr);
00597     nsCOMPtr <nsIFileSpec> msfFileSpec;
00598     rv = NS_NewFileSpecWithSpec(currentFolderPath, getter_AddRefs(msfFileSpec));
00599     if (NS_SUCCEEDED(rv) && msfFileSpec)
00600     {
00601       // leaf name is the db name w/o .msf (nsShouldIgnoreFile strips it off)
00602       // so this trims the .msf off the file spec.
00603       msfFileSpec->SetLeafName(leafName.get());
00604     }
00605     // use the utf7 name as the uri for the folder.
00606     AddSubfolderWithPath(utf7LeafName, msfFileSpec, getter_AddRefs(child));
00607     if (child)
00608     {
00609       // use the unicode name as the "pretty" name. Set it so it won't be
00610       // automatically computed from the URI, which is in utf7 form.
00611       if (!currentFolderNameStr.IsEmpty())
00612         child->SetPrettyName(currentFolderNameStr.get());
00613       child->SetMsgDatabase(nsnull);
00614     }
00615   }
00616   return rv;
00617 }
00618 
00619 NS_IMETHODIMP nsImapMailFolder::GetSubFolders(nsIEnumerator* *result)
00620 {
00621   PRBool isServer;
00622   nsresult rv = GetIsServer(&isServer);
00623 
00624   if (!m_initialized)
00625   {
00626     nsCOMPtr<nsIFileSpec> pathSpec;
00627     rv = GetPath(getter_AddRefs(pathSpec));
00628     if (NS_FAILED(rv)) return rv;
00629 
00630     nsFileSpec path;
00631     rv = pathSpec->GetFileSpec(&path);
00632     if (NS_FAILED(rv)) return rv;
00633 
00634     // host directory does not need .sbd tacked on
00635     if (NS_SUCCEEDED(rv) && !isServer)
00636       rv = AddDirectorySeparator(path);
00637 
00638     if(NS_FAILED(rv)) return rv;
00639     
00640     m_initialized = PR_TRUE;      // need to set this here to avoid infinite recursion from CreateSubfolders.
00641     // we have to treat the root folder specially, because it's name
00642     // doesn't end with .sbd
00643 
00644     PRInt32 newFlags = MSG_FOLDER_FLAG_MAIL;
00645     if (path.IsDirectory()) 
00646     {
00647         newFlags |= (MSG_FOLDER_FLAG_DIRECTORY | MSG_FOLDER_FLAG_ELIDED);
00648         if (!mIsServer)
00649           SetFlag(newFlags);
00650         rv = CreateSubFolders(path);
00651     }
00652     if (isServer)
00653     {
00654       PRUint32 numFolders = 0;
00655       nsCOMPtr <nsIMsgFolder> inboxFolder;
00656 
00657       rv = GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, 1, &numFolders, getter_AddRefs(inboxFolder));
00658       if (NS_FAILED(rv) || numFolders == 0 || !inboxFolder)
00659       {
00660         // create an inbox if we don't have one.
00661         CreateClientSubfolderInfo("INBOX", kOnlineHierarchySeparatorUnknown,0, PR_TRUE);
00662       }
00663     }
00664 
00665     UpdateSummaryTotals(PR_FALSE);
00666 
00667     if (NS_FAILED(rv)) return rv;
00668   }
00669   rv = mSubFolders->Enumerate(result);
00670   return rv;
00671 }
00672 
00673 //Makes sure the database is open and exists.  If the database is valid then
00674 //returns NS_OK.  Otherwise returns a failure error value.
00675 nsresult nsImapMailFolder::GetDatabase(nsIMsgWindow *aMsgWindow)
00676 {
00677   nsresult folderOpen = NS_OK;
00678   if (!mDatabase)
00679   {
00680     nsCOMPtr<nsIFileSpec> pathSpec;
00681     nsresult rv = GetPath(getter_AddRefs(pathSpec));
00682     if (NS_FAILED(rv)) return rv;
00683 
00684     nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
00685     NS_ENSURE_SUCCESS(rv, rv);
00686 
00687     folderOpen = msgDBService->OpenFolderDB(this, PR_TRUE, PR_FALSE, getter_AddRefs(mDatabase));
00688     
00689     if (NS_FAILED(folderOpen) && folderOpen != NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00690       folderOpen = msgDBService->OpenFolderDB(this, PR_TRUE, PR_TRUE, getter_AddRefs(mDatabase));
00691 
00692     if (NS_FAILED(folderOpen) && folderOpen != NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00693       return folderOpen;
00694 
00695     if(folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00696       folderOpen = NS_OK;
00697 
00698     if(mDatabase)
00699     {
00700       UpdateNewMessages();
00701       if(mAddListener)
00702         mDatabase->AddListener(this);
00703       UpdateSummaryTotals(PR_TRUE);
00704     }
00705   }
00706   return folderOpen;
00707 }
00708 
00709 NS_IMETHODIMP
00710 nsImapMailFolder::UpdateFolder(nsIMsgWindow *msgWindow)
00711 {
00712   nsresult rv = NS_ERROR_NULL_POINTER;
00713   PRBool selectFolder = PR_FALSE;
00714   
00715   if (mFlags & MSG_FOLDER_FLAG_INBOX && !m_filterList) 
00716       rv = GetFilterList(msgWindow, getter_AddRefs(m_filterList));
00717   
00718   if (m_filterList) 
00719   {
00720     nsCOMPtr<nsIMsgIncomingServer> server;
00721     rv = GetServer(getter_AddRefs(server));
00722     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get server");
00723     
00724     PRBool canFileMessagesOnServer = PR_TRUE;
00725     if (server) 
00726     {
00727       rv = server->GetCanFileMessagesOnServer(&canFileMessagesOnServer);
00728       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to determine if we could file messages on this server");
00729     }
00730     
00731     // the mdn filter is for filing return receipts into the sent folder
00732     // some servers (like AOL mail servers)
00733     // can't file to the sent folder, so we don't add the filter for those servers
00734     if (canFileMessagesOnServer) 
00735     {
00736       rv = server->ConfigureTemporaryFilters(m_filterList);
00737       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to add temp filters");
00738     }
00739   }
00740   
00741   selectFolder = PR_TRUE;
00742   
00743   PRBool isServer;
00744   rv = GetIsServer(&isServer);
00745   if (NS_SUCCEEDED(rv) && isServer)
00746   {
00747     if (!m_haveDiscoveredAllFolders)
00748     {
00749       PRBool hasSubFolders = PR_FALSE;
00750       GetHasSubFolders(&hasSubFolders);
00751       if (!hasSubFolders)
00752       {
00753         rv = CreateClientSubfolderInfo("Inbox", kOnlineHierarchySeparatorUnknown,0, PR_FALSE);
00754         if (NS_FAILED(rv)) 
00755           return rv;
00756       }
00757       m_haveDiscoveredAllFolders = PR_TRUE;
00758     }
00759     selectFolder = PR_FALSE;
00760   }
00761   rv = GetDatabase(msgWindow);
00762   if (NS_FAILED(rv))
00763   {
00764     ThrowAlertMsg("errorGettingDB", msgWindow);
00765     return rv;
00766   }
00767   PRBool canOpenThisFolder = PR_TRUE;
00768   GetCanIOpenThisFolder(&canOpenThisFolder);
00769   
00770   PRBool hasOfflineEvents = PR_FALSE;
00771   GetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS, &hasOfflineEvents);
00772   
00773   if (!WeAreOffline())
00774   {
00775     if (hasOfflineEvents)
00776     {
00777       nsImapOfflineSync *goOnline = new nsImapOfflineSync(msgWindow, this, this);
00778       if (goOnline)
00779         return goOnline->ProcessNextOperation();
00780     }
00781   }
00782   else // we're offline - check if we're password protecting the offline store
00783   {
00784     nsCOMPtr<nsIMsgAccountManager> accountManager = 
00785              do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00786     NS_ENSURE_SUCCESS(rv, rv);
00787     PRBool userNeedsToAuthenticate = PR_FALSE;
00788     // if we're PasswordProtectLocalCache, then we need to find out if the server is authenticated.
00789     (void) accountManager->GetUserNeedsToAuthenticate(&userNeedsToAuthenticate);
00790     if (userNeedsToAuthenticate)
00791     {
00792       nsCOMPtr<nsIMsgIncomingServer> server;
00793       rv = GetServer(getter_AddRefs(server));
00794       if (NS_SUCCEEDED(rv))
00795       {
00796         PRBool passwordMatches = PR_FALSE;
00797         rv = PromptForCachePassword(server, msgWindow, passwordMatches);
00798         if (!passwordMatches)
00799           return NS_ERROR_FAILURE;
00800       }
00801     }
00802   }
00803   if (!canOpenThisFolder) 
00804     selectFolder = PR_FALSE;
00805   // don't run select if we can't select the folder...
00806   if (NS_SUCCEEDED(rv) && !m_urlRunning && selectFolder)
00807   {
00808     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv); 
00809     if (NS_FAILED(rv)) return rv;
00810   
00811     nsCOMPtr <nsIURI> url;
00812     rv = imapService->SelectFolder(m_eventQueue, this, m_urlListener, msgWindow, getter_AddRefs(url));
00813     if (NS_SUCCEEDED(rv))
00814     {
00815       m_urlRunning = PR_TRUE;
00816       m_updatingFolder = PR_TRUE;
00817     }
00818     if (url)
00819     {
00820       nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(url);
00821       if (mailnewsUrl)
00822       {
00823         mailnewsUrl->RegisterListener(this);
00824         m_urlListener = nsnull;
00825       }
00826     }
00827     switch (rv)
00828     {
00829       case NS_MSG_ERROR_OFFLINE:
00830         if (msgWindow)
00831           AutoCompact(msgWindow);  
00832         // note fall through to next case.
00833       case NS_BINDING_ABORTED:
00834         rv = NS_OK;
00835         NotifyFolderEvent(mFolderLoadedAtom);
00836         break;
00837       default:
00838         break;
00839     }
00840   }
00841   else if (NS_SUCCEEDED(rv))  // tell the front end that the folder is loaded if we're not going to 
00842   {                           // actually run a url.
00843     if (!m_updatingFolder)    // if we're already running an update url, we'll let that one send the folder loaded
00844       NotifyFolderEvent(mFolderLoadedAtom);
00845     NS_ENSURE_SUCCESS(rv,rv);
00846   }
00847   
00848   return rv;
00849 }
00850 
00851 
00852 NS_IMETHODIMP nsImapMailFolder::GetMessages(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator* *result)
00853 {
00854   if (result)
00855     *result = nsnull;
00856   if (!mDatabase)
00857     GetDatabase(nsnull);
00858   if (mDatabase)
00859     return mDatabase->EnumerateMessages(result);
00860   return NS_ERROR_UNEXPECTED;
00861 }
00862 
00863 NS_IMETHODIMP nsImapMailFolder::CreateSubfolder(const PRUnichar* folderName, nsIMsgWindow *msgWindow )
00864 {
00865     nsresult rv = NS_ERROR_NULL_POINTER;
00866     if (!folderName) 
00867       return rv;
00868 
00869     nsAutoString trashName;
00870     GetTrashFolderName(trashName);
00871     if ( nsDependentString(folderName).Equals(trashName) )   // Trash , a special folder
00872     {
00873         ThrowAlertMsg("folderExists", msgWindow);
00874         return NS_MSG_FOLDER_EXISTS;
00875     }
00876     else if (mIsServer && nsDependentString(folderName).LowerCaseEqualsLiteral("inbox") )  // Inbox, a special folder
00877     {
00878         ThrowAlertMsg("folderExists", msgWindow);
00879         return NS_MSG_FOLDER_EXISTS;
00880     }
00881 
00882     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
00883     NS_ENSURE_SUCCESS(rv,rv);
00884 
00885     rv = imapService->CreateFolder(m_eventQueue, this, 
00886                                        folderName, this, nsnull);
00887     return rv;
00888 }
00889 
00890 NS_IMETHODIMP nsImapMailFolder::CreateClientSubfolderInfo(const char *folderName, PRUnichar hierarchyDelimiter, PRInt32 flags, PRBool suppressNotification)
00891 {
00892   nsresult rv = NS_OK;
00893     
00894   //Get a directory based on our current path.
00895   nsFileSpec path;
00896   rv = CreateDirectoryForFolder(path);
00897   if(NS_FAILED(rv))
00898     return rv;
00899 
00900     NS_ConvertASCIItoUTF16 leafName(folderName);
00901     nsAutoString folderNameStr;
00902     nsAutoString parentName = leafName;
00903     // use RFind, because folder can start with a delimiter and
00904     // not be a leaf folder.
00905     PRInt32 folderStart = leafName.RFindChar('/');
00906     if (folderStart > 0)
00907     {
00908         nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv));
00909         NS_ENSURE_SUCCESS(rv, rv);
00910         nsCOMPtr<nsIRDFResource> res;
00911         nsCOMPtr<nsIMsgImapMailFolder> parentFolder;
00912         nsCAutoString uri (mURI);
00913         parentName.Right(leafName, leafName.Length() - folderStart - 1);
00914         parentName.Truncate(folderStart);
00915 
00916        // the parentName might be too long or have some illegal chars
00917         // so we make it safe.
00918         // XXX Here it's assumed that IMAP folder names are stored locally 
00919         // in modified UTF-7 (ASCII-only) as is stored remotely.  If we ever change
00920         // this, we have to work with nsString instead of nsCString 
00921         // (ref. bug 264071)
00922         nsCAutoString safeParentName;
00923         safeParentName.AssignWithConversion(parentName);
00924         NS_MsgHashIfNecessary(safeParentName);
00925         path += safeParentName.get();
00926         // path is an out parameter to CreateDirectoryForFolder - I'm not
00927         // sure why we're munging it above.
00928         rv = CreateDirectoryForFolder(path);
00929         if (NS_FAILED(rv)) return rv;
00930         uri.Append('/');
00931         uri.AppendWithConversion(parentName);
00932         
00933         rv = rdf->GetResource(uri,
00934                               getter_AddRefs(res));
00935         if (NS_FAILED(rv)) return rv;
00936         parentFolder = do_QueryInterface(res, &rv);
00937         if (NS_FAILED(rv)) return rv;
00938         nsCAutoString leafnameC;
00939         leafnameC.AssignWithConversion(leafName);
00940         return parentFolder->CreateClientSubfolderInfo(leafnameC.get(), hierarchyDelimiter,flags, suppressNotification);
00941     }
00942     
00943   // if we get here, it's really a leaf, and "this" is the parent.
00944     folderNameStr = leafName;
00945     
00946 //    path += folderNameStr;
00947 
00948   // Create an empty database for this mail folder, set its name from the user  
00949   nsCOMPtr<nsIMsgDatabase> mailDBFactory;
00950   nsCOMPtr<nsIMsgFolder> child;
00951 
00952   nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
00953   if (msgDBService)
00954   {
00955     nsCOMPtr<nsIMsgDatabase> unusedDB;
00956     nsCOMPtr <nsIFileSpec> dbFileSpec;
00957 
00958     // warning, path will be changed
00959     rv = CreateFileSpecForDB(folderName, path, getter_AddRefs(dbFileSpec));
00960     NS_ENSURE_SUCCESS(rv,rv);
00961 
00962     //Now let's create the actual new folder
00963     rv = AddSubfolderWithPath(folderNameStr, dbFileSpec, getter_AddRefs(child));
00964     NS_ENSURE_SUCCESS(rv, rv);
00965     rv = msgDBService->OpenMailDBFromFileSpec(dbFileSpec, PR_TRUE, PR_TRUE, (nsIMsgDatabase **) getter_AddRefs(unusedDB));
00966    if (rv == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00967      rv = NS_OK;
00968 
00969     if (NS_SUCCEEDED(rv) && unusedDB)
00970     {
00971     //need to set the folder name
00972       nsCOMPtr <nsIDBFolderInfo> folderInfo;
00973       rv = unusedDB->GetDBFolderInfo(getter_AddRefs(folderInfo));
00974 //      if(NS_SUCCEEDED(rv))
00975 //      {
00976         // ### DMB used to be leafNameFromUser?
00977 //        folderInfo->SetMailboxName(&folderNameStr);
00978 //      }
00979 
00980       nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(child);
00981       if (imapFolder)
00982       {
00983         nsCAutoString onlineName(m_onlineFolderName); 
00984         if (!onlineName.IsEmpty())
00985           onlineName.Append(char(hierarchyDelimiter));
00986         onlineName.AppendWithConversion(folderNameStr);
00987         imapFolder->SetVerifiedAsOnlineFolder(PR_TRUE);
00988         imapFolder->SetOnlineName(onlineName.get());
00989         imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
00990         imapFolder->SetBoxFlags(flags);
00991    
00992         child->SetFlag(MSG_FOLDER_FLAG_ELIDED);
00993         nsXPIDLString unicodeName;
00994         rv = CopyMUTF7toUTF16(nsDependentCString(folderName), unicodeName);
00995         if (NS_SUCCEEDED(rv))
00996           child->SetPrettyName(unicodeName);
00997  
00998         // store the online name as the mailbox name in the db folder info
00999         // I don't think anyone uses the mailbox name, so we'll use it
01000         // to restore the online name when blowing away an imap db.
01001         if (folderInfo)
01002         {
01003           nsAutoString unicodeOnlineName; unicodeOnlineName.AssignWithConversion(onlineName.get());
01004           folderInfo->SetMailboxName(unicodeOnlineName);
01005         }
01006       }
01007 
01008       unusedDB->SetSummaryValid(PR_TRUE);
01009       unusedDB->Commit(nsMsgDBCommitType::kLargeCommit);
01010       unusedDB->Close(PR_TRUE);
01011       // don't want to hold onto this newly created db.
01012       child->SetMsgDatabase(nsnull);
01013     }
01014   }
01015   if (!suppressNotification)
01016   {
01017     nsCOMPtr <nsIAtom> folderCreateAtom;
01018     if(NS_SUCCEEDED(rv) && child)
01019     {
01020       NotifyItemAdded(child);
01021       folderCreateAtom = do_GetAtom("FolderCreateCompleted");
01022       child->NotifyFolderEvent(folderCreateAtom);
01023     }
01024     else
01025     {
01026       folderCreateAtom = do_GetAtom("FolderCreateFailed");
01027       NotifyFolderEvent(folderCreateAtom);
01028     }
01029   }
01030   return rv;
01031 }
01032     
01033 NS_IMETHODIMP nsImapMailFolder::List()
01034 {
01035   nsresult rv;
01036   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
01037   NS_ENSURE_SUCCESS(rv,rv);
01038 
01039   rv = imapService->ListFolder(m_eventQueue, this, this, nsnull);
01040   return rv;
01041 }
01042 
01043 NS_IMETHODIMP nsImapMailFolder::RemoveSubFolder (nsIMsgFolder *which)
01044 {
01045     nsCOMPtr<nsISupportsArray> folders;
01046     nsresult rv = NS_NewISupportsArray(getter_AddRefs(folders));
01047     if (NS_FAILED(rv)) return rv;
01048     nsCOMPtr<nsISupports> folderSupport = do_QueryInterface(which, &rv);
01049     if (NS_FAILED(rv)) return rv;
01050     folders->AppendElement(folderSupport);
01051     rv = nsMsgDBFolder::DeleteSubFolders(folders, nsnull);
01052     which->Delete();
01053     return rv;
01054 }
01055 
01056 NS_IMETHODIMP nsImapMailFolder::CreateStorageIfMissing(nsIUrlListener* urlListener)
01057 {
01058    nsresult status = NS_OK;
01059   nsCOMPtr <nsIMsgFolder> msgParent;
01060   GetParentMsgFolder(getter_AddRefs(msgParent));
01061 
01062   // parent is probably not set because *this* was probably created by rdf
01063   // and not by folder discovery. So, we have to compute the parent.
01064   if (!msgParent)
01065   {
01066     nsCAutoString folderName(mURI);
01067       
01068     PRInt32 leafPos = folderName.RFindChar('/');
01069     nsCAutoString parentName(folderName);
01070 
01071     if (leafPos > 0)
01072     {
01073       // If there is a hierarchy, there is a parent.
01074       // Don't strip off slash if it's the first character
01075       parentName.Truncate(leafPos);
01076       // get the corresponding RDF resource
01077       // RDF will create the folder resource if it doesn't already exist
01078       nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &status));
01079       if (NS_FAILED(status)) return status;
01080       nsCOMPtr<nsIRDFResource> resource;
01081       status = rdf->GetResource(parentName, getter_AddRefs(resource));
01082       if (NS_FAILED(status)) return status;
01083 
01084       msgParent = do_QueryInterface(resource, &status);
01085     }
01086   }
01087   if (msgParent)
01088   {
01089     nsXPIDLString folderName;
01090     GetName(getter_Copies(folderName));
01091     nsresult rv;
01092     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv); 
01093     if (NS_SUCCEEDED(rv) && imapService)
01094     {
01095       nsCOMPtr <nsIURI> uri;
01096       imapService->EnsureFolderExists(m_eventQueue, msgParent, folderName.get(), urlListener, getter_AddRefs(uri));
01097     }
01098   }
01099 
01100   return status;
01101 }
01102 
01103 
01104 NS_IMETHODIMP nsImapMailFolder::GetVerifiedAsOnlineFolder(PRBool *aVerifiedAsOnlineFolder)
01105 {
01106 
01107   if (!aVerifiedAsOnlineFolder)
01108     return NS_ERROR_NULL_POINTER;
01109 
01110   *aVerifiedAsOnlineFolder = m_verifiedAsOnlineFolder;
01111   return NS_OK;
01112 }
01113 
01114 NS_IMETHODIMP nsImapMailFolder::SetVerifiedAsOnlineFolder(PRBool aVerifiedAsOnlineFolder)
01115 {
01116   m_verifiedAsOnlineFolder = aVerifiedAsOnlineFolder;
01117   // mark ancestors as verified as well
01118   if (aVerifiedAsOnlineFolder)
01119   {
01120     nsCOMPtr<nsIMsgFolder> parent;
01121     do
01122     {
01123       GetParent(getter_AddRefs(parent));
01124       if (parent)
01125       {
01126         nsCOMPtr<nsIMsgImapMailFolder> imapParent = do_QueryInterface(parent);
01127         if (imapParent)
01128         {
01129           PRBool verifiedOnline;
01130           imapParent->GetVerifiedAsOnlineFolder(&verifiedOnline);
01131           if (verifiedOnline)
01132             break;
01133           imapParent->SetVerifiedAsOnlineFolder(PR_TRUE);
01134         }
01135       }
01136     }
01137     while (parent);
01138   }
01139   return NS_OK;
01140 }
01141 
01142 NS_IMETHODIMP nsImapMailFolder::GetOnlineDelimiter(char** onlineDelimiter)
01143 {
01144   if (onlineDelimiter)
01145   {
01146     nsresult rv;
01147     PRUnichar delimiter = 0;
01148     rv = GetHierarchyDelimiter(&delimiter);
01149     nsAutoString aString(delimiter);
01150     *onlineDelimiter = ToNewCString(aString);
01151     return rv;
01152   }
01153   return NS_ERROR_NULL_POINTER;
01154 }
01155 
01156 NS_IMETHODIMP nsImapMailFolder::SetHierarchyDelimiter(PRUnichar aHierarchyDelimiter)
01157 {
01158   m_hierarchyDelimiter = aHierarchyDelimiter;
01159   return NS_OK;
01160 }
01161 
01162 NS_IMETHODIMP nsImapMailFolder::GetHierarchyDelimiter(PRUnichar *aHierarchyDelimiter)
01163 {
01164   NS_ENSURE_ARG_POINTER(aHierarchyDelimiter);
01165   if (mIsServer) 
01166   {
01167     // if it's the root folder, we don't know the delimiter. So look at the
01168     // first child.
01169     PRUint32 count = 0;
01170     (void) mSubFolders->Count(&count);
01171     if (count > 0)
01172     {
01173       nsCOMPtr<nsIMsgImapMailFolder> childFolder = do_QueryElementAt(mSubFolders, 0);
01174       if (childFolder)
01175         return childFolder->GetHierarchyDelimiter(aHierarchyDelimiter);
01176     }
01177   }
01178   ReadDBFolderInfo(PR_FALSE); // update cache first.
01179   *aHierarchyDelimiter = m_hierarchyDelimiter;
01180   return NS_OK;
01181 }
01182 
01183 NS_IMETHODIMP nsImapMailFolder::SetBoxFlags(PRInt32 aBoxFlags)
01184 {
01185   ReadDBFolderInfo(PR_FALSE);
01186 
01187   m_boxFlags = aBoxFlags;
01188   PRUint32 newFlags = mFlags;
01189 
01190   newFlags |= MSG_FOLDER_FLAG_IMAPBOX;
01191 
01192   if (m_boxFlags & kNoinferiors)
01193     newFlags |= MSG_FOLDER_FLAG_IMAP_NOINFERIORS;
01194   else
01195     newFlags &= ~MSG_FOLDER_FLAG_IMAP_NOINFERIORS;
01196     if (m_boxFlags & kNoselect)
01197         newFlags |= MSG_FOLDER_FLAG_IMAP_NOSELECT;
01198     else
01199         newFlags &= ~MSG_FOLDER_FLAG_IMAP_NOSELECT;
01200     if (m_boxFlags & kPublicMailbox)
01201         newFlags |= MSG_FOLDER_FLAG_IMAP_PUBLIC;
01202     else
01203         newFlags &= ~MSG_FOLDER_FLAG_IMAP_PUBLIC;
01204     if (m_boxFlags & kOtherUsersMailbox)
01205         newFlags |= MSG_FOLDER_FLAG_IMAP_OTHER_USER;
01206     else
01207         newFlags &= ~MSG_FOLDER_FLAG_IMAP_OTHER_USER;
01208     if (m_boxFlags & kPersonalMailbox)
01209         newFlags |= MSG_FOLDER_FLAG_IMAP_PERSONAL;
01210     else
01211         newFlags &= ~MSG_FOLDER_FLAG_IMAP_PERSONAL;
01212 
01213     SetFlags(newFlags);
01214   return NS_OK;
01215 }
01216 
01217 NS_IMETHODIMP nsImapMailFolder::GetBoxFlags(PRInt32 *aBoxFlags)
01218 {
01219   if (!aBoxFlags)
01220     return NS_ERROR_NULL_POINTER;
01221   *aBoxFlags = m_boxFlags;
01222   return NS_OK;
01223 }
01224 
01225 
01226 NS_IMETHODIMP nsImapMailFolder::GetExplicitlyVerify(PRBool *aExplicitlyVerify)
01227 {
01228   if (!aExplicitlyVerify)
01229     return NS_ERROR_NULL_POINTER;
01230   *aExplicitlyVerify = m_explicitlyVerify;
01231   return NS_OK;
01232 }
01233 
01234 NS_IMETHODIMP nsImapMailFolder::SetExplicitlyVerify(PRBool aExplicitlyVerify)
01235 {
01236   m_explicitlyVerify = aExplicitlyVerify;
01237   return NS_OK;
01238 }
01239 
01240 NS_IMETHODIMP nsImapMailFolder::GetNoSelect(PRBool *aResult)
01241 {
01242   NS_ENSURE_ARG_POINTER(aResult);
01243   return GetFlag(MSG_FOLDER_FLAG_IMAP_NOSELECT, aResult);
01244 }
01245 
01246 NS_IMETHODIMP nsImapMailFolder::Compact(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow)
01247 {
01248   nsresult rv;
01249 
01250   rv = GetDatabase(nsnull);
01251   // now's a good time to apply the retention settings. If we do delete any
01252   // messages, the expunge is going to have to wait until the delete to 
01253   // finish before it can run, but the multiple-connection protection code
01254   // should handle that.
01255   if (mDatabase)
01256     ApplyRetentionSettings();
01257 
01258   // compact offline store, if folder configured for offline use.
01259   // for now, check aMsgWindow because not having aMsgWindow means
01260   // we're doing a compact at shut-down. TEMPORARY HACK
01261   if (aMsgWindow && mFlags & MSG_FOLDER_FLAG_OFFLINE)
01262     CompactOfflineStore(aMsgWindow);
01263 
01264   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
01265   NS_ENSURE_SUCCESS(rv,rv);
01266  
01267   return  imapService->Expunge(m_eventQueue, this, aListener, nsnull);
01268 }
01269 
01270 NS_IMETHODIMP nsImapMailFolder::CompactAll(nsIUrlListener *aListener,  nsIMsgWindow *aMsgWindow, nsISupportsArray *aFolderArray, PRBool aCompactOfflineAlso, nsISupportsArray *aOfflineFolderArray)
01271 {
01272   NS_ASSERTION(!aOfflineFolderArray, "compacting automatically compacts offline stores");
01273   nsresult rv = NS_OK;
01274   nsCOMPtr<nsISupportsArray> folderArray; 
01275 
01276   if (!aFolderArray)
01277   {
01278     nsCOMPtr<nsIMsgFolder> rootFolder;
01279     nsCOMPtr<nsISupportsArray> allDescendents;
01280     rv = GetRootFolder(getter_AddRefs(rootFolder));  
01281     if (NS_SUCCEEDED(rv) && rootFolder)
01282     {
01283       NS_NewISupportsArray(getter_AddRefs(allDescendents));
01284       rootFolder->ListDescendents(allDescendents);
01285       PRUint32 cnt =0;
01286       rv = allDescendents->Count(&cnt);
01287       NS_ENSURE_SUCCESS(rv,rv);
01288       NS_NewISupportsArray(getter_AddRefs(folderArray));
01289       for (PRUint32 i=0; i< cnt;i++)
01290       {
01291         nsCOMPtr<nsISupports> supports = getter_AddRefs(allDescendents->ElementAt(i));
01292         nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(supports, &rv);
01293         NS_ENSURE_SUCCESS(rv,rv);
01294         rv = folderArray->AppendElement(supports);
01295 
01296       }
01297       rv = folderArray->Count(&cnt);
01298       NS_ENSURE_SUCCESS(rv,rv);
01299       if (cnt == 0 )
01300         return NotifyCompactCompleted();
01301     }
01302   }
01303   nsCOMPtr <nsIMsgFolderCompactor> folderCompactor =  do_CreateInstance(NS_MSGLOCALFOLDERCOMPACTOR_CONTRACTID, &rv);
01304   if (NS_SUCCEEDED(rv) && folderCompactor)
01305     if (aFolderArray)
01306        rv = folderCompactor->CompactAll(aFolderArray, aMsgWindow, aCompactOfflineAlso, aOfflineFolderArray);  
01307     else if (folderArray)
01308        rv = folderCompactor->CompactAll(folderArray, aMsgWindow, aCompactOfflineAlso, aOfflineFolderArray);  
01309   return rv;
01310 }
01311 
01312 NS_IMETHODIMP nsImapMailFolder::UpdateStatus(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow)
01313 {
01314   nsresult rv;
01315   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
01316   NS_ENSURE_SUCCESS(rv,rv);
01317 
01318   nsCOMPtr <nsIURI> uri;
01319 
01320   rv = imapService->UpdateFolderStatus(m_eventQueue, this, aListener, getter_AddRefs(uri));
01321   if (uri)
01322   {
01323     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(uri);
01324     // if no msg window, we won't put up error messages (this is almost certainly a biff-inspired status)
01325     if (!aMsgWindow)
01326       mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE);
01327   }
01328   return rv;
01329 }
01330 
01331 NS_IMETHODIMP nsImapMailFolder::EmptyTrash(nsIMsgWindow *aMsgWindow,
01332                                            nsIUrlListener *aListener)
01333 {
01334     nsCOMPtr<nsIMsgFolder> trashFolder;
01335     nsresult rv = GetTrashFolder(getter_AddRefs(trashFolder));
01336     if (NS_SUCCEEDED(rv))
01337     {
01338        nsCOMPtr<nsIMsgAccountManager> accountManager = 
01339                 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
01340        if (accountManager)
01341        {
01342          // if we are emptying trash on exit and we are an aol server then don't perform
01343          // this operation because it's causing a hang that we haven't been able to figure out yet
01344          // this is an rtm fix and we'll look for the right solution post rtm. 
01345 
01346          PRBool empytingOnExit = PR_FALSE;
01347          accountManager->GetEmptyTrashInProgress(&empytingOnExit);
01348          if (empytingOnExit)
01349          {
01350             nsCOMPtr<nsIImapIncomingServer> imapServer;
01351             rv = GetImapIncomingServer(getter_AddRefs(imapServer));
01352 
01353             if (NS_SUCCEEDED(rv) && imapServer) 
01354             {
01355               PRBool isAOLServer = PR_FALSE;
01356               imapServer->GetIsAOLServer(&isAOLServer);
01357               if (isAOLServer)
01358                 return NS_ERROR_FAILURE;  // we will not be performing an empty trash....
01359             } // if we fetched an imap server
01360          } // if emptying trash on exit which is done through the account manager.
01361        }
01362 
01363         nsCOMPtr<nsIMsgDatabase> trashDB;
01364 
01365         if (WeAreOffline())
01366         {
01367           nsCOMPtr <nsIMsgDatabase> trashDB;
01368           rv = trashFolder->GetMsgDatabase(nsnull, getter_AddRefs(trashDB));
01369           if (NS_SUCCEEDED(rv) && trashDB)
01370           {
01371             nsMsgKey fakeKey;
01372             trashDB->GetNextFakeOfflineMsgKey(&fakeKey);
01373     
01374             nsCOMPtr <nsIMsgOfflineImapOperation> op;
01375             rv = trashDB->GetOfflineOpForKey(fakeKey, PR_TRUE, getter_AddRefs(op));
01376             trashFolder->SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
01377             op->SetOperation(nsIMsgOfflineImapOperation::kDeleteAllMsgs);
01378           }
01379           return rv;
01380         }
01381         nsCOMPtr <nsIDBFolderInfo> transferInfo;
01382         rv = trashFolder->GetDBTransferInfo(getter_AddRefs(transferInfo));
01383         rv = trashFolder->Delete(); // delete summary spec
01384         trashFolder->SetDBTransferInfo(transferInfo);
01385 
01386         trashFolder->SetSizeOnDisk(0);
01387         nsCOMPtr<nsIImapService> imapService = 
01388                  do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
01389         if (NS_SUCCEEDED(rv))
01390         {
01391         PRBool hasSubfolders = PR_FALSE;
01392         rv = trashFolder->GetHasSubFolders(&hasSubfolders);
01393         if (hasSubfolders)
01394         {
01395             nsCOMPtr<nsIEnumerator> aEnumerator;
01396             nsCOMPtr<nsISupports> aSupport;
01397             nsCOMPtr<nsIMsgFolder> aFolder;
01398             nsCOMPtr<nsISupportsArray> aSupportsArray;
01399             rv = NS_NewISupportsArray(getter_AddRefs(aSupportsArray));
01400             if (NS_FAILED(rv)) return rv;
01401             rv = trashFolder->GetSubFolders(getter_AddRefs(aEnumerator));
01402             PRBool confirmDeletion;
01403             nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
01404             if (NS_SUCCEEDED(rv))
01405               prefBranch->GetBoolPref("mail.imap.confirm_emptyTrashFolderDeletion", &confirmDeletion);
01406 
01407             nsXPIDLString confirmationStr;
01408             nsCOMPtr<nsIStringBundle> bundle;
01409             nsCOMPtr<nsIDOMWindowInternal> parentWindow;
01410             nsCOMPtr<nsIPromptService> promptService;
01411             if (confirmDeletion)
01412             {
01413               IMAPGetStringByID(IMAP_EMPTY_TRASH_CONFIRM, getter_Copies(confirmationStr));
01414               promptService = do_GetService(NS_PROMPTSERVICE_CONTRACTID);
01415               nsCOMPtr<nsIDocShell> docShell;
01416               if (aMsgWindow)
01417               {
01418                      (void) aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
01419                    parentWindow = do_QueryInterface(docShell);
01420               }
01421               rv = IMAPGetStringBundle(getter_AddRefs(bundle));
01422               NS_ENSURE_SUCCESS(rv, rv);
01423             rv = aEnumerator->First();
01424             while(NS_SUCCEEDED(rv))
01425             {
01426                 PRInt32 dlgResult  = -1;
01427                 rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
01428                 if (confirmDeletion)
01429                 {
01430                   nsXPIDLString statusString, confirmText;
01431                   nsCOMPtr <nsIMsgFolder> folder = do_QueryInterface(aSupport);
01432                   nsXPIDLString folderName;
01433                   folder->GetName(getter_Copies(folderName));
01434                   const PRUnichar *formatStrings[1] = { folderName.get() };
01435 
01436                   rv = bundle->FormatStringFromID(IMAP_EMPTY_TRASH_CONFIRM,
01437                                                     formatStrings, 1,
01438                                                     getter_Copies(confirmText));
01439                   // Got the text, now show dialog.
01440                   rv = promptService->ConfirmEx(parentWindow, nsnull, confirmText,
01441                                               (nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0) +
01442                                               (nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_1), 
01443                                                 nsnull, nsnull, nsnull, nsnull, nsnull, &dlgResult);
01444                 }
01445               if ( NS_SUCCEEDED( rv ) ) 
01446               {
01447                   if (dlgResult == 1)
01448                   return NS_BINDING_ABORTED;
01449                 rv = aEnumerator->Next();
01450               }
01451             }
01452           }
01453         }
01454         if (aListener)
01455         {
01456             rv = imapService->DeleteAllMessages(m_eventQueue, trashFolder,
01457                                                 aListener, nsnull);
01458         }
01459         else
01460         {
01461             nsCOMPtr<nsIUrlListener> urlListener = 
01462                 do_QueryInterface(trashFolder);
01463             rv = imapService->DeleteAllMessages(m_eventQueue, trashFolder,
01464                                                 urlListener, nsnull);
01465         }
01466         // return an error if this failed. We want the empty trash on exit code
01467         // to know if this fails so that it doesn't block waiting for empty trash to finish.
01468         if (NS_FAILED(rv))
01469           return rv;
01470         if (hasSubfolders)
01471         {
01472             nsCOMPtr<nsIEnumerator> aEnumerator;
01473             nsCOMPtr<nsISupports> aSupport;
01474             nsCOMPtr<nsIMsgFolder> aFolder;
01475             nsCOMPtr<nsISupportsArray> aSupportsArray;
01476             rv = NS_NewISupportsArray(getter_AddRefs(aSupportsArray));
01477             if (NS_FAILED(rv)) return rv;
01478             rv = trashFolder->GetSubFolders(getter_AddRefs(aEnumerator));
01479 
01480             rv = aEnumerator->First();
01481             while(NS_SUCCEEDED(rv))
01482             {
01483                 rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
01484                       aSupportsArray->AppendElement(aSupport);
01485                   rv = aEnumerator->Next();
01486               }
01487               PRUint32 cnt = 0;
01488               aSupportsArray->Count(&cnt);
01489               for (PRInt32 i = cnt-1; i >= 0; i--)
01490               {
01491                   aFolder = do_QueryElementAt(aSupportsArray, i);
01492                   aSupportsArray->RemoveElementAt(i);
01493                   if (aFolder)
01494                       trashFolder->PropagateDelete(aFolder, PR_TRUE, aMsgWindow);
01495               }
01496             }
01497         }
01498 
01499         return NS_OK;
01500     }
01501 
01502     return rv;
01503 }
01504 
01505 NS_IMETHODIMP nsImapMailFolder::Delete ()
01506 {
01507     nsresult rv = NS_ERROR_FAILURE;
01508     if (mDatabase)
01509     {
01510         mDatabase->ForceClosed();
01511         mDatabase = nsnull;
01512     }
01513 
01514     nsCOMPtr<nsIFileSpec> pathSpec;
01515     rv = GetPath(getter_AddRefs(pathSpec));
01516     if (NS_SUCCEEDED(rv))
01517     {
01518         nsFileSpec fileSpec;
01519         rv = pathSpec->GetFileSpec(&fileSpec);
01520         if (NS_SUCCEEDED(rv))
01521         {
01522             nsLocalFolderSummarySpec summarySpec(fileSpec);
01523             if (summarySpec.Exists())
01524                 summarySpec.Delete(PR_FALSE);
01525         }
01526     }
01527     if (mPath)
01528     {
01529       nsFileSpec fileSpec;
01530       if (NS_SUCCEEDED(mPath->GetFileSpec(&fileSpec)) && fileSpec.Exists())
01531         fileSpec.Delete(PR_FALSE);
01532     }
01533     // should notify nsIMsgFolderListeners about the folder getting deleted...
01534     return rv;
01535 }
01536 
01537 NS_IMETHODIMP nsImapMailFolder::Rename (const PRUnichar *newName, nsIMsgWindow *msgWindow )
01538 {
01539     if (mFlags & MSG_FOLDER_FLAG_VIRTUAL)
01540       return nsMsgDBFolder::Rename(newName, msgWindow);
01541     nsresult rv = NS_ERROR_FAILURE;
01542     nsAutoString newNameStr(newName);
01543     if (newNameStr.FindChar(m_hierarchyDelimiter,0) != -1)
01544     {
01545       nsCOMPtr<nsIDocShell> docShell;
01546       if (msgWindow)
01547         msgWindow->GetRootDocShell(getter_AddRefs(docShell));
01548       if (docShell)
01549       {
01550         nsCOMPtr<nsIStringBundle> bundle;
01551         rv = IMAPGetStringBundle(getter_AddRefs(bundle));
01552         if (NS_SUCCEEDED(rv) && bundle)
01553         {
01554           const PRUnichar *formatStrings[] =
01555           {
01556              (const PRUnichar*) m_hierarchyDelimiter
01557           };
01558           nsXPIDLString alertString;
01559           rv = bundle->FormatStringFromID(IMAP_SPECIAL_CHAR,
01560                                         formatStrings, 1,
01561                                         getter_Copies(alertString));
01562           nsCOMPtr<nsIPrompt> dialog(do_GetInterface(docShell));
01563           if (dialog && alertString)
01564             dialog->Alert(nsnull, alertString);
01565         }
01566       }
01567       return NS_ERROR_FAILURE;
01568     }
01569     nsCOMPtr <nsIImapIncomingServer> incomingImapServer;
01570 
01571     GetImapIncomingServer(getter_AddRefs(incomingImapServer));
01572     if (incomingImapServer)
01573       RecursiveCloseActiveConnections(incomingImapServer);
01574 
01575     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
01576     NS_ENSURE_SUCCESS(rv,rv);
01577 
01578     return imapService->RenameLeaf(m_eventQueue, this, newName, this, msgWindow,
01579                                      nsnull);
01580 }
01581 
01582 NS_IMETHODIMP nsImapMailFolder::RecursiveCloseActiveConnections(nsIImapIncomingServer *incomingImapServer)
01583 {
01584   NS_ENSURE_ARG(incomingImapServer);
01585   PRUint32 cnt = 0, i;
01586   nsresult rv;
01587   if (mSubFolders)
01588   {
01589       nsCOMPtr<nsIMsgImapMailFolder> folder;
01590       mSubFolders->Count(&cnt);
01591       if (cnt > 0)
01592       {
01593           for (i = 0; i < cnt; i++)
01594           {
01595               folder = do_QueryElementAt(mSubFolders, i);
01596               if (folder)
01597                   folder->RecursiveCloseActiveConnections(incomingImapServer);
01598               nsCOMPtr<nsIMsgFolder> msgFolder = do_QueryInterface(folder, &rv);
01599               if (NS_SUCCEEDED(rv) && msgFolder)
01600                 incomingImapServer->CloseConnectionForFolder(msgFolder);
01601           }
01602       }
01603   }
01604   return NS_OK;  
01605 }
01606 
01607 // this is called *after* we've done the rename on the server.
01608 NS_IMETHODIMP nsImapMailFolder::PrepareToRename()
01609 {
01610     PRUint32 cnt = 0, i;
01611     if (mSubFolders)
01612     {
01613         nsCOMPtr<nsIMsgImapMailFolder> folder;
01614         mSubFolders->Count(&cnt);
01615         if (cnt > 0)
01616         {
01617             for (i = 0; i < cnt; i++)
01618             {
01619                 folder = do_QueryElementAt(mSubFolders, i);
01620                 if (folder)
01621                     folder->PrepareToRename();
01622             }
01623         }
01624     }
01625     SetOnlineName("");
01626     return NS_OK;
01627 }
01628 
01629 NS_IMETHODIMP nsImapMailFolder::RenameLocal(const char *newName, nsIMsgFolder *parent)
01630 {
01631     // XXX Here it's assumed that IMAP folder names are stored locally 
01632     // in modified UTF-7 (ASCII-only) as is stored remotely.  If we ever change
01633     // this, we have to work with nsString instead of nsCString 
01634     // (ref. bug 264071)
01635     nsCAutoString leafname(newName);
01636     nsCAutoString parentName;
01637     // newName always in the canonical form "greatparent/parentname/leafname"
01638     PRInt32 leafpos = leafname.RFindChar('/');
01639     if (leafpos >0) 
01640         leafname.Cut(0, leafpos+1);
01641     m_msgParser = nsnull;
01642     PrepareToRename();
01643     ForceDBClosed();
01644 
01645     nsresult rv = NS_OK;
01646     nsCOMPtr<nsIFileSpec> oldPathSpec;
01647     rv = GetPath(getter_AddRefs(oldPathSpec));
01648     if (NS_FAILED(rv)) return rv;
01649 
01650        nsCOMPtr<nsIFileSpec> parentPathSpec;
01651        rv = parent->GetPath(getter_AddRefs(parentPathSpec));
01652        NS_ENSURE_SUCCESS(rv,rv);
01653 
01654        nsFileSpec parentPath;
01655        rv = parentPathSpec->GetFileSpec(&parentPath);
01656        NS_ENSURE_SUCCESS(rv,rv);
01657 
01658     if (!parentPath.IsDirectory())
01659          AddDirectorySeparator(parentPath);
01660     
01661     PRUint32 cnt = 0;
01662     nsFileSpec dirSpec;
01663 
01664     if (mSubFolders)
01665         mSubFolders->Count(&cnt);
01666     if (cnt > 0)
01667         rv = CreateDirectoryForFolder(dirSpec);
01668 
01669     nsFileSpec fileSpec;
01670     oldPathSpec->GetFileSpec(&fileSpec);
01671     nsLocalFolderSummarySpec oldSummarySpec(fileSpec);
01672     nsCAutoString newNameStr;
01673     oldSummarySpec.Delete(PR_FALSE);
01674     if (cnt > 0)
01675     {
01676        newNameStr = leafname;
01677        NS_MsgHashIfNecessary(newNameStr);
01678        newNameStr += ".sbd";
01679        char *leafName = dirSpec.GetLeafName();
01680        if (nsCRT::strcmp(leafName, newNameStr.get()) != 0 )
01681        {
01682          dirSpec.Rename(newNameStr.get());      // in case of rename operation leaf names will differ
01683          nsCRT::free(leafName);
01684          return rv;
01685        }
01686        nsCRT::free(leafName);
01687                                            
01688        parentPath += newNameStr.get();    //only for move we need to progress further in case the parent differs
01689 
01690        if (!parentPath.IsDirectory())
01691          parentPath.CreateDirectory();
01692        else
01693          NS_ASSERTION(0,"Directory already exists.");
01694        
01695        nsCOMPtr<nsILocalFile> srcDir = (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
01696        NS_ENSURE_SUCCESS(rv,rv);
01697 
01698        nsCOMPtr<nsILocalFile> destDir = (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
01699        NS_ENSURE_SUCCESS(rv,rv);
01700          
01701        srcDir->InitWithNativePath(nsDependentCString(dirSpec.GetNativePathCString()));
01702           
01703        destDir->InitWithNativePath(nsDependentCString(parentPath.GetNativePathCString()));
01704        
01705        rv = RecursiveCopy(srcDir, destDir);
01706    
01707        NS_ENSURE_SUCCESS(rv,rv);
01708 
01709        dirSpec.Delete(PR_TRUE);                         // moving folders
01710     }
01711     return rv;
01712 }
01713 
01714 NS_IMETHODIMP nsImapMailFolder::GetPrettyName(PRUnichar ** prettyName)
01715 {
01716   return GetName(prettyName);
01717 }
01718     
01719 NS_IMETHODIMP nsImapMailFolder::UpdateSummaryTotals(PRBool force) 
01720 {
01721   if (!mNotifyCountChanges || mIsServer)
01722     return NS_OK;
01723 
01724   // could we move this into nsMsgDBFolder, or do we need to deal
01725   // with the pending imap counts?
01726   nsresult rv = NS_OK;
01727 
01728   PRInt32 oldUnreadMessages = mNumUnreadMessages + mNumPendingUnreadMessages;
01729   PRInt32 oldTotalMessages = mNumTotalMessages + mNumPendingTotalMessages;
01730   //We need to read this info from the database
01731   ReadDBFolderInfo(force);
01732 
01733   PRInt32 newUnreadMessages = mNumUnreadMessages + mNumPendingUnreadMessages;
01734   PRInt32 newTotalMessages = mNumTotalMessages + mNumPendingTotalMessages;
01735 
01736   //Need to notify listeners that total count changed.
01737   if(oldTotalMessages != newTotalMessages)
01738   {
01739     NotifyIntPropertyChanged(kTotalMessagesAtom, oldTotalMessages, newTotalMessages);
01740   }
01741 
01742   if(oldUnreadMessages != newUnreadMessages)
01743   {
01744     NotifyIntPropertyChanged(kTotalUnreadMessagesAtom, oldUnreadMessages, newUnreadMessages);
01745   }
01746 
01747   FlushToFolderCache();
01748   return rv;
01749 }
01750     
01751 NS_IMETHODIMP nsImapMailFolder::GetDeletable (PRBool *deletable)
01752 {
01753     nsresult rv = NS_ERROR_FAILURE;
01754     return rv;
01755 }
01756 
01757 NS_IMETHODIMP nsImapMailFolder::GetRequiresCleanup(PRBool *requiresCleanup)
01758 {
01759     nsresult rv = NS_ERROR_FAILURE;
01760     return rv;
01761 }
01762     
01763 NS_IMETHODIMP nsImapMailFolder::GetSizeOnDisk(PRUint32 * size)
01764 {
01765   NS_ENSURE_ARG_POINTER(size);
01766   *size = mFolderSize;
01767   return NS_OK;
01768 }
01769 
01770 NS_IMETHODIMP
01771 nsImapMailFolder::GetCanCreateSubfolders(PRBool *aResult)
01772 {
01773   NS_ENSURE_ARG_POINTER(aResult);
01774   *aResult = !(mFlags & (MSG_FOLDER_FLAG_IMAP_NOINFERIORS | MSG_FOLDER_FLAG_VIRTUAL));
01775 
01776   PRBool isServer = PR_FALSE;
01777   GetIsServer(&isServer);
01778   if (!isServer)
01779   {
01780       nsCOMPtr<nsIImapIncomingServer> imapServer;
01781       nsresult rv = GetImapIncomingServer(getter_AddRefs(imapServer));
01782       PRBool dualUseFolders = PR_TRUE;
01783       if (NS_SUCCEEDED(rv) && imapServer)
01784           imapServer->GetDualUseFolders(&dualUseFolders);
01785       if (!dualUseFolders && *aResult)
01786           *aResult = (mFlags & MSG_FOLDER_FLAG_IMAP_NOSELECT);
01787   }
01788   
01789   return NS_OK;
01790 }
01791 
01792 NS_IMETHODIMP
01793 nsImapMailFolder::GetCanSubscribe(PRBool *aResult)
01794 {
01795   NS_ENSURE_ARG_POINTER(aResult);
01796   *aResult = PR_FALSE;
01797 
01798   PRBool isImapServer = PR_FALSE;
01799   nsresult rv = GetIsServer(&isImapServer);
01800   if (NS_FAILED(rv)) return rv;
01801  
01802   // you can only subscribe to imap servers, not imap folders
01803   *aResult = isImapServer;
01804   return NS_OK;
01805 }
01806 
01807 nsresult nsImapMailFolder::GetServerKey(char **serverKey)
01808 {
01809   // look for matching imap folders, then pop folders
01810   nsCOMPtr<nsIMsgIncomingServer> server;
01811   nsresult rv = GetServer(getter_AddRefs(server));
01812   if (NS_SUCCEEDED(rv) && server)
01813     return server->GetKey(serverKey);
01814   return rv;
01815 }
01816 
01817 nsresult nsImapMailFolder::GetImapIncomingServer(nsIImapIncomingServer **aImapIncomingServer)
01818 {
01819   NS_ENSURE_ARG(aImapIncomingServer);
01820 
01821   *aImapIncomingServer = nsnull;
01822 
01823   nsCOMPtr<nsIMsgIncomingServer> server;
01824 
01825   if (NS_SUCCEEDED(GetServer(getter_AddRefs(server))) && server)
01826   {
01827     nsCOMPtr <nsIImapIncomingServer> incomingServer = do_QueryInterface(server);
01828     *aImapIncomingServer = incomingServer;
01829     NS_IF_ADDREF(*aImapIncomingServer);
01830     return NS_OK;
01831   }
01832   return NS_ERROR_NULL_POINTER;
01833 }
01834 
01835 NS_IMETHODIMP
01836 nsImapMailFolder::AddMessageDispositionState(nsIMsgDBHdr *aMessage, nsMsgDispositionState aDispositionFlag)
01837 {
01838   nsMsgDBFolder::AddMessageDispositionState(aMessage, aDispositionFlag);
01839 
01840   // set the mark message answered flag on the server for this message...
01841   if (aMessage)
01842   {
01843     nsMsgKeyArray messageIDs;
01844     nsMsgKey msgKey;
01845     aMessage->GetMessageKey(&msgKey);
01846     messageIDs.Add(msgKey);
01847 
01848     if (aDispositionFlag == nsIMsgFolder::nsMsgDispositionState_Replied)
01849       StoreImapFlags(kImapMsgAnsweredFlag, PR_TRUE, messageIDs.GetArray(), messageIDs.GetSize(), nsnull);
01850     else if (aDispositionFlag == nsIMsgFolder::nsMsgDispositionState_Forwarded)
01851       StoreImapFlags(kImapMsgForwardedFlag, PR_TRUE, messageIDs.GetArray(), messageIDs.GetSize(), nsnull);
01852   }
01853   return NS_OK;
01854 }
01855 
01856 NS_IMETHODIMP
01857 nsImapMailFolder::MarkMessagesRead(nsISupportsArray *messages, PRBool markRead)
01858 {
01859   // tell the folder to do it, which will mark them read in the db.
01860   nsresult rv = nsMsgDBFolder::MarkMessagesRead(messages, markRead);
01861   if (NS_SUCCEEDED(rv))
01862   {
01863     nsCAutoString messageIds;
01864     nsMsgKeyArray keysToMarkRead;
01865     rv = BuildIdsAndKeyArray(messages, messageIds, keysToMarkRead);
01866     if (NS_FAILED(rv)) return rv;
01867 
01868     StoreImapFlags(kImapMsgSeenFlag, markRead,  keysToMarkRead.GetArray(), keysToMarkRead.GetSize(), nsnull);
01869     rv = GetDatabase(nsnull);
01870     if (NS_SUCCEEDED(rv))
01871       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
01872   }
01873   return rv;
01874 }
01875 
01876 NS_IMETHODIMP
01877 nsImapMailFolder::SetLabelForMessages(nsISupportsArray *aMessages, nsMsgLabelValue aLabel)
01878 {
01879   NS_ENSURE_ARG(aMessages);
01880 
01881   nsresult rv = nsMsgDBFolder::SetLabelForMessages(aMessages, aLabel);
01882   if (NS_SUCCEEDED(rv))
01883   {
01884     nsCAutoString messageIds;
01885     nsMsgKeyArray keysToLabel;
01886     nsresult rv = BuildIdsAndKeyArray(aMessages, messageIds, keysToLabel);
01887     NS_ENSURE_SUCCESS(rv, rv);
01888     StoreImapFlags((aLabel << 9), PR_TRUE, keysToLabel.GetArray(), keysToLabel.GetSize(), nsnull);
01889     rv = GetDatabase(nsnull);
01890     if (NS_SUCCEEDED(rv))
01891       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
01892   }
01893   return rv;
01894 }
01895 
01896 NS_IMETHODIMP
01897 nsImapMailFolder::MarkAllMessagesRead(void)
01898 {
01899   nsresult rv = GetDatabase(nsnull);
01900   
01901   if(NS_SUCCEEDED(rv))
01902   {
01903     nsMsgKeyArray thoseMarked;
01904     EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE /*dbBatching*/);
01905     rv = mDatabase->MarkAllRead(&thoseMarked);
01906     EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE /*dbBatching*/);
01907     if (NS_SUCCEEDED(rv))
01908     {
01909       rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, thoseMarked.GetArray(), 
01910                           thoseMarked.GetSize(), nsnull);
01911       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
01912     }
01913   }
01914 
01915   return rv;
01916 }
01917 
01918 NS_IMETHODIMP nsImapMailFolder::MarkThreadRead(nsIMsgThread *thread)
01919 {
01920 
01921   nsresult rv = GetDatabase(nsnull);
01922   if(NS_SUCCEEDED(rv))
01923   {
01924     nsMsgKeyArray thoseMarked;
01925               rv = mDatabase->MarkThreadRead(thread, nsnull, &thoseMarked);
01926     if (NS_SUCCEEDED(rv))
01927     {
01928       rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, thoseMarked.GetArray(), 
01929                           thoseMarked.GetSize(), nsnull);
01930       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
01931     }
01932   }
01933   return rv;
01934 }
01935 
01936 
01937 NS_IMETHODIMP nsImapMailFolder::ReadFromFolderCacheElem(nsIMsgFolderCacheElement *element)
01938 {
01939   nsresult rv = nsMsgDBFolder::ReadFromFolderCacheElem(element);
01940   PRInt32 hierarchyDelimiter = kOnlineHierarchySeparatorUnknown;
01941   nsXPIDLCString onlineName;
01942 
01943   element->GetInt32Property("boxFlags", &m_boxFlags);
01944   if (NS_SUCCEEDED(element->GetInt32Property("hierDelim", &hierarchyDelimiter)) 
01945       && hierarchyDelimiter != kOnlineHierarchySeparatorUnknown)
01946     m_hierarchyDelimiter = (PRUnichar) hierarchyDelimiter;
01947   rv = element->GetStringProperty("onlineName", getter_Copies(onlineName));
01948   if (NS_SUCCEEDED(rv) && (const char *) onlineName && strlen((const char *) onlineName))
01949     m_onlineFolderName.Assign(onlineName);
01950 
01951   m_aclFlags = -1; // init to invalid value.
01952   element->GetInt32Property("aclFlags", (PRInt32 *) &m_aclFlags);
01953 #ifdef DEBUG_bienvenu
01954   if (!nsCRT::strcasecmp((const char *) onlineName, "Sent"))
01955     printf("loading folder cache elem for %s flags = %lx", (const char *) onlineName, mFlags);
01956   else if (!nsCRT::strcasecmp((const char *) onlineName, "INBOX"))
01957     printf("loading folder cache elem for %s flags = %lx", (const char *) onlineName, mFlags);
01958 #endif
01959   return rv;
01960 }
01961 
01962 NS_IMETHODIMP nsImapMailFolder::WriteToFolderCacheElem(nsIMsgFolderCacheElement *element)
01963 {
01964   nsresult rv = nsMsgDBFolder::WriteToFolderCacheElem(element);
01965   element->SetInt32Property("boxFlags", m_boxFlags);
01966   element->SetInt32Property("hierDelim", (PRInt32) m_hierarchyDelimiter);
01967   element->SetStringProperty("onlineName", m_onlineFolderName.get());
01968   element->SetInt32Property("aclFlags", (PRInt32) m_aclFlags);
01969   return rv;
01970 }
01971 
01972 
01973 
01974 NS_IMETHODIMP
01975 nsImapMailFolder::MarkMessagesFlagged(nsISupportsArray *messages, PRBool markFlagged)
01976 {
01977   nsresult rv;
01978 
01979   // tell the folder to do it, which will mark them read in the db.
01980   rv = nsMsgDBFolder::MarkMessagesFlagged(messages, markFlagged);
01981   if (NS_SUCCEEDED(rv))
01982   {
01983     nsCAutoString messageIds;
01984         nsMsgKeyArray keysToMarkFlagged;
01985     rv = BuildIdsAndKeyArray(messages, messageIds, keysToMarkFlagged);
01986     if (NS_FAILED(rv)) return rv;
01987 
01988     rv = StoreImapFlags(kImapMsgFlaggedFlag, markFlagged,  keysToMarkFlagged.GetArray(), 
01989                         keysToMarkFlagged.GetSize(), nsnull);
01990     mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
01991   }
01992   return rv;
01993 }
01994 
01995 
01996 NS_IMETHODIMP nsImapMailFolder::SetOnlineName(const char * aOnlineFolderName)
01997 {
01998   nsresult rv;
01999   nsCOMPtr<nsIMsgDatabase> db; 
02000   nsCOMPtr<nsIDBFolderInfo> folderInfo;
02001   rv = GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(db));
02002   // do this after GetDBFolderInfoAndDB, because it crunches m_onlineFolderName (not sure why)
02003   m_onlineFolderName = aOnlineFolderName;
02004   if(NS_SUCCEEDED(rv) && folderInfo)
02005   {
02006     nsAutoString onlineName; onlineName.AssignWithConversion(aOnlineFolderName);
02007     rv = folderInfo->SetProperty("onlineName", onlineName);
02008     rv = folderInfo->SetMailboxName(onlineName);
02009     // so, when are we going to commit this? Definitely not every time!
02010     // We could check if the online name has changed.
02011     db->Commit(nsMsgDBCommitType::kLargeCommit);
02012   }
02013   folderInfo = nsnull;
02014   return rv;
02015 }
02016 
02017 
02018 NS_IMETHODIMP nsImapMailFolder::GetOnlineName(char ** aOnlineFolderName)
02019 {
02020   if (!aOnlineFolderName)
02021     return NS_ERROR_NULL_POINTER;
02022   ReadDBFolderInfo(PR_FALSE); // update cache first.
02023   *aOnlineFolderName = ToNewCString(m_onlineFolderName);
02024   return (*aOnlineFolderName) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
02025 
02026   // ### do we want to read from folder cache first, or has that been done?
02027 }
02028 
02029 
02030 NS_IMETHODIMP
02031 nsImapMailFolder::GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db)
02032 {
02033   nsresult openErr=NS_ERROR_UNEXPECTED;
02034   if(!db || !folderInfo)
02035     return NS_ERROR_NULL_POINTER; //ducarroz: should we use NS_ERROR_INVALID_ARG?
02036   nsresult rv;
02037 
02038   openErr = GetDatabase(nsnull);
02039 
02040   *db = mDatabase;
02041   NS_IF_ADDREF(*db);
02042   if (NS_SUCCEEDED(openErr)&& *db)
02043   {
02044     openErr = (*db)->GetDBFolderInfo(folderInfo);
02045     if (NS_SUCCEEDED(openErr) && folderInfo)
02046     {
02047       nsXPIDLCString onlineName;
02048       if (NS_SUCCEEDED((*folderInfo)->GetCharPtrProperty("onlineName", getter_Copies(onlineName))))
02049       {
02050         if (!onlineName.IsEmpty())
02051           m_onlineFolderName.Assign(onlineName);
02052         else
02053         {
02054           nsAutoString autoOnlineName; 
02055           // autoOnlineName.AssignWithConversion(name);
02056           (*folderInfo)->GetMailboxName(autoOnlineName);
02057           if (autoOnlineName.IsEmpty())
02058           {
02059             nsXPIDLCString uri;
02060             rv = GetURI(getter_Copies(uri));
02061             if (NS_FAILED(rv)) return rv;
02062             nsXPIDLCString hostname;
02063             rv = GetHostname(getter_Copies(hostname));
02064             if (NS_FAILED(rv)) return rv;
02065             nsXPIDLCString name;
02066             rv = nsImapURI2FullName(kImapRootURI, hostname, uri, getter_Copies(name));
02067             nsCAutoString onlineCName(name);
02068             if (m_hierarchyDelimiter != '/')
02069               onlineCName.ReplaceChar('/',  char(m_hierarchyDelimiter));
02070             m_onlineFolderName.Assign(onlineCName); 
02071             autoOnlineName.AssignWithConversion(onlineCName.get());
02072           }
02073           rv = (*folderInfo)->SetProperty("onlineName", autoOnlineName);
02074         }
02075       }
02076     }
02077   }
02078   return openErr;
02079 }
02080 
02081 nsresult
02082 nsImapMailFolder::BuildIdsAndKeyArray(nsISupportsArray* messages,
02083                                       nsCString& msgIds,
02084                                       nsMsgKeyArray& keyArray)
02085 {
02086     nsresult rv = NS_ERROR_NULL_POINTER;
02087     PRUint32 count = 0;
02088     PRUint32 i;
02089 
02090     if (!messages) return rv;
02091 
02092     rv = messages->Count(&count);
02093     if (NS_FAILED(rv)) return rv;
02094 
02095     // build up message keys.
02096     for (i = 0; i < count; i++)
02097     {
02098       nsMsgKey key;
02099       nsCOMPtr <nsIMsgDBHdr> msgDBHdr = do_QueryElementAt(messages, i, &rv);
02100       if (msgDBHdr)
02101         rv = msgDBHdr->GetMessageKey(&key);
02102       if (NS_SUCCEEDED(rv))
02103         keyArray.Add(key);
02104     }
02105     
02106   return AllocateUidStringFromKeys(keyArray.GetArray(), keyArray.GetSize(), msgIds);
02107 }
02108 
02109 static int PR_CALLBACK CompareKey (const void *v1, const void *v2, void *)
02110 {
02111        // QuickSort callback to compare array values
02112        nsMsgKey i1 = *(nsMsgKey *)v1;
02113        nsMsgKey i2 = *(nsMsgKey *)v2;
02114        return i1 - i2;
02115 }
02116 
02117 /* static */nsresult
02118 nsImapMailFolder::AllocateUidStringFromKeys(nsMsgKey *keys, PRUint32 numKeys, nsCString &msgIds)
02119 {
02120   if (!numKeys)
02121     return NS_ERROR_INVALID_ARG;
02122   nsresult rv = NS_OK;
02123   PRUint32 startSequence;
02124   startSequence = keys[0];
02125   PRUint32 curSequenceEnd = startSequence;
02126   PRUint32 total = numKeys;
02127   // sort keys and then generate ranges instead of singletons!
02128   NS_QuickSort(keys, numKeys, sizeof(nsMsgKey), CompareKey, nsnull);
02129   for (PRUint32 keyIndex = 0; keyIndex < total; keyIndex++)
02130   {
02131     PRUint32 curKey = keys[keyIndex];
02132     PRUint32 nextKey = (keyIndex + 1 < total) ? keys[keyIndex + 1] : 0xFFFFFFFF;
02133     PRBool lastKey = (nextKey == 0xFFFFFFFF);
02134 
02135     if (lastKey)
02136       curSequenceEnd = curKey;
02137     if (nextKey == (PRUint32) curSequenceEnd + 1 && !lastKey)
02138     {
02139       curSequenceEnd = nextKey;
02140       continue;
02141     }
02142     else if (curSequenceEnd > startSequence)
02143     {
02144       AppendUid(msgIds, startSequence);
02145       msgIds += ':';
02146       AppendUid(msgIds,curSequenceEnd);
02147       if (!lastKey)
02148         msgIds += ',';
02149       startSequence = nextKey;
02150       curSequenceEnd = startSequence;
02151     }
02152     else
02153     {
02154       startSequence = nextKey;
02155       curSequenceEnd = startSequence;
02156       AppendUid(msgIds, keys[keyIndex]);
02157       if (!lastKey)
02158         msgIds += ',';
02159     }
02160   }
02161   return rv;
02162 }
02163 
02164 nsresult nsImapMailFolder::MarkMessagesImapDeleted(nsMsgKeyArray *keyArray, PRBool deleted, nsIMsgDatabase *db)
02165 {
02166   for (PRUint32 kindex = 0; kindex < keyArray->GetSize(); kindex++)
02167   {
02168     nsMsgKey key = keyArray->ElementAt(kindex);
02169     db->MarkImapDeleted(key, deleted, nsnull);
02170   }
02171   return NS_OK;
02172 }
02173 
02174 NS_IMETHODIMP nsImapMailFolder::DeleteMessages(nsISupportsArray *messages,
02175                                                nsIMsgWindow *msgWindow,
02176                                                PRBool deleteStorage, PRBool isMove,
02177                                                nsIMsgCopyServiceListener* listener,
02178                                                PRBool allowUndo)
02179 {
02180   // *** jt - assuming delete is move to the trash folder for now
02181   nsCOMPtr<nsIEnumerator> aEnumerator;
02182   nsCOMPtr<nsIRDFResource> res;
02183   nsCAutoString uri;
02184   PRBool deleteImmediatelyNoTrash = PR_FALSE;
02185   nsCAutoString messageIds;
02186   nsMsgKeyArray srcKeyArray;
02187   PRBool deleteMsgs = PR_TRUE;  //used for toggling delete status - default is true
02188   nsMsgImapDeleteModel deleteModel = nsMsgImapDeleteModels::MoveToTrash;
02189   imapMessageFlagsType messageFlags = kImapMsgDeletedFlag;
02190 
02191   nsCOMPtr<nsIImapIncomingServer> imapServer;
02192   nsresult rv = GetFlag(MSG_FOLDER_FLAG_TRASH, &deleteImmediatelyNoTrash);
02193   rv = GetImapIncomingServer(getter_AddRefs(imapServer));
02194   
02195   if (NS_SUCCEEDED(rv) && imapServer)
02196   {
02197     imapServer->GetDeleteModel(&deleteModel);
02198     if (deleteModel != nsMsgImapDeleteModels::MoveToTrash || deleteStorage)
02199       deleteImmediatelyNoTrash = PR_TRUE;
02200     // if we're deleting a message, we should pseudo-interrupt the msg
02201     //load of the current message.
02202     PRBool interrupted = PR_FALSE;
02203     imapServer->PseudoInterruptMsgLoad(this, msgWindow, &interrupted);
02204   }
02205   
02206   rv = BuildIdsAndKeyArray(messages, messageIds, srcKeyArray);
02207   if (NS_FAILED(rv)) return rv;
02208   
02209   
02210   nsCOMPtr<nsIMsgFolder> rootFolder;
02211   nsCOMPtr<nsIMsgFolder> trashFolder;
02212   
02213   if (!deleteImmediatelyNoTrash)
02214   {
02215     rv = GetRootFolder(getter_AddRefs(rootFolder));
02216     if (NS_SUCCEEDED(rv) && rootFolder)
02217     {
02218       PRUint32 numFolders = 0;
02219       rv = rootFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_TRASH,
02220         1, &numFolders,
02221         getter_AddRefs(trashFolder));
02222 
02223       NS_ASSERTION(NS_SUCCEEDED(rv) && trashFolder != 0, "couldn't find trash");
02224       
02225       // if we can't find the trash, we'll just have to do an imap delete and pretend this is the trash
02226       if (NS_FAILED(rv) || !trashFolder)
02227         deleteImmediatelyNoTrash = PR_TRUE;
02228     }
02229   }
02230   
02231   if ((NS_SUCCEEDED(rv) && deleteImmediatelyNoTrash) || deleteModel == nsMsgImapDeleteModels::IMAPDelete )
02232   {
02233     if (allowUndo)
02234     {
02235       //need to take care of these two delete models
02236       nsImapMoveCopyMsgTxn* undoMsgTxn = new nsImapMoveCopyMsgTxn;
02237       if (!undoMsgTxn || NS_FAILED(undoMsgTxn->Init(this, &srcKeyArray, messageIds.get(), nsnull,
02238                                                       PR_TRUE, isMove, m_eventQueue, nsnull)))
02239       {
02240         delete undoMsgTxn;
02241         return NS_ERROR_OUT_OF_MEMORY;
02242       }
02243       undoMsgTxn->SetTransactionType(nsIMessenger::eDeleteMsg);
02244       // we're adding this undo action before the delete is successful. This is evil,
02245       // but 4.5 did it as well.
02246       nsCOMPtr <nsITransactionManager> txnMgr;
02247       if (msgWindow)
02248         msgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
02249       if (txnMgr)
02250         txnMgr->DoTransaction(undoMsgTxn);
02251     }
02252     
02253     if (deleteModel == nsMsgImapDeleteModels::IMAPDelete && !deleteStorage)
02254     {
02255       PRUint32 cnt, flags;
02256       rv = messages->Count(&cnt);
02257       NS_ENSURE_SUCCESS(rv, rv);
02258       deleteMsgs = PR_FALSE;
02259       for (PRUint32 i=0; i <cnt; i++)
02260       {
02261         nsCOMPtr <nsIMsgDBHdr> msgHdr = do_QueryElementAt(messages, i);
02262         if (msgHdr)
02263         {
02264           msgHdr->GetFlags(&flags);
02265           if (!(flags & MSG_FLAG_IMAP_DELETED))
02266           {
02267             deleteMsgs = PR_TRUE;
02268             break;
02269           }
02270         }
02271       }
02272     }
02273     // if copy service listener is also a url listener, pass that
02274     // url listener into StoreImapFlags.
02275     nsCOMPtr <nsIUrlListener> urlListener = do_QueryInterface(listener);
02276     if (deleteMsgs)
02277       messageFlags |= kImapMsgSeenFlag;
02278     rv = StoreImapFlags(messageFlags, deleteMsgs, srcKeyArray.GetArray(), 
02279                         srcKeyArray.GetSize(), urlListener);
02280     
02281     if (NS_SUCCEEDED(rv))
02282     {
02283       if (mDatabase)
02284       {
02285         if (deleteModel == nsMsgImapDeleteModels::IMAPDelete)
02286         {
02287 
02288           MarkMessagesImapDeleted(&srcKeyArray, deleteMsgs, mDatabase);
02289         }
02290         else
02291         {
02292           EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE /*dbBatching*/);  //"remove it immediately" model
02293           mDatabase->DeleteMessages(&srcKeyArray,nsnull);
02294           EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE /*dbBatching*/);
02295           NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);            
02296         }    
02297       }   
02298     }
02299     return rv;
02300   }
02301   else  // have to move the messages to the trash
02302   {
02303     if(trashFolder)
02304     {
02305       nsCOMPtr<nsIMsgFolder> srcFolder;
02306       nsCOMPtr<nsISupports>srcSupport;
02307       PRUint32 count = 0;
02308       rv = messages->Count(&count);
02309       
02310       rv = QueryInterface(NS_GET_IID(nsIMsgFolder),
02311         getter_AddRefs(srcFolder));
02312       
02313       nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
02314       NS_ENSURE_SUCCESS(rv, rv);
02315       rv = copyService->CopyMessages(srcFolder, messages, trashFolder, PR_TRUE, listener, msgWindow, allowUndo);
02316     }
02317   }
02318   return rv;
02319 }
02320 
02321 // check if folder is the trash, or a descendent of the trash
02322 // so we can tell if the folders we're deleting from it should
02323 // be *really* deleted.
02324 PRBool
02325 nsImapMailFolder::TrashOrDescendentOfTrash(nsIMsgFolder* folder)
02326 {
02327     nsCOMPtr<nsIMsgFolder> parent;
02328     nsCOMPtr<nsIMsgFolder> curFolder;
02329     nsresult rv;
02330     PRUint32 flags = 0;
02331 
02332     if (!folder) return PR_FALSE;
02333     curFolder = do_QueryInterface(folder, &rv);
02334     if (NS_FAILED(rv)) return PR_FALSE;
02335 
02336     do 
02337     {
02338         rv = curFolder->GetFlags(&flags);
02339         if (NS_FAILED(rv)) return PR_FALSE;
02340         if (flags & MSG_FOLDER_FLAG_TRASH)
02341             return PR_TRUE;
02342         rv = curFolder->GetParentMsgFolder(getter_AddRefs(parent));
02343         if (NS_FAILED(rv)) return PR_FALSE;
02344         curFolder = do_QueryInterface(parent, &rv);
02345     } while (NS_SUCCEEDED(rv) && curFolder);
02346 
02347     return PR_FALSE;
02348 }
02349 NS_IMETHODIMP
02350 nsImapMailFolder::DeleteSubFolders(nsISupportsArray* folders, nsIMsgWindow *msgWindow)
02351 {
02352     nsCOMPtr<nsIMsgFolder> curFolder;
02353     nsCOMPtr<nsIUrlListener> urlListener;
02354     nsCOMPtr<nsIMsgFolder> trashFolder;
02355     PRInt32 i;
02356     PRUint32 folderCount = 0;
02357     nsresult rv;
02358     // "this" is the folder we're deleting from
02359     PRBool deleteNoTrash = TrashOrDescendentOfTrash(this) || !DeleteIsMoveToTrash();
02360     PRBool confirmed = PR_FALSE;
02361     PRBool confirmDeletion = PR_TRUE;
02362 
02363 
02364     (void) folders->Count(&folderCount);
02365 
02366     for (i = folderCount - 1; i >= 0; i--)
02367     {
02368       curFolder = do_QueryElementAt(folders, i, &rv);
02369       if (NS_SUCCEEDED(rv))
02370       {
02371         PRUint32 folderFlags;
02372         curFolder->GetFlags(&folderFlags);
02373         if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL)
02374         {
02375           RemoveSubFolder(curFolder);
02376           folders->RemoveElementAt(i);
02377           // since the folder pane only allows single selection, we can do this
02378           deleteNoTrash = confirmed = PR_TRUE;
02379           confirmDeletion = PR_FALSE;
02380         }
02381       }
02382     }
02383 
02384     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
02385     if (NS_SUCCEEDED(rv))
02386     {
02387       if (!deleteNoTrash)
02388       {
02389         rv = GetTrashFolder(getter_AddRefs(trashFolder));
02390 
02391         //If we can't find the trash folder and we are supposed to move it to the trash
02392         //return failure.
02393         if(NS_FAILED(rv) || !trashFolder)
02394           return NS_ERROR_FAILURE;
02395 
02396          PRBool canHaveSubFoldersOfTrash = PR_TRUE;
02397          trashFolder->GetCanCreateSubfolders(&canHaveSubFoldersOfTrash);
02398          if (canHaveSubFoldersOfTrash) // UW server doesn't set NOINFERIORS - check dual use pref
02399          {
02400            nsCOMPtr<nsIImapIncomingServer> imapServer;
02401            rv = GetImapIncomingServer(getter_AddRefs(imapServer));
02402 
02403            if (NS_SUCCEEDED(rv) && imapServer) 
02404            {
02405              PRBool serverSupportsDualUseFolders;
02406              imapServer->GetDualUseFolders(&serverSupportsDualUseFolders);
02407              if (!serverSupportsDualUseFolders)
02408                canHaveSubFoldersOfTrash = PR_FALSE;
02409            }
02410          }
02411          if (!canHaveSubFoldersOfTrash)
02412            deleteNoTrash = PR_TRUE;
02413 
02414          nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
02415          if (NS_SUCCEEDED(rv))
02416            prefBranch->GetBoolPref("mailnews.confirm.moveFoldersToTrash", &confirmDeletion);
02417       }
02418       if (!confirmed && (confirmDeletion || deleteNoTrash)) //let us alert the user if we are deleting folder immediately
02419       {
02420         nsXPIDLString confirmationStr;
02421         IMAPGetStringByID(((!deleteNoTrash) ? IMAP_MOVE_FOLDER_TO_TRASH : IMAP_DELETE_NO_TRASH),
02422         getter_Copies(confirmationStr));
02423 
02424         if (!msgWindow) 
02425           return NS_ERROR_NULL_POINTER;
02426         nsCOMPtr<nsIDocShell> docShell;
02427         msgWindow->GetRootDocShell(getter_AddRefs(docShell));
02428 
02429         nsCOMPtr<nsIPrompt> dialog;
02430         if (docShell) 
02431           dialog = do_GetInterface(docShell);
02432 
02433         if (dialog && confirmationStr)
02434           dialog->Confirm(nsnull, confirmationStr, &confirmed);
02435       }
02436       else
02437         confirmed = PR_TRUE;
02438 
02439       if (confirmed)
02440       {
02441         for (i = 0; i < folderCount; i++)
02442         {
02443           curFolder = do_QueryElementAt(folders, i, &rv);
02444           if (NS_SUCCEEDED(rv))
02445           {
02446             urlListener = do_QueryInterface(curFolder);
02447             if (deleteNoTrash)
02448               rv = imapService->DeleteFolder(m_eventQueue,
02449                                              curFolder,
02450                                              urlListener,
02451                                              nsnull);
02452             else
02453             {
02454               PRBool confirm = PR_FALSE;
02455               PRBool match = PR_FALSE;
02456               rv = curFolder->MatchOrChangeFilterDestination(nsnull, PR_FALSE, &match);
02457               if (match)
02458               {
02459                 curFolder->ConfirmFolderDeletionForFilter(msgWindow, &confirm);
02460                 if (!confirm) 
02461                   return NS_OK;
02462               }
02463               rv = imapService->MoveFolder(m_eventQueue,
02464                                            curFolder,
02465                                            trashFolder,
02466                                            urlListener,
02467                                            msgWindow,
02468                                            nsnull);
02469             }
02470           }
02471         }
02472       }
02473     }
02474     
02475     if (confirmed && deleteNoTrash)   //delete subfolders only if you are  deleting things from trash
02476         return nsMsgDBFolder::DeleteSubFolders(folders, msgWindow);
02477     return rv;
02478 }
02479 
02480 // Called by Biff, or when user presses GetMsg button.
02481 NS_IMETHODIMP nsImapMailFolder::GetNewMessages(nsIMsgWindow *aWindow, nsIUrlListener *aListener)
02482 {
02483   nsCOMPtr<nsIMsgFolder> rootFolder;
02484   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
02485 
02486   if(NS_SUCCEEDED(rv) && rootFolder) 
02487   {
02488 
02489     nsCOMPtr<nsIImapIncomingServer> imapServer;
02490     GetImapIncomingServer(getter_AddRefs(imapServer));
02491  
02492     PRBool performingBiff = PR_FALSE;
02493 
02494     if (imapServer)
02495     {
02496       nsCOMPtr<nsIMsgIncomingServer> incomingServer = do_QueryInterface(imapServer, &rv);
02497       if (incomingServer)
02498         incomingServer->GetPerformingBiff(&performingBiff);
02499     }
02500 
02501     // Check preferences to see if we should check all folders for new 
02502     // messages, or just the inbox and marked ones
02503     PRBool checkAllFolders = PR_FALSE;
02504 
02505     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
02506     if (NS_SUCCEEDED(rv) && prefBranch) 
02507       // This pref might not exist, which is OK. We'll only check inbox and marked ones
02508       rv = prefBranch->GetBoolPref("mail.check_all_imap_folders_for_new", &checkAllFolders); 
02509 
02510     m_urlListener = aListener;                                                  
02511 
02512     // Get new messages for inbox
02513     PRUint32 numFolders;
02514     nsCOMPtr<nsIMsgFolder> inbox;
02515     rv = rootFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, 1, &numFolders, getter_AddRefs(inbox));
02516     if (inbox)
02517     {
02518       nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(inbox, &rv);
02519       if (imapFolder)
02520         imapFolder->SetPerformingBiff(performingBiff);
02521 
02522       inbox->SetGettingNewMessages(PR_TRUE);
02523       rv = inbox->UpdateFolder(aWindow);
02524     }
02525 
02526     // Get new messages for other folders if marked, or all of them if the pref is set
02527     if (imapServer)
02528       rv = imapServer->GetNewMessagesForNonInboxFolders(rootFolder, aWindow, checkAllFolders, performingBiff);
02529   }
02530 
02531   return rv;
02532 }
02533 
02534 NS_IMETHODIMP nsImapMailFolder::Shutdown(PRBool shutdownChildren)
02535 {
02536   m_filterList = nsnull;
02537   m_initialized = PR_FALSE;
02538   // m_pathName is used to decide if folder pathname needs to be reconstructed in GetPath().
02539   delete m_pathName;
02540   m_pathName = nsnull; 
02541   NS_IF_RELEASE(m_moveCoalescer);
02542   return nsMsgDBFolder::Shutdown(shutdownChildren);
02543 }
02544 
02545 nsresult nsImapMailFolder::GetBodysToDownload(nsMsgKeyArray *keysOfMessagesToDownload)
02546 {
02547   NS_ENSURE_ARG(keysOfMessagesToDownload);
02548 
02549   nsresult rv = NS_ERROR_NULL_POINTER; // if mDatabase not set
02550 
02551   if (mDatabase)
02552   {
02553     nsCOMPtr <nsISimpleEnumerator> enumerator;
02554     rv = mDatabase->EnumerateMessages(getter_AddRefs(enumerator));
02555     if (NS_SUCCEEDED(rv) && enumerator)
02556     {
02557       PRBool hasMore;
02558 
02559       while (NS_SUCCEEDED(rv = enumerator->HasMoreElements(&hasMore)) && (hasMore == PR_TRUE)) 
02560       {
02561         nsCOMPtr <nsIMsgDBHdr> pHeader;
02562         rv = enumerator->GetNext(getter_AddRefs(pHeader));
02563         NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
02564         if (pHeader && NS_SUCCEEDED(rv))
02565         {
02566           PRBool shouldStoreMsgOffline = PR_FALSE;
02567           nsMsgKey msgKey;
02568           pHeader->GetMessageKey(&msgKey);
02569           // MsgFitsDownloadCriteria ignores MSG_FOLDER_FLAG_OFFLINE, which we want
02570           if (m_downloadingFolderForOfflineUse)
02571             MsgFitsDownloadCriteria(msgKey, &shouldStoreMsgOffline);
02572           else
02573             ShouldStoreMsgOffline(msgKey, &shouldStoreMsgOffline);
02574           if (shouldStoreMsgOffline)
02575             keysOfMessagesToDownload->Add(msgKey);
02576         }
02577       }
02578     }
02579   }
02580   return rv;
02581 }
02582 
02583 NS_IMETHODIMP nsImapMailFolder::OnNewIdleMessages()
02584 {
02585   PRBool checkAllFolders = PR_FALSE;
02586 
02587   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
02588   if (prefBranch) 
02589     // This pref might not exist, which is OK. 
02590     (void) prefBranch->GetBoolPref("mail.check_all_imap_folders_for_new", &checkAllFolders); 
02591 
02592   // only trigger biff if we're checking all new folders for new messages, or this particular folder,
02593   // but excluding trash,junk, sent, and no select folders, by default.
02594   if ((checkAllFolders && 
02595     !(mFlags & (MSG_FOLDER_FLAG_TRASH | MSG_FOLDER_FLAG_JUNK | MSG_FOLDER_FLAG_SENTMAIL | MSG_FOLDER_FLAG_IMAP_NOSELECT)))
02596     || (mFlags & (MSG_FOLDER_FLAG_CHECK_NEW|MSG_FOLDER_FLAG_INBOX)))
02597     SetPerformingBiff(PR_TRUE);
02598 
02599   return UpdateFolder(nsnull);
02600 }
02601 
02602 NS_IMETHODIMP nsImapMailFolder::UpdateImapMailboxInfo(
02603   nsIImapProtocol* aProtocol, nsIMailboxSpec* aSpec)
02604 {
02605   nsresult rv = NS_ERROR_FAILURE;
02606   ChangeNumPendingTotalMessages(-GetNumPendingTotalMessages());
02607   ChangeNumPendingUnread(-GetNumPendingUnread());
02608   m_numStatusRecentMessages = 0; // clear this since we selected the folder.
02609   m_numStatusUnseenMessages = 0; // clear this since we selected the folder.
02610 
02611   
02612   if (!mDatabase)
02613     GetDatabase(nsnull);
02614   
02615   PRBool folderSelected;
02616   rv = aSpec->GetFolderSelected(&folderSelected);
02617   if (NS_SUCCEEDED(rv) && folderSelected)
02618   {
02619     nsMsgKeyArray existingKeys;
02620     nsMsgKeyArray keysToDelete;
02621     nsMsgKeyArray keysToFetch;
02622     PRUint32 numNewUnread;
02623     nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
02624     PRInt32 imapUIDValidity = 0;
02625     
02626     rv = NS_ERROR_UNEXPECTED;
02627     if (mDatabase)
02628       rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
02629     
02630     if (NS_SUCCEEDED(rv) && dbFolderInfo)
02631       dbFolderInfo->GetImapUidValidity(&imapUIDValidity);
02632     
02633     if (mDatabase) 
02634     {
02635       mDatabase->ListAllKeys(existingKeys);
02636       PRInt32 keyCount = existingKeys.GetSize();
02637       mDatabase->ListAllOfflineDeletes(&existingKeys);
02638       if (keyCount < existingKeys.GetSize())
02639         existingKeys.QuickSort();
02640     }
02641     PRInt32 folderValidity;
02642     aSpec->GetFolder_UIDVALIDITY(&folderValidity);
02643     
02644     nsCOMPtr <nsIImapFlagAndUidState> flagState;
02645     
02646     aSpec->GetFlagState(getter_AddRefs(flagState));
02647     
02648     // remember what the supported user flags are.
02649     PRUint32 supportedUserFlags;
02650     aSpec->GetSupportedUserFlags(&supportedUserFlags);
02651     SetSupportedUserFlags(supportedUserFlags);
02652 
02653     m_uidValidity = folderValidity;
02654 
02655     if ((imapUIDValidity != folderValidity) /* && // if UIDVALIDITY Changed 
02656       !NET_IsOffline() */)
02657     {
02658       NS_ASSERTION(PR_FALSE, "uid validity seems to have changed, blowing away db");
02659       nsCOMPtr<nsIFileSpec> pathSpec;
02660       rv = GetPath(getter_AddRefs(pathSpec));
02661       if (NS_FAILED(rv)) return rv;
02662       
02663       nsFileSpec dbName;
02664       rv = pathSpec->GetFileSpec(&dbName);
02665       if (NS_FAILED(rv)) return rv;
02666       
02667       nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
02668       NS_ENSURE_SUCCESS(rv, rv);
02669       
02670       nsCOMPtr <nsIDBFolderInfo> transferInfo;
02671       if (dbFolderInfo)
02672         dbFolderInfo->GetTransferInfo(getter_AddRefs(transferInfo));
02673       if (mDatabase)
02674       {
02675         dbFolderInfo = nsnull;
02676         mDatabase->ForceClosed();
02677       }
02678       mDatabase = nsnull;
02679       
02680       nsLocalFolderSummarySpec  summarySpec(dbName);
02681       // Remove summary file.
02682       summarySpec.Delete(PR_FALSE);
02683       
02684       // Create a new summary file, update the folder message counts, and
02685       // Close the summary file db.
02686       rv = msgDBService->OpenFolderDB(this, PR_TRUE, PR_TRUE, getter_AddRefs(mDatabase));
02687       
02688       // ********** Important *************
02689       // David, help me here I don't know this is right or wrong
02690       if (rv == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
02691         rv = NS_OK;
02692       
02693       if (NS_FAILED(rv) && mDatabase)
02694       {
02695         mDatabase->ForceClosed();
02696         mDatabase = nsnull;
02697       }
02698       else if (NS_SUCCEEDED(rv) && mDatabase)
02699       {
02700         if (transferInfo)
02701           SetDBTransferInfo(transferInfo);
02702         
02703         SummaryChanged();
02704         rv = NS_ERROR_UNEXPECTED;
02705         if (mDatabase) 
02706         {
02707           if(mAddListener)
02708             mDatabase->AddListener(this);
02709           rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
02710         }
02711       }
02712       // store the new UIDVALIDITY value
02713       
02714       if (NS_SUCCEEDED(rv) && dbFolderInfo)
02715         dbFolderInfo->SetImapUidValidity(folderValidity);
02716       // delete all my msgs, the keys are bogus now
02717       // add every message in this folder
02718       existingKeys.RemoveAll();
02719       //      keysToDelete.CopyArray(&existingKeys);
02720       
02721       if (flagState)
02722       {
02723         nsMsgKeyArray no_existingKeys;
02724 
02725         FindKeysToAdd(no_existingKeys, keysToFetch, numNewUnread, flagState);
02726       }
02727       if (NS_FAILED(rv))
02728         dbName.Delete(PR_FALSE);
02729       
02730     }   
02731     else if (!flagState /*&& !NET_IsOffline() */) // if there are no messages on the server
02732     {
02733       keysToDelete.CopyArray(&existingKeys);
02734     }
02735     else /* if ( !NET_IsOffline()) */
02736     {
02737       FindKeysToDelete(existingKeys, keysToDelete, flagState);
02738       
02739       PRUint32 boxFlags;
02740       
02741       aSpec->GetBox_flags(&boxFlags);
02742       // if this is the result of an expunge then don't grab headers
02743       if (!(boxFlags & kJustExpunged))
02744         FindKeysToAdd(existingKeys, keysToFetch, numNewUnread, flagState);
02745     }
02746     
02747     
02748     if (keysToDelete.GetSize())
02749     {
02750       PRUint32 total;
02751       
02752       // It would be nice to notify RDF or whoever of a mass delete here.
02753       if (mDatabase) 
02754       {
02755         mDatabase->DeleteMessages(&keysToDelete, nsnull);
02756         total = keysToDelete.GetSize();
02757       }
02758     }
02759     // If we are performing biff for this folder, tell the
02760     // stand-alone biff about the new high water mark
02761     if (m_performingBiff)
02762     {
02763       if (numNewUnread > 0)
02764       {
02765         // We must ensure that the server knows that we are performing biff.
02766         // Otherwise the stand-alone biff won't fire.
02767         nsCOMPtr<nsIMsgIncomingServer> server;
02768         if (NS_SUCCEEDED(GetServer(getter_AddRefs(server))) && server)
02769           server->SetPerformingBiff(PR_TRUE);
02770         
02771          SetNumNewMessages(numNewUnread);
02772       }
02773     }
02774     SyncFlags(flagState);
02775     PRInt32 numUnreadFromServer;
02776     aSpec->GetNumUnseenMessages(&numUnreadFromServer);
02777     if (mDatabase&&
02778         mNumUnreadMessages + keysToFetch.GetSize() > numUnreadFromServer)
02779       mDatabase->SyncCounts();
02780 
02781     if (keysToFetch.GetSize())
02782     {     
02783       PrepareToAddHeadersToMailDB(aProtocol, keysToFetch, aSpec);
02784     }
02785     else 
02786     {
02787       // let the imap libnet module know that we don't need headers
02788       if (aProtocol)
02789         aProtocol->NotifyHdrsToDownload(nsnull, 0);
02790       PRBool gettingNewMessages;
02791       GetGettingNewMessages(&gettingNewMessages);
02792       if (gettingNewMessages)
02793         ProgressStatus(aProtocol,IMAP_NO_NEW_MESSAGES, nsnull);
02794       SetPerformingBiff(PR_FALSE);
02795     }
02796   }
02797   
02798   return rv;
02799 }
02800 
02801 NS_IMETHODIMP nsImapMailFolder::UpdateImapMailboxStatus(
02802   nsIImapProtocol* aProtocol, nsIMailboxSpec* aSpec)
02803 {
02804   NS_ENSURE_ARG_POINTER(aSpec);
02805   PRInt32 numRecent, numUnread;
02806   aSpec->GetNumRecentMessages(&numRecent);
02807   aSpec->GetNumUnseenMessages(&numUnread);
02808   // If m_numStatusUnseenMessages is 0, it means
02809   // this is the first time we've done a Status.
02810   // In that case, we count all the previous pending unread messages we know about
02811   // as unread messages. 
02812   // We may want to do similar things with total messages, but the total messages
02813   // include deleted messages if the folder hasn't been expunged.
02814   PRInt32 previousUnreadMessages = (m_numStatusUnseenMessages) 
02815     ? m_numStatusUnseenMessages : GetNumPendingUnread() + mNumUnreadMessages;
02816   if (numUnread != previousUnreadMessages)
02817   {
02818     // we're going to assume that recent messages are unread.
02819     ChangeNumPendingUnread(numUnread - previousUnreadMessages);
02820     ChangeNumPendingTotalMessages(numUnread - previousUnreadMessages);
02821     if (numUnread > previousUnreadMessages)
02822     {
02823       SetHasNewMessages(PR_TRUE);
02824       SetNumNewMessages(numUnread - previousUnreadMessages);
02825       SetBiffState(nsMsgBiffState_NewMail);
02826     }
02827     SummaryChanged();
02828   }
02829   SetPerformingBiff(PR_FALSE);
02830   m_numStatusUnseenMessages = numUnread;
02831   return NS_OK;
02832 }
02833 
02834 NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs(nsIImapProtocol *aProtocol, nsIImapHeaderXferInfo *aHdrXferInfo)
02835 {
02836   PRInt32 numHdrs;
02837   nsCOMPtr <nsIImapHeaderInfo> headerInfo;
02838   nsCOMPtr <nsIImapUrl> aImapUrl;
02839   nsImapAction imapAction = nsIImapUrl::nsImapTest; // unused value.
02840   if (!mDatabase)
02841     GetDatabase(nsnull);
02842   
02843   nsresult rv = aHdrXferInfo->GetNumHeaders(&numHdrs);
02844   if (aProtocol)
02845   {
02846     (void) aProtocol->GetRunningImapURL(getter_AddRefs(aImapUrl));
02847     if (aImapUrl)
02848       aImapUrl->GetImapAction(&imapAction);
02849   }
02850   for (PRUint32 i = 0; NS_SUCCEEDED(rv) && i < numHdrs; i++)
02851   {
02852 
02853     rv = aHdrXferInfo->GetHeader(i, getter_AddRefs(headerInfo));
02854     NS_ENSURE_SUCCESS(rv, rv);
02855     if (!headerInfo)
02856       break;
02857     PRInt32 msgSize;
02858     nsMsgKey msgKey;
02859     PRBool containsKey;
02860     const char *msgHdrs;
02861     headerInfo->GetMsgSize(&msgSize);
02862     headerInfo->GetMsgUid(&msgKey);
02863     if (msgKey == nsMsgKey_None) // not a valid uid.
02864       continue;
02865     if (imapAction == nsIImapUrl::nsImapMsgPreview)
02866     {
02867       nsCOMPtr <nsIMsgDBHdr> msgHdr;
02868       headerInfo->GetMsgHdrs(&msgHdrs);
02869       // create an input stream based on the hdr string.
02870       nsCOMPtr<nsIStringInputStream> inputStream = 
02871             do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
02872       NS_ENSURE_SUCCESS(rv, rv);
02873       inputStream->ShareData(msgHdrs, strlen(msgHdrs));
02874       GetMessageHeader(msgKey, getter_AddRefs(msgHdr));
02875       if (msgHdr)
02876         GetMsgPreviewTextFromStream(msgHdr, inputStream);
02877       continue;
02878     }
02879     if (mDatabase && NS_SUCCEEDED(mDatabase->ContainsKey(msgKey, &containsKey)) && containsKey)
02880     {
02881       NS_ASSERTION(PR_FALSE, "downloading hdrs for hdr we already have");
02882       continue;
02883     }
02884     nsresult rv = SetupHeaderParseStream(msgSize, nsnull, nsnull);
02885     NS_ENSURE_SUCCESS(rv, rv);
02886     headerInfo->GetMsgHdrs(&msgHdrs);
02887     rv = ParseAdoptedHeaderLine(msgHdrs, msgKey);
02888     NS_ENSURE_SUCCESS(rv, rv);
02889     rv = NormalEndHeaderParseStream(aProtocol, aImapUrl);
02890   }
02891 
02892   return rv;
02893 }
02894 
02895 nsresult nsImapMailFolder::SetupHeaderParseStream(PRUint32 aSize, 
02896                                                   const char *content_type, nsIMailboxSpec *boxSpec)
02897 {
02898   if (!mDatabase)
02899     GetDatabase(nsnull);
02900   
02901   m_nextMessageByteLength = aSize;
02902   if (!m_msgParser)
02903     m_msgParser = do_CreateInstance(kParseMailMsgStateCID);
02904   else
02905     m_msgParser->Clear();
02906   
02907   if (m_msgParser)
02908   {
02909     m_msgParser->SetMailDB(mDatabase);
02910     return m_msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
02911   }
02912 
02913   return NS_ERROR_OUT_OF_MEMORY;
02914 }
02915 
02916 nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char *aMessageLine, PRUint32 aMsgKey)
02917 {
02918   // we can get blocks that contain more than one line, 
02919   // but they never contain partial lines
02920   const char *str = aMessageLine;
02921   m_curMsgUid = aMsgKey;
02922   m_msgParser->SetEnvelopePos(m_curMsgUid);
02923   // m_envelope_pos, for local folders, 
02924   // is the msg key. Setting this will set the msg key for the new header.
02925   
02926   PRInt32 len = strlen(str);
02927   char *currentEOL  = PL_strstr(str, MSG_LINEBREAK);
02928   const char *currentLine = str;
02929   while (currentLine < (str + len))
02930   {
02931     if (currentEOL)
02932     {
02933       m_msgParser->ParseAFolderLine(currentLine, 
02934         (currentEOL + MSG_LINEBREAK_LEN) -
02935         currentLine);
02936       currentLine = currentEOL + MSG_LINEBREAK_LEN;
02937       currentEOL  = PL_strstr(currentLine, MSG_LINEBREAK);
02938     }
02939     else
02940     {
02941       m_msgParser->ParseAFolderLine(currentLine, PL_strlen(currentLine));
02942       currentLine = str + len + 1;
02943     }
02944   }
02945   return NS_OK;
02946 }
02947     
02948 nsresult nsImapMailFolder::NormalEndHeaderParseStream(nsIImapProtocol *aProtocol, nsIImapUrl* imapUrl)
02949 {
02950   nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
02951   nsresult rv = NS_OK;
02952 
02953   if (m_msgParser)
02954   {
02955     nsMailboxParseState parseState;
02956     m_msgParser->GetState(&parseState);
02957     if (parseState == nsIMsgParseMailMsgState::ParseHeadersState)
02958     m_msgParser->ParseAFolderLine(CRLF, 2);
02959     m_msgParser->GetNewMsgHdr(getter_AddRefs(newMsgHdr));
02960   }
02961   if (NS_SUCCEEDED(rv) && newMsgHdr)
02962   {
02963     char *headers;
02964     PRInt32 headersSize;
02965 
02966     nsCOMPtr <nsIMsgWindow> msgWindow;
02967     nsCOMPtr <nsIMsgMailNewsUrl> msgUrl;
02968     if (imapUrl)
02969     {
02970       msgUrl = do_QueryInterface(imapUrl);
02971       if (msgUrl)
02972         msgUrl->GetMsgWindow(getter_AddRefs(msgWindow));
02973     }
02974     nsCOMPtr<nsIMsgIncomingServer> server;
02975     rv = GetServer(getter_AddRefs(server));
02976     if (NS_SUCCEEDED(rv)) // don't use NS_ENSURE_SUCCESS here; it's not a fatal error
02977     {
02978       nsXPIDLCString redirectorType;
02979       server->GetRedirectorType(getter_Copies(redirectorType));
02980 
02981       // only notify redirected type servers of new hdrs for performance
02982       if (!redirectorType.IsEmpty())
02983         NotifyFolderEvent(mImapHdrDownloadedAtom);
02984     }
02985     newMsgHdr->SetMessageKey(m_curMsgUid);
02986     TweakHeaderFlags(aProtocol, newMsgHdr);
02987     PRUint32 messageSize;
02988     if (NS_SUCCEEDED(newMsgHdr->GetMessageSize(&messageSize)))
02989       mFolderSize += messageSize;
02990     m_msgMovedByFilter = PR_FALSE;
02991     // If this is the inbox, try to apply filters.
02992     if (mFlags & MSG_FOLDER_FLAG_INBOX)
02993     {
02994       PRUint32 msgFlags;
02995 
02996       newMsgHdr->GetFlags(&msgFlags);
02997       if (!(msgFlags & (MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED))) // only fire on unread msgs that haven't been deleted
02998       {
02999         PRInt32 duplicateAction = nsIMsgIncomingServer::keepDups;
03000         if (server)
03001           server->GetIncomingDuplicateAction(&duplicateAction);
03002         if (duplicateAction != nsIMsgIncomingServer::keepDups)
03003         {
03004           PRBool isDup;
03005           server->IsNewHdrDuplicate(newMsgHdr, &isDup);
03006           if (isDup)
03007           {
03008             // we want to do something similar to applying filter hits.
03009             // if a dup is marked read, it shouldn't trigger biff.
03010             // Same for deleting it or moving it to trash.
03011             switch (duplicateAction)
03012             {
03013               case nsIMsgIncomingServer::deleteDups:
03014                 {
03015                   PRUint32 newFlags;
03016                   newMsgHdr->OrFlags(MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED, &newFlags);
03017                   nsMsgKeyArray keysToFlag;
03018 
03019                   keysToFlag.Add(m_curMsgUid);
03020                   StoreImapFlags(kImapMsgSeenFlag | kImapMsgDeletedFlag, PR_TRUE, keysToFlag.GetArray(), 
03021                                 keysToFlag.GetSize(), nsnull);
03022                   m_msgMovedByFilter = PR_TRUE;
03023 
03024                 }
03025                 break;
03026               case nsIMsgIncomingServer::moveDupsToTrash:
03027                 {
03028                   nsCOMPtr <nsIMsgFolder> trash;
03029                   GetTrashFolder(getter_AddRefs(trash));
03030                   if (trash)
03031                   {
03032                     nsXPIDLCString trashUri;
03033                     trash->GetURI(getter_Copies(trashUri));
03034                     nsresult err = MoveIncorporatedMessage(newMsgHdr, mDatabase, trashUri, nsnull, msgWindow);
03035                     if (NS_SUCCEEDED(err))
03036                       m_msgMovedByFilter = PR_TRUE;
03037                   }
03038                 }
03039                 break;
03040               case nsIMsgIncomingServer::markDupsRead:
03041                 {
03042                   PRUint32 newFlags;
03043                   nsMsgKeyArray keysToFlag;
03044                   keysToFlag.Add(m_curMsgUid);
03045                   newMsgHdr->OrFlags(MSG_FLAG_READ, &newFlags);
03046                   StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, keysToFlag.GetArray(), keysToFlag.GetSize(), nsnull);
03047                 }
03048                 break;
03049             }
03050             PRInt32 numNewMessages;
03051             GetNumNewMessages(PR_FALSE, &numNewMessages);
03052             SetNumNewMessages(numNewMessages - 1);
03053 
03054           }
03055         }
03056         rv = m_msgParser->GetAllHeaders(&headers, &headersSize);
03057 
03058         if (NS_SUCCEEDED(rv) && headers && !m_msgMovedByFilter)
03059         {
03060           if (m_filterList)
03061           {
03062             GetMoveCoalescer();  // not sure why we're doing this here.
03063             m_filterList->ApplyFiltersToHdr(nsMsgFilterType::InboxRule, newMsgHdr, this, mDatabase, 
03064                                             headers, headersSize, this, msgWindow, nsnull);
03065           }
03066         }
03067       }
03068     }
03069     // here we need to tweak flags from uid state..
03070     if (mDatabase && (!m_msgMovedByFilter || ShowDeletedMessages()))
03071     {
03072       mDatabase->AddNewHdrToDB(newMsgHdr, PR_TRUE);
03073       nsCOMPtr <nsIMsgFolderNotificationService> notifier = do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID);
03074       if (notifier)
03075         notifier->NotifyItemAdded(newMsgHdr);    
03076       
03077     }
03078     m_msgParser->Clear(); // clear out parser, because it holds onto a msg hdr.
03079     m_msgParser->SetMailDB(nsnull); // tell it to let go of the db too.
03080     // I don't think we want to do this - it does bad things like set the size incorrectly.
03081 //    m_msgParser->FinishHeader();
03082   }
03083     return NS_OK;
03084 }
03085     
03086 NS_IMETHODIMP nsImapMailFolder::AbortHeaderParseStream(nsIImapProtocol*
03087                                                        aProtocol)
03088 {
03089     nsresult rv = NS_ERROR_FAILURE;
03090     return rv;
03091 }
03092 
03093 NS_IMETHODIMP nsImapMailFolder::BeginCopy(nsIMsgDBHdr *message)
03094 {
03095   nsresult rv = NS_ERROR_NULL_POINTER;
03096   if (!m_copyState) 
03097     return rv;
03098   if (m_copyState->m_tmpFileSpec) // leftover file spec nuke it
03099   {
03100     PRBool isOpen = PR_FALSE;
03101     rv = m_copyState->m_tmpFileSpec->IsStreamOpen(&isOpen);
03102     if (isOpen)
03103       m_copyState->m_tmpFileSpec->CloseStream();
03104     nsFileSpec fileSpec;
03105     m_copyState->m_tmpFileSpec->GetFileSpec(&fileSpec);
03106     if (fileSpec.Valid())
03107       fileSpec.Delete(PR_FALSE);
03108     m_copyState->m_tmpFileSpec = nsnull;
03109   }
03110   if (message)
03111     m_copyState->m_message = do_QueryInterface(message, &rv);
03112 
03113   nsSpecialSystemDirectory tmpFileSpec(nsSpecialSystemDirectory::OS_TemporaryDirectory);
03114 
03115   tmpFileSpec += "nscpmsg.txt";  
03116   tmpFileSpec.MakeUnique();
03117   rv = NS_NewFileSpecWithSpec(tmpFileSpec,
03118                                 getter_AddRefs(m_copyState->m_tmpFileSpec));
03119   nsCOMPtr<nsILocalFile> msgFile;
03120   if (NS_SUCCEEDED(rv))
03121     rv = NS_FileSpecToIFile(&tmpFileSpec, getter_AddRefs(msgFile));
03122   NS_ENSURE_SUCCESS(rv, rv);
03123   nsCOMPtr<nsIOutputStream> fileOutputStream;
03124   rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutputStream), msgFile, -1, 00600);
03125   NS_ENSURE_SUCCESS(rv,rv);
03126   rv = NS_NewBufferedOutputStream(getter_AddRefs(m_copyState->m_msgFileStream), fileOutputStream, FOUR_K);
03127   NS_ENSURE_SUCCESS(rv,rv);
03128 
03129   if (!m_copyState->m_dataBuffer)
03130     m_copyState->m_dataBuffer = (char*) PR_CALLOC(COPY_BUFFER_SIZE+1);
03131   if (!m_copyState->m_dataBuffer)
03132     return NS_ERROR_OUT_OF_MEMORY;
03133   m_copyState->m_dataBufferSize = COPY_BUFFER_SIZE;
03134 
03135   return rv;
03136 }
03137 
03138 NS_IMETHODIMP nsImapMailFolder::CopyDataToOutputStreamForAppend(nsIInputStream *aIStream,
03139                      PRInt32 aLength, nsIOutputStream *outputStream)
03140 {
03141   PRUint32 readCount;
03142   PRUint32 writeCount;
03143 
03144   if (!m_copyState)
03145   {
03146     nsImapMailCopyState* copyState = new nsImapMailCopyState();
03147     m_copyState = do_QueryInterface(copyState);
03148   }
03149   if ( aLength + m_copyState->m_leftOver > m_copyState->m_dataBufferSize )
03150   {
03151     m_copyState->m_dataBuffer = (char *) PR_REALLOC(m_copyState->m_dataBuffer, aLength + m_copyState->m_leftOver+ 1);
03152     if (!m_copyState->m_dataBuffer)
03153       return NS_ERROR_OUT_OF_MEMORY;
03154     m_copyState->m_dataBufferSize = aLength + m_copyState->m_leftOver;
03155   }
03156 
03157   char *start, *end;
03158   PRUint32 linebreak_len = 1;
03159 
03160   nsresult rv = aIStream->Read(m_copyState->m_dataBuffer+m_copyState->m_leftOver, aLength, &readCount);
03161   if (NS_FAILED(rv)) 
03162     return rv;
03163 
03164   m_copyState->m_leftOver += readCount;
03165   m_copyState->m_dataBuffer[m_copyState->m_leftOver] = '\0';
03166 
03167   start = m_copyState->m_dataBuffer;
03168   if (m_copyState->m_eatLF)
03169   {
03170     if (*start == nsCRT::LF)
03171       start++;
03172     m_copyState->m_eatLF = PR_FALSE;
03173   }
03174   end = PL_strpbrk(start, "\r\n");
03175   if (end && *end == '\r' && *(end+1) == '\n')
03176     linebreak_len = 2;
03177 
03178   while (start && end)
03179   {
03180     if (PL_strncasecmp(start, "X-Mozilla-Status:", 17) &&
03181         PL_strncasecmp(start, "X-Mozilla-Status2:", 18) &&
03182         PL_strncmp(start, "From - ", 7))
03183     {
03184       rv = outputStream->Write(start,
03185                                              end-start,
03186                                              &writeCount);
03187       rv = outputStream->Write(CRLF, 2, &writeCount);
03188     }
03189     start = end+linebreak_len;
03190     if (start >=
03191         m_copyState->m_dataBuffer+m_copyState->m_leftOver)
03192     {
03193        m_copyState->m_leftOver = 0;
03194        break;
03195     }
03196     linebreak_len = 1;
03197 
03198     end = PL_strpbrk(start, "\r\n");
03199     if (end && *end == '\r')
03200     {
03201       if (*(end+1) == '\n')
03202         linebreak_len = 2;
03203       else if (! *(end+1)) // block might have split CRLF so remember if
03204         m_copyState->m_eatLF = PR_TRUE; // we should eat LF
03205     }
03206 
03207     if (start && !end)
03208     {
03209       m_copyState->m_leftOver -= (start - m_copyState->m_dataBuffer);
03210       memcpy(m_copyState->m_dataBuffer, start, m_copyState->m_leftOver+1); // including null
03211     }
03212   }
03213   return rv;
03214 }
03215 
03216 NS_IMETHODIMP nsImapMailFolder::CopyDataDone()
03217 {
03218   m_copyState = nsnull;
03219   return NS_OK;
03220 }
03221 
03222 // sICopyMessageListener methods, BeginCopy, CopyData, EndCopy, EndMove, StartMessage, EndMessage
03223 
03224 NS_IMETHODIMP nsImapMailFolder::CopyData(nsIInputStream *aIStream,
03225                      PRInt32 aLength)
03226 {
03227   nsresult rv = NS_ERROR_NULL_POINTER;
03228   NS_ASSERTION(m_copyState && m_copyState->m_tmpFileSpec 
03229                   && m_copyState->m_dataBuffer, "Fatal copy operation error\n");
03230   if (!m_copyState || !m_copyState->m_msgFileStream || !m_copyState->m_dataBuffer) 
03231     return rv;
03232 
03233   return CopyDataToOutputStreamForAppend(aIStream, aLength, m_copyState->m_msgFileStream);
03234 }
03235 
03236 NS_IMETHODIMP nsImapMailFolder::EndCopy(PRBool copySucceeded)
03237 {
03238   nsresult rv = copySucceeded ? NS_OK : NS_ERROR_FAILURE;
03239     if (copySucceeded && m_copyState && m_copyState->m_msgFileStream)
03240     {
03241         nsCOMPtr<nsIUrlListener> urlListener;
03242         m_copyState->m_msgFileStream->Close();
03243         
03244         nsCOMPtr<nsIImapService> imapService = 
03245                  do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03246         NS_ENSURE_SUCCESS(rv,rv);
03247 
03248         rv = QueryInterface(NS_GET_IID(nsIUrlListener),
03249                             getter_AddRefs(urlListener));
03250         nsCOMPtr<nsISupports> copySupport;
03251         if (m_copyState)
03252             copySupport = do_QueryInterface(m_copyState);
03253         rv = imapService->AppendMessageFromFile(m_eventQueue,
03254                                                 m_copyState->m_tmpFileSpec,
03255                                                 this, "", PR_TRUE,
03256                                                 m_copyState->m_selectedState,
03257                                                 urlListener, nsnull,
03258                                                 copySupport,
03259                                                 m_copyState->m_msgWindow);
03260               
03261     }
03262   return rv;
03263 }
03264 
03265 NS_IMETHODIMP nsImapMailFolder::EndMove(PRBool moveSucceeded)
03266 {
03267   return NS_OK;
03268 }
03269 // this is the beginning of the next message copied
03270 NS_IMETHODIMP nsImapMailFolder::StartMessage()
03271 {
03272   return NS_OK;
03273 }
03274 
03275 // just finished the current message.
03276 NS_IMETHODIMP nsImapMailFolder::EndMessage(nsMsgKey key)
03277 {
03278   return NS_OK;
03279 }
03280 
03281 NS_IMETHODIMP nsImapMailFolder::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWindow *msgWindow, PRBool *applyMore)
03282 {  
03283   NS_ENSURE_ARG_POINTER(applyMore);
03284 
03285   nsMsgRuleActionType actionType;
03286   nsXPIDLCString actionTargetFolderUri;
03287   PRUint32  newFlags;
03288   nsresult rv = NS_OK;
03289 
03290   // look at action - currently handle move
03291   #ifdef DEBUG_bienvenu
03292     printf("got a rule hit!\n");
03293   #endif
03294 
03295   nsCOMPtr<nsIMsgDBHdr> msgHdr;
03296 
03297   if (m_msgParser)
03298     m_msgParser->GetNewMsgHdr(getter_AddRefs(msgHdr));
03299 
03300   if (!msgHdr)
03301     return NS_ERROR_NULL_POINTER; //fatal error, cannot apply filters
03302 
03303   PRBool deleteToTrash = DeleteIsMoveToTrash();
03304 
03305   nsCOMPtr<nsISupportsArray> filterActionList;
03306   rv = NS_NewISupportsArray(getter_AddRefs(filterActionList));
03307   NS_ENSURE_SUCCESS(rv, rv);
03308   rv = filter->GetSortedActionList(filterActionList);
03309   NS_ENSURE_SUCCESS(rv, rv);
03310 
03311   PRUint32 numActions;
03312   rv = filterActionList->Count(&numActions);
03313   NS_ENSURE_SUCCESS(rv, rv);
03314 
03315   PRBool loggingEnabled = PR_FALSE;
03316   if (m_filterList && numActions)
03317     (void)m_filterList->GetLoggingEnabled(&loggingEnabled);
03318 
03319   PRBool msgIsNew = PR_TRUE;
03320 
03321   for (PRUint32 actionIndex = 0; actionIndex < numActions; actionIndex++)
03322   {
03323     nsCOMPtr<nsIMsgRuleAction> filterAction;
03324     filterActionList->QueryElementAt(actionIndex, NS_GET_IID(nsIMsgRuleAction), getter_AddRefs(filterAction));
03325     if (!filterAction)
03326       continue;
03327     if (NS_SUCCEEDED(filterAction->GetType(&actionType)))
03328     {
03329       if (actionType == nsMsgFilterAction::MoveToFolder ||
03330           actionType == nsMsgFilterAction::CopyToFolder)
03331       {
03332         filterAction->GetTargetFolderUri(getter_Copies(actionTargetFolderUri));
03333         if (actionTargetFolderUri.IsEmpty())
03334         {
03335           NS_ASSERTION(PR_FALSE, "actionTargetFolderUri is empty");
03336           continue;
03337         }
03338       }
03339 
03340       PRUint32 msgFlags;
03341       nsMsgKey    msgKey;
03342       nsCAutoString trashNameVal;
03343 
03344       msgHdr->GetFlags(&msgFlags);
03345       msgHdr->GetMessageKey(&msgKey);
03346       PRBool isRead = (msgFlags & MSG_FLAG_READ);
03347       switch (actionType)
03348       {
03349         case nsMsgFilterAction::Delete:
03350         {
03351           if (deleteToTrash)
03352           {
03353             // set value to trash folder
03354             nsCOMPtr <nsIMsgFolder> mailTrash;
03355             rv = GetTrashFolder(getter_AddRefs(mailTrash));
03356             if (NS_SUCCEEDED(rv) && mailTrash)
03357               rv = mailTrash->GetURI(getter_Copies(actionTargetFolderUri));
03358 
03359             // msgHdr->OrFlags(MSG_FLAG_READ, &newFlags);  // mark read in trash.
03360           }
03361           else  // (!deleteToTrash)
03362           {
03363             msgHdr->OrFlags(MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED, &newFlags);
03364             nsMsgKeyArray keysToFlag;
03365 
03366             keysToFlag.Add(msgKey);
03367             StoreImapFlags(kImapMsgSeenFlag | kImapMsgDeletedFlag, PR_TRUE, keysToFlag.GetArray(), 
03368                           keysToFlag.GetSize(), nsnull);
03369             m_msgMovedByFilter = PR_TRUE; // this will prevent us from adding the header to the db.
03370           }
03371           msgIsNew = PR_FALSE;
03372         }
03373         // note that delete falls through to move.
03374         case nsMsgFilterAction::MoveToFolder:
03375         {
03376           // if moving to a different file, do it.
03377           nsXPIDLCString uri;
03378           rv = GetURI(getter_Copies(uri));
03379 
03380           if ((const char*)actionTargetFolderUri &&
03381             nsCRT::strcmp(uri, actionTargetFolderUri))
03382           {
03383             msgHdr->GetFlags(&msgFlags);
03384 
03385             if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && !isRead)
03386             {
03387                msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED);
03388                msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags);
03389             }
03390             nsresult err = MoveIncorporatedMessage(msgHdr, mDatabase, actionTargetFolderUri, filter, msgWindow);
03391             if (NS_SUCCEEDED(err))
03392               m_msgMovedByFilter = PR_TRUE;
03393           }
03394           // don't apply any more filters, even if it was a move to the same folder
03395           *applyMore = PR_FALSE; 
03396         }
03397         break;
03398         case nsMsgFilterAction::CopyToFolder:
03399         {
03400           nsXPIDLCString uri;
03401           rv = GetURI(getter_Copies(uri));
03402 
03403           if (NS_STATIC_CAST(const char *, actionTargetFolderUri) &&
03404             strcmp(uri, actionTargetFolderUri))
03405           {
03406             // XXXshaver I'm not actually 100% what the right semantics are for
03407             // MDNs and copied messages, but I suspect deep down inside that
03408             // we probably want to suppress them only on the copies.
03409             msgHdr->GetFlags(&msgFlags);
03410             if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && !isRead)
03411             {
03412                msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED);
03413                msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags);
03414             }
03415 
03416             nsCOMPtr<nsISupportsArray> messageArray;
03417             NS_NewISupportsArray(getter_AddRefs(messageArray));
03418             messageArray->AppendElement(msgHdr);
03419 
03420             nsCOMPtr<nsIMsgFolder> dstFolder;
03421             rv = GetExistingFolder(actionTargetFolderUri,
03422                                    getter_AddRefs(dstFolder));
03423             NS_ENSURE_SUCCESS(rv, rv);
03424 
03425             nsCOMPtr<nsIMsgCopyService> copyService =
03426               do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
03427             NS_ENSURE_SUCCESS(rv, rv);
03428             rv = copyService->CopyMessages(this, messageArray, dstFolder,
03429                                            PR_FALSE, nsnull, msgWindow, PR_FALSE);
03430             NS_ENSURE_SUCCESS(rv, rv);
03431           }
03432         }
03433         break;
03434         case nsMsgFilterAction::MarkRead:
03435         {
03436           nsMsgKeyArray keysToFlag;
03437           keysToFlag.Add(msgKey);
03438           mDatabase->MarkHdrRead(msgHdr, PR_TRUE, nsnull);
03439           StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, keysToFlag.GetArray(), keysToFlag.GetSize(), nsnull);
03440           msgIsNew = PR_FALSE;
03441         }
03442         break;
03443         case nsMsgFilterAction::MarkFlagged:
03444         {
03445           nsMsgKeyArray keysToFlag;
03446           keysToFlag.Add(msgKey);
03447           mDatabase->MarkHdrMarked(msgHdr, PR_TRUE, nsnull);
03448           StoreImapFlags(kImapMsgFlaggedFlag, PR_TRUE, keysToFlag.GetArray(), keysToFlag.GetSize(), nsnull);
03449         }
03450         break;
03451         case nsMsgFilterAction::KillThread:
03452           // The db will check for this flag when a hdr gets added to the db, and set the flag appropriately on the thread object
03453           msgHdr->OrFlags(MSG_FLAG_IGNORED, &newFlags);
03454           break;
03455         case nsMsgFilterAction::WatchThread:
03456           msgHdr->OrFlags(MSG_FLAG_WATCHED, &newFlags);
03457         break;
03458         case nsMsgFilterAction::ChangePriority:
03459         {
03460           nsMsgPriorityValue filterPriority;
03461           filterAction->GetPriority(&filterPriority);
03462           msgHdr->SetPriority(filterPriority);
03463         }
03464         break;
03465         case nsMsgFilterAction::Label:
03466         {
03467           nsMsgLabelValue filterLabel;
03468           filterAction->GetLabel(&filterLabel);
03469           msgHdr->SetLabel(filterLabel);
03470           nsMsgKeyArray keysToFlag;
03471 
03472           keysToFlag.Add(msgKey);
03473           StoreImapFlags((filterLabel << 9), PR_TRUE, keysToFlag.GetArray(), 
03474                           keysToFlag.GetSize(), nsnull);
03475         }
03476         break;
03477         case nsMsgFilterAction::AddTag:
03478         {
03479           nsXPIDLCString keyword;
03480           filterAction->GetStrValue(getter_Copies(keyword));
03481           nsCOMPtr<nsISupportsArray> messageArray;
03482           NS_NewISupportsArray(getter_AddRefs(messageArray));
03483           messageArray->AppendElement(msgHdr);
03484           AddKeywordsToMessages(messageArray, keyword.get());
03485           break;
03486         }
03487         case nsMsgFilterAction::JunkScore:
03488         {
03489           nsCAutoString junkScoreStr;
03490           PRInt32 junkScore;
03491           filterAction->GetJunkScore(&junkScore);
03492           junkScoreStr.AppendInt(junkScore);
03493           mDatabase->SetStringProperty(msgKey, "junkscore", junkScoreStr.get());
03494           mDatabase->SetStringProperty(msgKey, "junkscoreorigin", /* ### should this be plugin? */"plugin");
03495           if (junkScore == 100 || !junkScore) // if score is 0 or 100, set up to store junk status on server.
03496           {
03497             nsMsgKeyArray *keysToClassify = m_moveCoalescer->GetKeyBucket((junkScore == 100) ? 0 : 1);
03498             NS_ASSERTION(keysToClassify, "error getting key bucket");
03499             if (keysToClassify)
03500               keysToClassify->Add(msgKey);
03501             if (junkScore == 100)
03502               msgIsNew = PR_FALSE;
03503           }
03504         }
03505         break;
03506       case nsMsgFilterAction::Forward:
03507         {
03508           nsXPIDLCString forwardTo;
03509           filterAction->GetStrValue(getter_Copies(forwardTo));
03510           nsCOMPtr <nsIMsgIncomingServer> server;
03511           rv = GetServer(getter_AddRefs(server));
03512           NS_ENSURE_SUCCESS(rv, rv);
03513           if (!forwardTo.IsEmpty())
03514           {
03515             nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
03516             if (compService)
03517             {
03518               nsAutoString forwardStr;
03519               forwardStr.AssignWithConversion(forwardTo.get());
03520               rv = compService->ForwardMessage(forwardStr, msgHdr, msgWindow, server);
03521             }
03522           }
03523         }
03524         break;
03525 
03526       case nsMsgFilterAction::Reply:
03527         {
03528           nsXPIDLCString replyTemplateUri;
03529           filterAction->GetStrValue(getter_Copies(replyTemplateUri));
03530           nsCOMPtr <nsIMsgIncomingServer> server;
03531           GetServer(getter_AddRefs(server));
03532           NS_ENSURE_SUCCESS(rv, rv);
03533           if (!replyTemplateUri.IsEmpty())
03534           {
03535             nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
03536             if (compService)
03537               rv = compService->ReplyWithTemplate(msgHdr, replyTemplateUri, msgWindow, server);
03538           }
03539         }
03540         break;
03541 
03542         default:
03543           break;
03544       }
03545       if (loggingEnabled)
03546       {
03547         // only log if successful move, or non-move action
03548         if (m_msgMovedByFilter || (actionType != nsMsgFilterAction::MoveToFolder &&
03549              (actionType != nsMsgFilterAction::Delete || !deleteToTrash)))
03550           (void) filter->LogRuleHit(filterAction, msgHdr);
03551       }
03552     }
03553   }
03554   if (!msgIsNew)
03555   {
03556     PRInt32 numNewMessages;
03557     GetNumNewMessages(PR_FALSE, &numNewMessages);
03558     SetNumNewMessages(numNewMessages - 1);
03559   }
03560   return NS_OK;
03561 }
03562 
03563 NS_IMETHODIMP nsImapMailFolder::SetImapFlags(const char *uids, PRInt32 flags, nsIURI **url)
03564 {
03565   nsresult rv;
03566   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03567   NS_ENSURE_SUCCESS(rv,rv);
03568 
03569   return imapService->SetMessageFlags(m_eventQueue, this, this,
03570                                  url, uids, flags, PR_TRUE);
03571 }
03572 
03573 // "this" is the parent folder
03574 NS_IMETHODIMP nsImapMailFolder::PlaybackOfflineFolderCreate(const PRUnichar *aFolderName, nsIMsgWindow *aWindow, nsIURI **url)
03575 {
03576     NS_ENSURE_ARG_POINTER(aFolderName);
03577 
03578     nsresult rv;
03579     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03580     NS_ENSURE_SUCCESS(rv,rv);
03581 
03582     return imapService->CreateFolder(m_eventQueue, this, 
03583                                        aFolderName, this, url);
03584 }
03585 
03586 NS_IMETHODIMP nsImapMailFolder::ReplayOfflineMoveCopy(nsMsgKey *msgKeys, PRUint32 numKeys, PRBool isMove, nsIMsgFolder *aDstFolder,
03587                          nsIUrlListener *aUrlListener, nsIMsgWindow *aWindow)
03588 {
03589   nsresult rv;
03590   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03591   if (NS_SUCCEEDED(rv))
03592   {
03593     nsCOMPtr <nsIURI> resultUrl;
03594     nsCAutoString uids;
03595     AllocateUidStringFromKeys(msgKeys, numKeys, uids);
03596     rv = imapService->OnlineMessageCopy(m_eventQueue, 
03597                          this,
03598                          uids.get(),
03599                          aDstFolder,
03600                          PR_TRUE,
03601                          isMove,
03602                          aUrlListener,
03603                          getter_AddRefs(resultUrl), nsnull, aWindow);
03604     if (resultUrl)
03605     {
03606       nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(resultUrl);
03607       if (mailnewsUrl)
03608       {
03609         nsCOMPtr <nsIUrlListener> folderListener = do_QueryInterface(aDstFolder);
03610         if (folderListener)
03611           mailnewsUrl->RegisterListener(folderListener);
03612       }
03613     }
03614   }
03615   return rv;
03616 }
03617 
03618 NS_IMETHODIMP nsImapMailFolder::StoreImapFlags(PRInt32 flags, PRBool addFlags, 
03619                                                nsMsgKey *keys, PRUint32 numKeys,
03620                                                nsIUrlListener *aUrlListener)
03621 {
03622   nsresult rv = NS_OK;
03623   if (!WeAreOffline())
03624   {
03625     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03626     if (NS_SUCCEEDED(rv))
03627     {
03628       nsCAutoString msgIds;
03629       AllocateUidStringFromKeys(keys, numKeys, msgIds);
03630 
03631       if (addFlags)
03632       {
03633         imapService->AddMessageFlags(m_eventQueue, this, aUrlListener ? aUrlListener : this,
03634                                      nsnull, msgIds.get(), flags, PR_TRUE);
03635       }
03636       else
03637       {
03638         imapService->SubtractMessageFlags(m_eventQueue, this, aUrlListener ? aUrlListener : this,
03639                                           nsnull, msgIds.get(), flags,
03640                                           PR_TRUE);
03641       }
03642     }
03643   }
03644   else
03645   {
03646     GetDatabase(nsnull);
03647     if (mDatabase)
03648     {
03649       PRUint32 total = numKeys;
03650 
03651       for (PRUint32 keyIndex=0; keyIndex < total; keyIndex++)
03652       {
03653         nsCOMPtr <nsIMsgOfflineImapOperation> op;
03654         rv = mDatabase->GetOfflineOpForKey(keys[keyIndex], PR_TRUE, getter_AddRefs(op));
03655         SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
03656         if (NS_SUCCEEDED(rv) && op)
03657         {
03658           imapMessageFlagsType newFlags;
03659           op->GetNewFlags(&newFlags);
03660 
03661           if (addFlags)
03662             op->SetFlagOperation(newFlags | flags);
03663           else
03664             op->SetFlagOperation(newFlags & ~flags);
03665         }
03666       }
03667       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit); // flush offline flags
03668     }
03669   }
03670   return rv;
03671 }
03672 
03673 NS_IMETHODIMP nsImapMailFolder::LiteSelect(nsIUrlListener *aUrlListener)
03674 {
03675   nsresult rv;
03676   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03677   NS_ENSURE_SUCCESS(rv,rv);
03678 
03679   return imapService->LiteSelectFolder(m_eventQueue, this, aUrlListener, nsnull);
03680 }
03681 
03682 nsresult nsImapMailFolder::GetFolderOwnerUserName(char **userName)
03683 {  
03684   if ((mFlags & MSG_FOLDER_FLAG_IMAP_PERSONAL) ||
03685     !(mFlags & (MSG_FOLDER_FLAG_IMAP_PUBLIC | MSG_FOLDER_FLAG_IMAP_OTHER_USER)))
03686   {
03687     // this is one of our personal mail folders
03688     // return our username on this host
03689   nsCOMPtr<nsIMsgIncomingServer> server;
03690   nsresult rv = GetServer(getter_AddRefs(server));
03691   if (NS_SUCCEEDED(rv) && server)
03692     return server->GetUsername(userName);
03693   else
03694     return rv;
03695   }
03696   
03697   // the only other type of owner is if it's in the other users' namespace
03698   if (!(mFlags & MSG_FOLDER_FLAG_IMAP_OTHER_USER))
03699     return NS_OK;
03700   
03701   if (m_ownerUserName.IsEmpty())
03702   {
03703     nsXPIDLCString onlineName;
03704     GetOnlineName(getter_Copies(onlineName));
03705     m_ownerUserName = nsIMAPNamespaceList::GetFolderOwnerNameFromPath(GetNamespaceForFolder(), onlineName.get());
03706   }
03707   *userName = !m_ownerUserName.IsEmpty() ? ToNewCString(m_ownerUserName) : nsnull;
03708   return NS_OK;
03709 }
03710 
03711 // returns the online folder name, with the other users' namespace and his username
03712 // stripped out
03713 nsresult nsImapMailFolder::GetOwnersOnlineFolderName(char **retName)
03714 {
03715   nsXPIDLCString onlineName;
03716 
03717   GetOnlineName(getter_Copies(onlineName));
03718   if (mFlags & MSG_FOLDER_FLAG_IMAP_OTHER_USER)
03719   {
03720     nsXPIDLCString user;
03721     GetFolderOwnerUserName(getter_Copies(user));
03722     if (!onlineName.IsEmpty() && !user.IsEmpty())
03723     {
03724       const char *where = PL_strstr(onlineName.get(), user.get());
03725       NS_ASSERTION(where, "user name not in online name");
03726       if (where)
03727       {
03728         const char *relativeFolder = where + strlen(user) + 1;
03729         if (!relativeFolder)       // root of this user's personal namespace
03730         {
03731           *retName = PL_strdup("");
03732           return NS_OK;
03733         }
03734         else
03735         {
03736           *retName = PL_strdup(relativeFolder);
03737           return NS_OK;
03738         }
03739       }
03740     }
03741 
03742     *retName = PL_strdup(onlineName.get());
03743     return NS_OK;
03744   }
03745   else if (!(mFlags & MSG_FOLDER_FLAG_IMAP_PUBLIC))
03746   {
03747     // We own this folder.
03748     *retName = nsIMAPNamespaceList::GetFolderNameWithoutNamespace(GetNamespaceForFolder(), onlineName);
03749     
03750   }
03751   else
03752     *retName = PL_strdup(onlineName.get());
03753   return NS_OK;
03754 }
03755 
03756 nsIMAPNamespace *nsImapMailFolder::GetNamespaceForFolder()
03757 {
03758   if (!m_namespace)
03759   {
03760 #ifdef DEBUG_bienvenu
03761     // Make sure this isn't causing us to open the database
03762     NS_ASSERTION(m_hierarchyDelimiter != kOnlineHierarchySeparatorUnknown, "haven't set hierarchy delimiter");
03763 #endif
03764     nsXPIDLCString serverKey;
03765     nsXPIDLCString onlineName;
03766     GetServerKey(getter_Copies(serverKey));
03767     GetOnlineName(getter_Copies(onlineName));
03768     PRUnichar hierarchyDelimiter;
03769     GetHierarchyDelimiter(&hierarchyDelimiter);
03770 
03771     m_namespace = nsIMAPNamespaceList::GetNamespaceForFolder(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter);
03772     NS_ASSERTION(m_namespace, "didn't get namespace for folder");
03773     if (m_namespace)
03774     {
03775       nsIMAPNamespaceList::SuggestHierarchySeparatorForNamespace(m_namespace, (char) hierarchyDelimiter);
03776       m_folderIsNamespace = nsIMAPNamespaceList::GetFolderIsNamespace(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter, m_namespace);
03777     }
03778   }
03779   return m_namespace;
03780 }
03781 
03782 void nsImapMailFolder::SetNamespaceForFolder(nsIMAPNamespace *ns)
03783 {
03784 #ifdef DEBUG_bienvenu
03785   NS_ASSERTION(ns, "null namespace");
03786 #endif
03787   m_namespace = ns;
03788 }
03789 
03790 nsresult nsImapMailFolder::GetServerAdminUrl(char **aAdminUrl)
03791 {
03792   nsCOMPtr<nsIImapIncomingServer> imapServer;
03793   nsresult rv = GetImapIncomingServer(getter_AddRefs(imapServer));
03794 
03795   if (NS_SUCCEEDED(rv) && imapServer) 
03796     rv = imapServer->GetManageMailAccountUrl(aAdminUrl);
03797   return rv;
03798 }
03799 
03800 NS_IMETHODIMP nsImapMailFolder::FolderPrivileges(nsIMsgWindow *window)
03801 {
03802   nsresult rv = NS_ERROR_NULL_POINTER;  // if no window...
03803   if (window) 
03804   {
03805 #ifdef DEBUG_bienvenu
03806     m_adminUrl.Assign("http://www.netscape.com");
03807 #endif
03808     if (!m_adminUrl.IsEmpty())
03809     {
03810       nsCOMPtr <nsIDocShell> docShell;
03811       rv = window->GetRootDocShell(getter_AddRefs(docShell));
03812       if (NS_SUCCEEDED(rv) && docShell)
03813       {
03814         nsCOMPtr<nsIURI> uri;
03815         if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(uri), m_adminUrl.get())))
03816           return rv;
03817         rv = docShell->LoadURI(uri, nsnull, nsIWebNavigation::LOAD_FLAGS_IS_LINK, PR_FALSE);
03818 
03819       }
03820     }
03821     else
03822     {
03823     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03824     NS_ENSURE_SUCCESS(rv,rv);
03825 
03826     rv = imapService->GetFolderAdminUrl(m_eventQueue, this, window, this, nsnull);
03827     if (NS_SUCCEEDED(rv))
03828       m_urlRunning = PR_TRUE;
03829     }
03830   }
03831   return rv;
03832 }
03833 
03834 NS_IMETHODIMP nsImapMailFolder::GetHasAdminUrl(PRBool *aBool)
03835 {
03836   NS_ENSURE_ARG_POINTER(aBool);
03837   nsXPIDLCString manageMailAccountUrl;
03838   nsresult rv = GetServerAdminUrl(getter_Copies(manageMailAccountUrl));
03839   *aBool = (NS_SUCCEEDED(rv) && !manageMailAccountUrl.IsEmpty());
03840   return rv;
03841 }
03842 
03843 NS_IMETHODIMP nsImapMailFolder::GetAdminUrl(char **aResult)
03844 {
03845   NS_ENSURE_ARG_POINTER(aResult);
03846   *aResult = ToNewCString(m_adminUrl);
03847   return NS_OK;
03848 }
03849 
03850 NS_IMETHODIMP nsImapMailFolder::SetAdminUrl(const char *adminUrl)
03851 {
03852   m_adminUrl = adminUrl;
03853   return NS_OK;
03854 }
03855 
03856 NS_IMETHODIMP nsImapMailFolder::GetHdrParser(nsIMsgParseMailMsgState **aHdrParser)
03857 {
03858   NS_ENSURE_ARG_POINTER(aHdrParser);
03859   NS_IF_ADDREF(*aHdrParser = m_msgParser);
03860   return NS_OK;
03861 }
03862 
03863   // this is used to issue an arbitrary imap command on the passed in msgs.
03864   // It assumes the command needs to be run in the selected state.
03865 NS_IMETHODIMP nsImapMailFolder::IssueCommandOnMsgs(const char *command, const char *uids, nsIMsgWindow *aWindow, nsIURI **url)
03866 {
03867   nsresult rv;
03868   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03869   NS_ENSURE_SUCCESS(rv,rv);
03870 
03871   return imapService->IssueCommandOnMsgs(m_eventQueue, this, aWindow, command, uids, url);
03872 }
03873 
03874 NS_IMETHODIMP nsImapMailFolder::FetchCustomMsgAttribute(const char *attribute, const char *uids, nsIMsgWindow *aWindow, nsIURI **url)
03875 {
03876   nsresult rv;
03877   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
03878   NS_ENSURE_SUCCESS(rv,rv);
03879 
03880   return imapService->FetchCustomMsgAttribute(m_eventQueue, this, aWindow, attribute, uids, url);
03881 }
03882 
03883 nsresult nsImapMailFolder::MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr, 
03884                                                    nsIMsgDatabase *sourceDB, 
03885                                                    const nsACString& destFolderUri,
03886                                                    nsIMsgFilter *filter,
03887                                                    nsIMsgWindow *msgWindow)
03888 {
03889   nsresult err = NS_OK;
03890   
03891   if (m_moveCoalescer)
03892   {
03893 
03894     nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &err)); 
03895     nsCOMPtr<nsIRDFResource> res;
03896     err = rdf->GetResource(destFolderUri, getter_AddRefs(res));
03897     if (NS_FAILED(err))
03898       return err;
03899 
03900     nsCOMPtr<nsIMsgFolder> destIFolder(do_QueryInterface(res, &err));
03901     if (NS_FAILED(err))
03902       return err;        
03903 
03904     if (destIFolder)
03905     {
03906       // check if the destination is a real folder (by checking for null parent)
03907       // and if it can file messages (e.g., servers or news folders can't file messages).
03908       // Or read only imap folders...
03909       PRBool canFileMessages = PR_TRUE;
03910       nsCOMPtr<nsIMsgFolder> parentFolder;
03911       destIFolder->GetParent(getter_AddRefs(parentFolder));
03912       if (parentFolder)
03913         destIFolder->GetCanFileMessages(&canFileMessages);
03914       if (filter && (!parentFolder || !canFileMessages))
03915       {
03916         filter->SetEnabled(PR_FALSE);
03917         m_filterList->SaveToDefaultFile();
03918         destIFolder->ThrowAlertMsg("filterDisabled",msgWindow);
03919         return NS_MSG_NOT_A_MAIL_FOLDER;
03920       }
03921       // put the header into the source db, since it needs to be there when we copy it
03922       // and we need a valid header to pass to StartAsyncCopyMessagesInto
03923       nsMsgKey keyToFilter;
03924       mailHdr->GetMessageKey(&keyToFilter);
03925 
03926       if (sourceDB && destIFolder)
03927       {
03928         PRBool imapDeleteIsMoveToTrash = DeleteIsMoveToTrash();
03929 
03930         m_moveCoalescer->AddMove (destIFolder, keyToFilter);
03931         // For each folder, we need to keep track of the ids we want to move to that
03932         // folder - we used to store them in the MSG_FolderInfo and then when we'd finished
03933         // downloading headers, we'd iterate through all the folders looking for the ones
03934         // that needed messages moved into them - perhaps instead we could
03935         // keep track of nsIMsgFolder, nsMsgKeyArray pairs here in the imap code.
03936 //        nsMsgKeyArray *idsToMoveFromInbox = msgFolder->GetImapIdsToMoveFromInbox();
03937 //        idsToMoveFromInbox->Add(keyToFilter);
03938         if (imapDeleteIsMoveToTrash)
03939         {
03940         }
03941         PRBool isRead = PR_FALSE;
03942         mailHdr->GetIsRead(&isRead);
03943         if (!isRead)
03944           destIFolder->SetFlag(MSG_FOLDER_FLAG_GOT_NEW);
03945         
03946         if (imapDeleteIsMoveToTrash)  
03947           err = 0;
03948       }
03949     }
03950   }
03951   
03952   
03953   // we have to return an error because we do not actually move the message
03954   // it is done async and that can fail
03955   return err;
03956 }
03957 
03958 
03959 // both of these algorithms assume that key arrays and flag states are sorted by increasing key.
03960 void nsImapMailFolder::FindKeysToDelete(const nsMsgKeyArray &existingKeys, nsMsgKeyArray &keysToDelete, nsIImapFlagAndUidState *flagState)
03961 {
03962   PRBool showDeletedMessages = ShowDeletedMessages();
03963   PRUint32 total = existingKeys.GetSize();
03964   PRInt32 messageIndex;
03965 
03966   int onlineIndex=0; // current index into flagState
03967   for (PRUint32 keyIndex=0; keyIndex < total; keyIndex++)
03968   {
03969     PRUint32 uidOfMessage;
03970 
03971     flagState->GetNumberOfMessages(&messageIndex);
03972     while ((onlineIndex < messageIndex) && 
03973          (flagState->GetUidOfMessage(onlineIndex, &uidOfMessage), (existingKeys[keyIndex] > uidOfMessage) ))
03974     {
03975       onlineIndex++;
03976     }
03977     
03978     imapMessageFlagsType flags;
03979     flagState->GetUidOfMessage(onlineIndex, &uidOfMessage);
03980     flagState->GetMessageFlags(onlineIndex, &flags);
03981     // delete this key if it is not there or marked deleted
03982     if ( (onlineIndex >= messageIndex ) ||
03983        (existingKeys[keyIndex] != uidOfMessage) ||
03984        ((flags & kImapMsgDeletedFlag) && !showDeletedMessages) )
03985     {
03986       nsMsgKey doomedKey = existingKeys[keyIndex];
03987       if ((PRInt32) doomedKey <= 0 && doomedKey != nsMsgKey_None)
03988         continue;
03989       else
03990         keysToDelete.Add(existingKeys[keyIndex]);
03991     }
03992     
03993     flagState->GetUidOfMessage(onlineIndex, &uidOfMessage);
03994     if (existingKeys[keyIndex] == uidOfMessage) 
03995       onlineIndex++;
03996   }
03997 }
03998 
03999 void nsImapMailFolder::FindKeysToAdd(const nsMsgKeyArray &existingKeys, nsMsgKeyArray &keysToFetch, PRUint32 &numNewUnread, nsIImapFlagAndUidState *flagState)
04000 {
04001   PRBool showDeletedMessages = ShowDeletedMessages();
04002   int dbIndex=0; // current index into existingKeys
04003   PRInt32 existTotal, numberOfKnownKeys;
04004   PRInt32 messageIndex;
04005  
04006   numNewUnread = 0;
04007   existTotal = numberOfKnownKeys = existingKeys.GetSize();
04008   flagState->GetNumberOfMessages(&messageIndex);
04009   for (PRInt32 flagIndex=0; flagIndex < messageIndex; flagIndex++)
04010   {
04011     PRUint32 uidOfMessage;
04012     flagState->GetUidOfMessage(flagIndex, &uidOfMessage);
04013     while ( (flagIndex < numberOfKnownKeys) && (dbIndex < existTotal) &&
04014         existingKeys[dbIndex] < uidOfMessage) 
04015       dbIndex++;
04016     
04017     if ( (flagIndex >= numberOfKnownKeys)  || 
04018        (dbIndex >= existTotal) ||
04019        (existingKeys[dbIndex] != uidOfMessage ) )
04020     {
04021       numberOfKnownKeys++;
04022 
04023       imapMessageFlagsType flags;
04024       flagState->GetMessageFlags(flagIndex, &flags);
04025       NS_ASSERTION(uidOfMessage != nsMsgKey_None, "got invalid msg key");
04026       if (uidOfMessage && uidOfMessage != nsMsgKey_None && (showDeletedMessages || ! (flags & kImapMsgDeletedFlag)))
04027       {
04028         if (mDatabase)
04029         {
04030           PRBool dbContainsKey;
04031           if (NS_SUCCEEDED(mDatabase->ContainsKey(uidOfMessage, &dbContainsKey)) && dbContainsKey)
04032           {
04033             NS_ASSERTION(PR_FALSE, "db has key - flagState messed up?");
04034             continue;
04035           }
04036         }
04037         keysToFetch.Add(uidOfMessage);
04038         if (! (flags & kImapMsgSeenFlag))
04039           numNewUnread++;
04040       }
04041     }
04042   }
04043 }
04044 
04045 void nsImapMailFolder::PrepareToAddHeadersToMailDB(nsIImapProtocol* aProtocol, const nsMsgKeyArray &keysToFetch,
04046                                                 nsIMailboxSpec *boxSpec)
04047 {
04048   PRUint32 *theKeys = (PRUint32 *) PR_Malloc( keysToFetch.GetSize() * sizeof(PRUint32) );
04049   if (theKeys)
04050   {
04051     PRUint32 total = keysToFetch.GetSize();
04052     
04053     for (PRUint32 keyIndex=0; keyIndex < total; keyIndex++)
04054       theKeys[keyIndex] = keysToFetch[keyIndex];
04055     
04056     // tell the imap thread which hdrs to download
04057     if (aProtocol)
04058     {
04059       aProtocol->NotifyHdrsToDownload(theKeys, total /*keysToFetch.GetSize() */);
04060       // now, tell it we don't need any bodies.
04061       aProtocol->NotifyBodysToDownload(nsnull, 0);
04062     }
04063   }
04064   else
04065   {
04066     if (aProtocol)
04067       aProtocol->NotifyHdrsToDownload(nsnull, 0);
04068   }
04069 }
04070 
04071 
04072 void nsImapMailFolder::TweakHeaderFlags(nsIImapProtocol* aProtocol, nsIMsgDBHdr *tweakMe)
04073 {
04074   if (mDatabase && aProtocol && tweakMe)
04075   {
04076     tweakMe->SetMessageKey(m_curMsgUid);
04077     tweakMe->SetMessageSize(m_nextMessageByteLength);
04078     
04079     PRBool foundIt = PR_FALSE;
04080     imapMessageFlagsType imap_flags;
04081 
04082     nsXPIDLCString customFlags;
04083     nsresult res = aProtocol->GetFlagsForUID(m_curMsgUid, &foundIt, &imap_flags, getter_Copies(customFlags));
04084     if (NS_SUCCEEDED(res) && foundIt)
04085     {
04086       // make a mask and clear these message flags
04087       PRUint32 mask = MSG_FLAG_READ | MSG_FLAG_REPLIED | MSG_FLAG_MARKED | MSG_FLAG_IMAP_DELETED | MSG_FLAG_LABELS;
04088       PRUint32 dbHdrFlags;
04089 
04090       tweakMe->GetFlags(&dbHdrFlags);
04091       tweakMe->AndFlags(~mask, &dbHdrFlags);
04092       
04093       // set the new value for these flags
04094       PRUint32 newFlags = 0;
04095       if (imap_flags & kImapMsgSeenFlag)
04096         newFlags |= MSG_FLAG_READ;
04097       else // if (imap_flags & kImapMsgRecentFlag)
04098         newFlags |= MSG_FLAG_NEW;
04099 
04100       // Okay here is the MDN needed logic (if DNT header seen):
04101       /* if server support user defined flag:
04102           MDNSent flag set => clear kMDNNeeded flag
04103           MDNSent flag not set => do nothing, leave kMDNNeeded on
04104          else if 
04105           not MSG_FLAG_NEW => clear kMDNNeeded flag
04106           MSG_FLAG_NEW => do nothing, leave kMDNNeeded on
04107        */
04108       PRUint16 userFlags;
04109       res = aProtocol->GetSupportedUserFlags(&userFlags);
04110       if (NS_SUCCEEDED(res) && (userFlags & (kImapMsgSupportUserFlag |
04111                             kImapMsgSupportMDNSentFlag)))
04112       {
04113         if (imap_flags & kImapMsgMDNSentFlag)
04114         {
04115           newFlags |= MSG_FLAG_MDN_REPORT_SENT;
04116           if (dbHdrFlags & MSG_FLAG_MDN_REPORT_NEEDED)
04117             tweakMe->AndFlags(~MSG_FLAG_MDN_REPORT_NEEDED, &dbHdrFlags);
04118         }
04119       }
04120 
04121       if (imap_flags & kImapMsgAnsweredFlag)
04122         newFlags |= MSG_FLAG_REPLIED;
04123       if (imap_flags & kImapMsgFlaggedFlag)
04124         newFlags |= MSG_FLAG_MARKED;
04125       if (imap_flags & kImapMsgDeletedFlag)
04126         newFlags |= MSG_FLAG_IMAP_DELETED;
04127       if (imap_flags & kImapMsgForwardedFlag)
04128         newFlags |= MSG_FLAG_FORWARDED;
04129 
04130       // db label flags are 0x0E000000 and imap label flags are 0x0E00
04131       // so we need to shift 16 bits to the left to convert them.
04132       if (imap_flags & kImapMsgLabelFlags)
04133       {
04134         // we need to set label attribute on header because the dbview code 
04135         // does msgHdr->GetLabel when asked to paint a row
04136         tweakMe->SetLabel((imap_flags & kImapMsgLabelFlags) >> 9);
04137         newFlags |= (imap_flags & kImapMsgLabelFlags) << 16;
04138       }
04139 
04140       if (newFlags)
04141         tweakMe->OrFlags(newFlags, &dbHdrFlags);
04142       if (!customFlags.IsEmpty())
04143         (void) HandleCustomFlags(m_curMsgUid, tweakMe, customFlags);
04144     }
04145   }
04146 }    
04147 
04148 NS_IMETHODIMP
04149 //nsImapMailFolder::SetupMsgWriteStream(nsIFileSpec * aFileSpec, PRBool addDummyEnvelope)
04150 nsImapMailFolder::SetupMsgWriteStream(const char * aNativeString, PRBool addDummyEnvelope)
04151 {
04152     nsresult rv = NS_ERROR_FAILURE;
04153 //    if (!aFileSpec)
04154 //        return NS_ERROR_NULL_POINTER;
04155     nsFileSpec fileSpec (aNativeString);
04156 //    aFileSpec->GetFileSpec(&fileSpec);
04157   fileSpec.Delete(PR_FALSE);
04158   nsCOMPtr<nsISupports>  supports;
04159   rv = NS_NewIOFileStream(getter_AddRefs(supports), fileSpec, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 00700);
04160   m_tempMessageStream = do_QueryInterface(supports);
04161     if (m_tempMessageStream && addDummyEnvelope)
04162     {
04163         nsCAutoString result;
04164         char *ct;
04165         PRUint32 writeCount;
04166         time_t now = time ((time_t*) 0);
04167         ct = ctime(&now);
04168         ct[24] = 0;
04169         result = "From - ";
04170         result += ct;
04171         result += MSG_LINEBREAK;
04172         
04173         m_tempMessageStream->Write(result.get(), result.Length(),
04174                                    &writeCount);
04175         result = "X-Mozilla-Status: 0001";
04176         result += MSG_LINEBREAK;
04177         m_tempMessageStream->Write(result.get(), result.Length(),
04178                                    &writeCount);
04179         result =  "X-Mozilla-Status2: 00000000";
04180         result += MSG_LINEBREAK;
04181         m_tempMessageStream->Write(result.get(), result.Length(),
04182                                    &writeCount);
04183     }
04184     return rv;
04185 }
04186 
04187 NS_IMETHODIMP nsImapMailFolder::DownloadMessagesForOffline(nsISupportsArray *messages, nsIMsgWindow *window)
04188 {
04189   nsCAutoString messageIds;
04190   nsMsgKeyArray srcKeyArray;
04191   nsresult rv = BuildIdsAndKeyArray(messages, messageIds, srcKeyArray);
04192   if (NS_FAILED(rv) || messageIds.IsEmpty()) return rv;
04193 
04194   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
04195   NS_ENSURE_SUCCESS(rv,rv);
04196 
04197   SetNotifyDownloadedLines(PR_TRUE); 
04198   rv = AcquireSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this));
04199   if (NS_FAILED(rv))
04200   {
04201     ThrowAlertMsg("operationFailedFolderBusy", window);
04202     return rv;
04203   }
04204 
04205   return imapService->DownloadMessagesForOffline(messageIds.get(), this, this, window);
04206 }
04207 
04208 NS_IMETHODIMP nsImapMailFolder::DownloadAllForOffline(nsIUrlListener *listener, nsIMsgWindow *msgWindow)
04209 {
04210   nsresult rv = NS_OK;
04211   nsCOMPtr <nsIURI> runningURI;
04212   PRBool noSelect;
04213   GetFlag(MSG_FOLDER_FLAG_IMAP_NOSELECT, &noSelect);
04214 
04215   if (!noSelect)
04216   {
04217     nsCAutoString messageIdsToDownload;
04218     nsMsgKeyArray msgsToDownload;
04219 
04220     GetDatabase(msgWindow);
04221     m_downloadingFolderForOfflineUse = PR_TRUE;
04222 
04223     rv = AcquireSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this));
04224     if (NS_FAILED(rv))
04225     {
04226       ThrowAlertMsg("operationFailedFolderBusy", msgWindow);
04227       return rv;
04228     }
04229     SetNotifyDownloadedLines(PR_TRUE); 
04230     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
04231     NS_ENSURE_SUCCESS(rv,rv);
04232 
04233     // selecting the folder with m_downloadingFolderForOfflineUse true will cause
04234     // us to fetch any message bodies we don't have.
04235     rv = imapService->SelectFolder(m_eventQueue, this, listener, msgWindow, nsnull);
04236     if (NS_SUCCEEDED(rv))
04237       m_urlRunning = PR_TRUE;
04238   }
04239   else
04240     return NS_MSG_FOLDER_UNREADABLE;
04241   return rv;
04242 }
04243 
04244 NS_IMETHODIMP
04245 nsImapMailFolder::GetNotifyDownloadedLines(PRBool *notifyDownloadedLines)
04246 {
04247   NS_ENSURE_ARG(notifyDownloadedLines);
04248   *notifyDownloadedLines = m_downloadMessageForOfflineUse;
04249   return NS_OK;
04250 }
04251 
04252 NS_IMETHODIMP
04253 nsImapMailFolder::SetNotifyDownloadedLines(PRBool notifyDownloadedLines)
04254 {
04255   // ignore this if we're downloading the whole folder and someone says
04256   // to turn off downloading for offline use, which can happen if a 3rd party
04257   // app tries to stream a message while we're downloading for offline use.
04258   if (!notifyDownloadedLines && m_downloadingFolderForOfflineUse)
04259     return NS_OK;
04260   m_downloadMessageForOfflineUse = notifyDownloadedLines;
04261   return NS_OK;
04262 }
04263 
04264 NS_IMETHODIMP 
04265 nsImapMailFolder::ParseAdoptedMsgLine(const char *adoptedMessageLine, nsMsgKey uidOfMessage)
04266 {
04267   PRUint32 count = 0;
04268   nsresult rv = NS_OK;
04269   // remember the uid of the message we're downloading.
04270   m_curMsgUid = uidOfMessage;
04271   if (m_downloadMessageForOfflineUse && !m_offlineHeader)
04272   {
04273     GetMessageHeader(uidOfMessage, getter_AddRefs(m_offlineHeader));
04274     rv = StartNewOfflineMessage();
04275   }
04276   // adoptedMessageLine is actually a string with a lot of message lines, separated by native line terminators
04277   // we need to count the number of MSG_LINEBREAK's to determine how much to increment m_numOfflineMsgLines by.
04278   if (m_downloadMessageForOfflineUse)
04279   {
04280     const char *nextLine = adoptedMessageLine;
04281     do
04282     {
04283       m_numOfflineMsgLines++;
04284       nextLine = PL_strstr(nextLine, MSG_LINEBREAK);
04285       if (nextLine)
04286         nextLine += MSG_LINEBREAK_LEN;
04287     }
04288     while (nextLine && *nextLine);
04289   }
04290   if (m_tempMessageStream)
04291   {
04292       nsCOMPtr <nsISeekableStream> seekable;
04293 
04294       seekable = do_QueryInterface(m_tempMessageStream);
04295 
04296       if (seekable)
04297         seekable->Seek(PR_SEEK_END, 0);
04298      rv = m_tempMessageStream->Write(adoptedMessageLine, 
04299                   PL_strlen(adoptedMessageLine), &count);
04300      NS_ASSERTION(NS_SUCCEEDED(rv), "failed to write to stream");
04301   }
04302                                                                                 
04303   return rv;
04304 }
04305 
04306 void nsImapMailFolder::EndOfflineDownload()
04307 {
04308   if (m_tempMessageStream)
04309   {
04310     m_tempMessageStream->Close();
04311     m_tempMessageStream = nsnull;
04312     if (mDatabase)
04313       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
04314   }
04315   m_offlineHeader = nsnull;
04316 }
04317 
04318 NS_IMETHODIMP
04319 nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, 
04320                                           PRBool markRead,
04321                                           nsIImapUrl *imapUrl)
04322 {
04323   nsresult res = NS_OK;
04324   PRBool commit = PR_FALSE;
04325   if (m_offlineHeader)
04326     EndNewOfflineMessage();
04327 
04328   m_curMsgUid = uidOfMessage;
04329   
04330   if (commit && mDatabase)
04331     mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
04332 
04333   return res;
04334 }
04335 
04336 NS_IMETHODIMP
04337 nsImapMailFolder::AbortMsgWriteStream()
04338 {
04339   m_offlineHeader = nsnull;
04340   return NS_ERROR_FAILURE;
04341 }
04342 
04343     // message move/copy related methods
04344 NS_IMETHODIMP 
04345 nsImapMailFolder::OnlineCopyCompleted(nsIImapProtocol *aProtocol, ImapOnlineCopyState aCopyState)
04346 {
04347   NS_ENSURE_ARG_POINTER(aProtocol);
04348 
04349   nsresult rv;
04350   if (aCopyState == ImapOnlineCopyStateType::kSuccessfulCopy)
04351   {
04352       
04353     nsCOMPtr <nsIImapUrl> imapUrl;
04354     rv = aProtocol->GetRunningImapURL(getter_AddRefs(imapUrl));
04355         if (NS_FAILED(rv) || !imapUrl) return NS_ERROR_FAILURE;
04356     nsImapAction action;
04357     rv = imapUrl->GetImapAction(&action);
04358     if (NS_FAILED(rv)) return rv;
04359     
04360     if (action == nsIImapUrl::nsImapOnlineToOfflineMove)
04361     {
04362         nsXPIDLCString messageIds;
04363         rv = imapUrl->CreateListOfMessageIdsString(getter_Copies(messageIds));
04364 
04365         if (NS_FAILED(rv)) return rv;
04366         nsCOMPtr<nsIImapService> imapService = 
04367                  do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
04368         NS_ENSURE_SUCCESS(rv,rv);
04369    
04370         return imapService->AddMessageFlags(m_eventQueue, this, nsnull, nsnull,
04371                                           messageIds,
04372                                           kImapMsgDeletedFlag,
04373                                           PR_TRUE);
04374     }
04375     /* unhandled action */
04376     else return NS_ERROR_FAILURE;
04377   }
04378 
04379   /* unhandled copystate */
04380   else 
04381   {
04382     // whoops, this is the wrong folder - should use the source folder
04383     if (m_copyState)
04384     {
04385        nsCOMPtr<nsIMsgFolder> srcFolder;
04386        srcFolder = do_QueryInterface(m_copyState->m_srcSupport, &rv);
04387        if (srcFolder)
04388         srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
04389     }
04390     return NS_ERROR_FAILURE;
04391   }
04392 
04393   return rv;
04394 }
04395 
04396 NS_IMETHODIMP
04397 nsImapMailFolder::PrepareToReleaseObject(nsISupports * aSupports)
04398 {
04399   NS_ASSERTION(!mSupportsToRelease, "can't prepare to release w/o releasing prev object");
04400   mSupportsToRelease = aSupports;
04401   return NS_OK;
04402 }
04403 
04404 NS_IMETHODIMP
04405 nsImapMailFolder::ReleaseObject()
04406 {
04407   mSupportsToRelease = nsnull;
04408   return NS_OK;
04409 }
04410 
04411 NS_IMETHODIMP
04412 nsImapMailFolder::CloseMockChannel(nsIImapMockChannel * aChannel)
04413 {
04414   aChannel->Close();
04415   return NS_OK;
04416 }
04417 
04418 NS_IMETHODIMP
04419 nsImapMailFolder::ReleaseUrlCacheEntry(nsIMsgMailNewsUrl *aUrl)
04420 {
04421   if (aUrl)
04422     aUrl->SetMemCacheEntry(nsnull);
04423   return NS_OK;
04424 }
04425 
04426 NS_IMETHODIMP
04427 nsImapMailFolder::BeginMessageUpload()
04428 {
04429     return NS_ERROR_FAILURE;
04430 }
04431 
04432 nsresult nsImapMailFolder::HandleCustomFlags(nsMsgKey uidOfMessage, nsIMsgDBHdr *dbHdr, nsXPIDLCString &keywords)
04433 {
04434   ToLowerCase(keywords);
04435   PRBool messageClassified = PR_TRUE;
04436   nsXPIDLCString::const_iterator b, e;
04437   if (FindInReadable(NS_LITERAL_CSTRING("NonJunk"), keywords.BeginReading(b), 
04438                       keywords.EndReading(e), nsCaseInsensitiveCStringComparator()))
04439     mDatabase->SetStringProperty(uidOfMessage, "junkscore", "0");
04440   // Mac Mail uses "NotJunk"
04441   else if (FindInReadable(NS_LITERAL_CSTRING("NotJunk"), keywords.BeginReading(b), 
04442                         keywords.EndReading(e), nsCaseInsensitiveCStringComparator()))
04443     mDatabase->SetStringProperty(uidOfMessage, "junkscore", "0");
04444   // ### TODO: we really should parse the keywords into space delimited keywords before checking
04445   else if (FindInReadable(NS_LITERAL_CSTRING("Junk"), keywords.BeginReading(b), 
04446                           keywords.EndReading(e), nsCaseInsensitiveCStringComparator()))
04447   {
04448     PRUint32 newFlags;
04449     dbHdr->AndFlags(~MSG_FLAG_NEW, &newFlags);
04450     mDatabase->SetStringProperty(uidOfMessage, "junkscore", "100");
04451   }
04452   else
04453     messageClassified = PR_FALSE;
04454   if (messageClassified)
04455   {
04456     // only set the junkscore origin if it wasn't set before. We assume plugin since we
04457     // think that's the more common scenario.
04458     nsXPIDLCString existingProperty;
04459     dbHdr->GetStringProperty("junkscoreorigin", getter_Copies(existingProperty));
04460     if (existingProperty.IsEmpty())
04461       dbHdr->SetStringProperty("junkscoreorigin", "plugin");
04462   }
04463   return dbHdr->SetStringProperty("keywords", keywords);
04464 }
04465 
04466 // synchronize the message flags in the database with the server flags
04467 nsresult nsImapMailFolder::SyncFlags(nsIImapFlagAndUidState *flagState)
04468 {
04469   nsresult rv = GetDatabase(nsnull); // we need a database for this
04470   NS_ENSURE_SUCCESS(rv, rv);
04471     // update all of the database flags
04472   PRInt32 messageIndex;
04473   PRUint32 messageSize;
04474   PRUint32 oldFolderSize = mFolderSize;
04475   // take this opportunity to recalculate the folder size:
04476   mFolderSize = 0;
04477   flagState->GetNumberOfMessages(&messageIndex);
04478 
04479   for (PRInt32 flagIndex=0; flagIndex < messageIndex; flagIndex++)
04480   {
04481     PRUint32 uidOfMessage;
04482     flagState->GetUidOfMessage(flagIndex, &uidOfMessage);
04483     imapMessageFlagsType flags;
04484     flagState->GetMessageFlags(flagIndex, &flags);
04485     nsCOMPtr<nsIMsgDBHdr> dbHdr;
04486     PRBool containsKey;
04487     rv = mDatabase->ContainsKey(uidOfMessage , &containsKey);
04488     // if we don't have the header, don't diddle the flags.
04489     // GetMsgHdrForKey will create the header if it doesn't exist.
04490     if (NS_FAILED(rv) || !containsKey)
04491       continue;
04492 
04493     rv = mDatabase->GetMsgHdrForKey(uidOfMessage, getter_AddRefs(dbHdr));
04494     if (NS_SUCCEEDED(dbHdr->GetMessageSize(&messageSize)))
04495       mFolderSize += messageSize;
04496 
04497     if (flags & kImapMsgCustomKeywordFlag)
04498     {
04499       nsXPIDLCString keywords;
04500       if (NS_SUCCEEDED(flagState->GetCustomFlags(uidOfMessage, getter_Copies(keywords))))
04501       {
04502         if (!keywords.IsEmpty() && dbHdr && NS_SUCCEEDED(rv))
04503         {
04504           HandleCustomFlags(uidOfMessage, dbHdr, keywords);
04505         }
04506       }
04507     }
04508     NotifyMessageFlagsFromHdr(dbHdr, uidOfMessage, flags);
04509   }
04510   if (oldFolderSize != mFolderSize)
04511     NotifyIntPropertyChanged(kFolderSizeAtom, oldFolderSize, mFolderSize);
04512 
04513   return NS_OK;
04514 }
04515 
04516 // helper routine to sync the flags on a given header
04517 nsresult nsImapMailFolder::NotifyMessageFlagsFromHdr(nsIMsgDBHdr *dbHdr, nsMsgKey msgKey, PRUint32 flags)
04518 {
04519     mDatabase->MarkHdrRead(dbHdr, (flags & kImapMsgSeenFlag) != 0, nsnull);
04520     mDatabase->MarkHdrReplied(dbHdr, (flags & kImapMsgAnsweredFlag) != 0, nsnull);
04521     mDatabase->MarkHdrMarked(dbHdr, (flags & kImapMsgFlaggedFlag) != 0, nsnull);
04522     mDatabase->MarkImapDeleted(msgKey, (flags & kImapMsgDeletedFlag) != 0, nsnull);
04523     // this turns on labels, but it doesn't handle the case where the user
04524     // unlabels a message on one machine, and expects it to be unlabeled
04525     // on their other machines. If I turn that on, I'll be removing all the labels
04526     // that were assigned before we started storing them on the server, which will
04527     // make some people very unhappy.
04528     if (flags & kImapMsgLabelFlags)
04529       mDatabase->SetLabel(msgKey, (flags & kImapMsgLabelFlags) >> 9);
04530     else
04531     {
04532       PRUint32 supportedFlags;
04533       GetSupportedUserFlags(&supportedFlags);
04534       if (supportedFlags & kImapMsgLabelFlags)
04535         mDatabase->SetLabel(msgKey, 0);
04536     }
04537     if (flags & kImapMsgMDNSentFlag)
04538       mDatabase->MarkMDNSent(msgKey, PR_TRUE, nsnull);
04539   
04540     return NS_OK;
04541 }
04542 
04543 // message flags operation - this is called (rarely) from the imap protocol,
04544 // proxied over from the imap thread to the ui thread
04545 NS_IMETHODIMP
04546 nsImapMailFolder::NotifyMessageFlags(PRUint32 flags, nsMsgKey msgKey)
04547 {
04548   if (NS_SUCCEEDED(GetDatabase(nsnull)) && mDatabase)
04549   {
04550     nsCOMPtr<nsIMsgDBHdr> dbHdr;
04551     nsresult rv;
04552     PRBool containsKey;
04553     
04554     rv = mDatabase->ContainsKey(msgKey , &containsKey);
04555     // if we don't have the header, don't diddle the flags.
04556     // GetMsgHdrForKey will create the header if it doesn't exist.
04557     if (NS_FAILED(rv) || !containsKey)
04558       return rv;
04559     
04560     rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(dbHdr));
04561     
04562     if(NS_SUCCEEDED(rv) && dbHdr)
04563     {
04564       NotifyMessageFlagsFromHdr(dbHdr, msgKey, flags);
04565     }
04566   }
04567   
04568   return NS_OK;
04569 }
04570 
04571 NS_IMETHODIMP
04572 nsImapMailFolder::NotifyMessageDeleted(const char *onlineFolderName,PRBool deleteAllMsgs, const char *msgIdString)
04573 {
04574   const char *doomedKeyString = msgIdString;
04575 
04576   if (deleteAllMsgs)
04577     return NS_OK;
04578 
04579   char *keyTokenString = PL_strdup(doomedKeyString);
04580   nsMsgKeyArray affectedMessages;
04581   ParseUidString(keyTokenString, affectedMessages);
04582 
04583   if (doomedKeyString && !ShowDeletedMessages())
04584   {
04585     if (affectedMessages.GetSize() > 0) // perhaps Search deleted these messages
04586     {
04587       GetDatabase(nsnull);
04588       if (mDatabase)
04589         mDatabase->DeleteMessages(&affectedMessages, nsnull);
04590     }
04591     
04592   }
04593   else if (doomedKeyString) // && !imapDeleteIsMoveToTrash
04594   {
04595     GetDatabase(nsnull);
04596     if (mDatabase)
04597       SetIMAPDeletedFlag(mDatabase, affectedMessages, nsnull);
04598   }
04599   PR_Free(keyTokenString);
04600   return NS_OK;
04601 }
04602 
04603 PRBool nsImapMailFolder::ShowDeletedMessages()
04604 {
04605   nsresult err;
04606   nsCOMPtr<nsIImapHostSessionList> hostSession = 
04607       do_GetService(kCImapHostSessionList, &err);
04608   PRBool showDeleted = PR_FALSE;
04609 
04610   if (NS_SUCCEEDED(err) && hostSession)
04611   {
04612     nsXPIDLCString serverKey;
04613     GetServerKey(getter_Copies(serverKey));
04614     err = hostSession->GetShowDeletedMessagesForHost(serverKey, showDeleted);
04615   }
04616   // check for special folders that need to show deleted messages
04617   if (!showDeleted)
04618   {
04619     nsCOMPtr<nsIImapIncomingServer> imapServer;
04620     nsresult rv = GetImapIncomingServer(getter_AddRefs(imapServer));
04621 
04622     if (NS_SUCCEEDED(rv) && imapServer) 
04623     {
04624       // See if the redirector type has a different trash folder name (ie, not 'TRASH').
04625       // If so then convert it to the beautified name (if configured) and compare it 
04626       // against the current folder name.
04627       nsXPIDLCString specialTrashName;
04628       rv = imapServer->GetTrashFolderByRedirectorType(getter_Copies(specialTrashName));
04629       if (NS_SUCCEEDED(rv))
04630       {
04631         nsXPIDLString convertedName;
04632         rv = imapServer->ConvertFolderName(specialTrashName.get(), getter_Copies(convertedName));
04633         if (NS_SUCCEEDED(rv))
04634         {
04635           nsXPIDLString folderName;
04636           GetName(getter_Copies(folderName));
04637           if (StringBeginsWith(folderName, convertedName, nsCaseInsensitiveStringComparator()))
04638             showDeleted = PR_TRUE;
04639         }
04640       }
04641     }
04642   }
04643   return showDeleted;
04644 }
04645 
04646 
04647 PRBool nsImapMailFolder::DeleteIsMoveToTrash()
04648 {
04649   nsresult err;
04650   nsCOMPtr<nsIImapHostSessionList> hostSession = 
04651              do_GetService(kCImapHostSessionList, &err);
04652   PRBool rv = PR_TRUE;
04653 
04654     if (NS_SUCCEEDED(err) && hostSession)
04655   {
04656     nsXPIDLCString serverKey;
04657     GetServerKey(getter_Copies(serverKey));
04658     err = hostSession->GetDeleteIsMoveToTrashForHost(serverKey.get(), rv);
04659   }
04660   return rv;
04661 }
04662 
04663 nsresult nsImapMailFolder::GetTrashFolder(nsIMsgFolder **pTrashFolder)
04664 {
04665   if (!pTrashFolder)
04666     return NS_ERROR_NULL_POINTER;
04667 
04668   nsCOMPtr<nsIMsgFolder> rootFolder;
04669   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
04670   if(NS_SUCCEEDED(rv))
04671   {
04672     PRUint32 numFolders;
04673     rv = rootFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_TRASH, 1, &numFolders, pTrashFolder);
04674     if (numFolders != 1)
04675       rv = NS_ERROR_FAILURE;
04676   }
04677   return rv;
04678 }
04679 
04680 
04681 // store MSG_FLAG_IMAP_DELETED in the specified mailhdr records
04682 void nsImapMailFolder::SetIMAPDeletedFlag(nsIMsgDatabase *mailDB, const nsMsgKeyArray &msgids, PRBool markDeleted)
04683 {
04684   nsresult markStatus = 0;
04685   PRUint32 total = msgids.GetSize();
04686 
04687   for (PRUint32 msgIndex=0; !markStatus && (msgIndex < total); msgIndex++)
04688   {
04689     markStatus = mailDB->MarkImapDeleted(msgids[msgIndex], markDeleted, nsnull);
04690   }
04691 }
04692 
04693 
04694 NS_IMETHODIMP
04695 nsImapMailFolder::GetMessageSizeFromDB(const char *id, PRBool idIsUid, PRUint32 *size)
04696 {
04697   nsresult rv = NS_ERROR_FAILURE;
04698   NS_ENSURE_ARG(size);
04699   *size = 0;
04700   (void) GetDatabase(nsnull);
04701   if (id && mDatabase)
04702   {
04703     PRUint32 key = atoi(id);
04704     nsCOMPtr<nsIMsgDBHdr> mailHdr;
04705     NS_ASSERTION(idIsUid, "ids must be uids to get message size");
04706     if (idIsUid)
04707       rv = mDatabase->GetMsgHdrForKey(key, getter_AddRefs(mailHdr));
04708     if (NS_SUCCEEDED(rv) && mailHdr)
04709       rv = mailHdr->GetMessageSize(size);
04710   }
04711   return rv;
04712 }
04713 
04714 NS_IMETHODIMP
04715 nsImapMailFolder::SetContentModified(nsIImapUrl *aImapUrl, nsImapContentModifiedType modified)
04716 {
04717   return aImapUrl->SetContentModified(modified);
04718 }
04719 
04720 NS_IMETHODIMP
04721 nsImapMailFolder::SetImageCacheSessionForUrl(nsIMsgMailNewsUrl *mailurl)
04722 {
04723   nsresult rv;
04724   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
04725   NS_ENSURE_SUCCESS(rv,rv);
04726   
04727   nsCOMPtr<nsICacheSession> cacheSession;
04728   rv = imapService->GetCacheSession(getter_AddRefs(cacheSession));
04729   if (NS_SUCCEEDED(rv) && cacheSession)
04730     rv = mailurl->SetImageCacheSession(cacheSession);
04731 
04732   return rv;
04733 }
04734 
04735 NS_IMETHODIMP nsImapMailFolder::GetCurMoveCopyMessageInfo(nsIImapUrl *runningUrl, PRTime *aDate, char **aKeywords, PRUint32 *aResult)
04736 {
04737   nsCOMPtr <nsISupports> copyState;
04738   runningUrl->GetCopyState(getter_AddRefs(copyState));
04739   if (copyState)
04740   {
04741     nsCOMPtr<nsImapMailCopyState> mailCopyState = do_QueryInterface(copyState);
04742     if (mailCopyState && mailCopyState->m_message)
04743     {
04744       nsMsgLabelValue label;
04745       PRUint32 supportedFlags = 0;
04746       mailCopyState->m_message->GetFlags(aResult);
04747       GetSupportedUserFlags(&supportedFlags);
04748       if (supportedFlags & (kImapMsgSupportUserFlag | kImapMsgLabelFlags))
04749       {
04750       mailCopyState->m_message->GetLabel(&label);
04751       if (label != 0)
04752         *aResult |= label << 25;
04753       }
04754       if (aDate)
04755         mailCopyState->m_message->GetDate(aDate);
04756       if (aKeywords && (supportedFlags & (kImapMsgSupportUserFlag)))
04757         mailCopyState->m_message->GetStringProperty("keywords", aKeywords);
04758     }
04759     // if we don't have a source header, and it's not the drafts folder,
04760     // then mark the message read, since it must be an append to the 
04761     // fcc or templates folder.
04762     else if (mailCopyState)
04763       *aResult = mailCopyState->m_newMsgFlags;
04764   }
04765   return NS_OK;
04766 }
04767 
04768 NS_IMETHODIMP nsImapMailFolder::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
04769 {
04770   return NS_OK;
04771 }
04772 
04773 NS_IMETHODIMP nsImapMailFolder::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult aStatus)
04774 {
04775   return NS_OK;
04776 }
04777 
04778 NS_IMETHODIMP
04779 nsImapMailFolder::OnStartRunningUrl(nsIURI *aUrl)
04780 {
04781   NS_PRECONDITION(aUrl, "sanity check - need to be be running non-null url");
04782   nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUrl);
04783   if (mailUrl)
04784   {
04785     PRBool updatingFolder;
04786     mailUrl->GetUpdatingFolder(&updatingFolder);
04787     m_updatingFolder = updatingFolder;
04788   }
04789   m_urlRunning = PR_TRUE;
04790   return NS_OK;
04791 }
04792 
04793 NS_IMETHODIMP
04794 nsImapMailFolder::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
04795 {
04796   nsresult rv = NS_OK;
04797   PRBool endedOfflineDownload = PR_FALSE;
04798   m_urlRunning = PR_FALSE;
04799   m_updatingFolder = PR_FALSE;
04800   if (m_downloadingFolderForOfflineUse)
04801   {
04802     ReleaseSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this));
04803     m_downloadingFolderForOfflineUse = PR_FALSE;
04804     endedOfflineDownload = PR_TRUE;
04805     EndOfflineDownload();
04806   }
04807   nsCOMPtr<nsIMsgMailSession> session = 
04808            do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
04809   if (aUrl)
04810   {
04811     nsCOMPtr<nsIMsgWindow> msgWindow;
04812     nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUrl);
04813     nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aUrl);
04814     PRBool folderOpen = PR_FALSE;
04815     if (mailUrl)
04816       mailUrl->GetMsgWindow(getter_AddRefs(msgWindow));
04817     if (session)
04818       session->IsFolderOpenInWindow(this, &folderOpen);
04819 #ifdef DEBUG_bienvenu1
04820     nsXPIDLCString urlSpec;
04821     aUrl->GetSpec(getter_Copies(urlSpec));
04822    printf("stop running url %s\n", (const char *) urlSpec);
04823 #endif
04824 
04825    if (imapUrl)
04826    {
04827         DisplayStatusMsg(imapUrl, NS_LITERAL_STRING("").get());
04828         nsImapAction imapAction = nsIImapUrl::nsImapTest;
04829         imapUrl->GetImapAction(&imapAction);
04830         if (imapAction == nsIImapUrl::nsImapMsgFetch || imapAction == nsIImapUrl::nsImapMsgDownloadForOffline)
04831         {
04832           ReleaseSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this));
04833           SetNotifyDownloadedLines(PR_FALSE);
04834           if (!endedOfflineDownload)
04835             EndOfflineDownload();
04836         }
04837 
04838         switch(imapAction)
04839         {
04840         case nsIImapUrl::nsImapDeleteMsg:
04841         case nsIImapUrl::nsImapOnlineMove:
04842         case nsIImapUrl::nsImapOnlineCopy:
04843           if (NS_SUCCEEDED(aExitCode))
04844           {
04845               if (folderOpen)
04846                 UpdateFolder(msgWindow);
04847               else
04848                 UpdatePendingCounts();
04849           }
04850           if (m_copyState)
04851           {
04852             nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryInterface(m_copyState->m_srcSupport, &rv);
04853             if (m_copyState->m_isMove && !m_copyState->m_isCrossServerOp)
04854             {
04855               if (NS_SUCCEEDED(aExitCode))
04856               {
04857                 nsCOMPtr<nsIMsgDatabase> srcDB;
04858                 if (srcFolder)
04859                     rv = srcFolder->GetMsgDatabase(msgWindow,
04860                         getter_AddRefs(srcDB));
04861                 if (NS_SUCCEEDED(rv) && srcDB)
04862                 {
04863                   nsRefPtr<nsImapMoveCopyMsgTxn> msgTxn;
04864                   nsMsgKeyArray srcKeyArray;
04865                   if (m_copyState->m_allowUndo)
04866                   {
04867                      rv = m_copyState->m_undoMsgTxn->QueryInterface(NS_GET_IID(nsImapMoveCopyMsgTxn), getter_AddRefs(msgTxn)); 
04868                      if (msgTxn)
04869                        msgTxn->GetSrcKeyArray(srcKeyArray);
04870                   }
04871                   else
04872                   {
04873                      nsCAutoString messageIds;
04874                      rv = BuildIdsAndKeyArray(m_copyState->m_messages, messageIds, srcKeyArray);
04875                      NS_ENSURE_SUCCESS(rv,rv);
04876                   }
04877                  
04878                   if (!ShowDeletedMessages())
04879                     srcDB->DeleteMessages(&srcKeyArray, nsnull);  
04880                   else
04881                     MarkMessagesImapDeleted(&srcKeyArray, PR_TRUE, srcDB);
04882                 }
04883                 srcFolder->EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE/* dbBatching*/);
04884                 // even if we're showing deleted messages, 
04885                 // we still need to notify FE so it will show the imap deleted flag
04886                 srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
04887                 // is there a way to see that we think we have new msgs?
04888                 nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
04889                 if (NS_SUCCEEDED(rv))
04890                 {
04891                   PRBool showPreviewText;
04892                   prefBranch->GetBoolPref("mail.biff.alert.show_preview", &showPreviewText);
04893                   // if we're showing preview text, update ourselves if we got a new unread
04894                   // message copied so that we can download the new headers and have a chance
04895                   // to preview the msg bodies.
04896                   if (!folderOpen && showPreviewText && m_copyState->m_unreadCount > 0
04897                       && ! (mFlags & (MSG_FOLDER_FLAG_TRASH | MSG_FOLDER_FLAG_JUNK)))
04898                     UpdateFolder(msgWindow);
04899                 }
04900               }
04901               else
04902               {
04903                 srcFolder->EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE/* dbBatching*/);
04904                 srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);  
04905               }
04906                 
04907             }
04908             if (m_copyState->m_msgWindow && NS_SUCCEEDED(aExitCode)) //we should do this only if move/copy succeeds
04909             {
04910               nsCOMPtr<nsITransactionManager> txnMgr;
04911               m_copyState->m_msgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
04912               if (txnMgr)
04913               {
04914                 nsresult rv2 = txnMgr->DoTransaction(m_copyState->m_undoMsgTxn);
04915                 NS_ASSERTION(NS_SUCCEEDED(rv2), "doing transaction failed");
04916               }
04917             }
04918              (void) OnCopyCompleted(m_copyState->m_srcSupport, aExitCode);
04919           }
04920           // we're the dest folder of a move/copy - if we're not open in the ui,
04921           // then we should clear our nsMsgDatabase pointer. Otherwise, the db would
04922           // be open until the user selected it and then selected another folder.
04923           // but don't do this for the trash or inbox - we'll leave them open
04924           if (!folderOpen && ! (mFlags & (MSG_FOLDER_FLAG_TRASH | MSG_FOLDER_FLAG_INBOX)))
04925             SetMsgDatabase(nsnull);
04926           break;
04927         case nsIImapUrl::nsImapSubtractMsgFlags:
04928           {
04929           // this isn't really right - we'd like to know we were 
04930           // deleting a message to start with, but it probably
04931           // won't do any harm.
04932             imapMessageFlagsType flags = 0;
04933             imapUrl->GetMsgFlags(&flags);
04934             //we need to subtract the delete flag in db only in case when we show deleted msgs
04935             if (flags & kImapMsgDeletedFlag && ShowDeletedMessages())
04936             {
04937               nsCOMPtr<nsIMsgDatabase> db;
04938               rv = GetMsgDatabase(nsnull, getter_AddRefs(db));
04939               if (NS_SUCCEEDED(rv) && db)
04940               {
04941                 nsMsgKeyArray keyArray;
04942                 char *keyString;
04943                 imapUrl->CreateListOfMessageIdsString(&keyString);
04944                 if (keyString)
04945                 {
04946                   ParseUidString(keyString, keyArray);
04947                   MarkMessagesImapDeleted(&keyArray, PR_FALSE, db);
04948                   db->Commit(nsMsgDBCommitType::kLargeCommit);
04949                   nsCRT::free(keyString);
04950                 }
04951               }
04952             }
04953           }
04954           break;
04955         case nsIImapUrl::nsImapAddMsgFlags:
04956           {
04957             imapMessageFlagsType flags = 0;
04958             imapUrl->GetMsgFlags(&flags);
04959             if (flags & kImapMsgDeletedFlag)
04960             {
04961               // we need to delete headers from db only when we don't show deleted msgs
04962               if (!ShowDeletedMessages()) 
04963               {
04964                 nsCOMPtr<nsIMsgDatabase> db;
04965                 rv = GetMsgDatabase(nsnull, getter_AddRefs(db));
04966                 if (NS_SUCCEEDED(rv) && db)
04967                 {
04968                   nsMsgKeyArray keyArray;
04969                   char *keyString = nsnull;
04970                   imapUrl->CreateListOfMessageIdsString(&keyString);
04971                   if (keyString)
04972                   {
04973                     ParseUidString(keyString, keyArray);
04974                     db->DeleteMessages(&keyArray, nsnull);
04975                     db->SetSummaryValid(PR_TRUE);
04976                     db->Commit(nsMsgDBCommitType::kLargeCommit);
04977                     nsCRT::free(keyString);
04978                   }
04979                 }
04980               }
04981               // see bug #188051
04982               // only send the folder event only if we are deleting
04983               // (and not for other flag changes)
04984               NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
04985             }
04986           }
04987           break;
04988         case nsIImapUrl::nsImapAppendMsgFromFile:
04989         case nsIImapUrl::nsImapAppendDraftFromFile:
04990             if (m_copyState)
04991             {
04992               if (NS_SUCCEEDED(aExitCode))
04993               {
04994                 UpdatePendingCounts();
04995 
04996                 m_copyState->m_curIndex++;
04997                 if (m_copyState->m_curIndex >= m_copyState->m_totalCount)
04998                 {
04999                   if (folderOpen)
05000                   {
05001                     // This gives a way for the caller to get notified 
05002                     // when the UpdateFolder url is done.
05003                     nsCOMPtr <nsIUrlListener> saveUrlListener = m_urlListener;
05004                     if (m_copyState->m_listener)
05005                       m_urlListener = do_QueryInterface(m_copyState->m_listener);
05006 
05007                     UpdateFolder(msgWindow);
05008                     m_urlListener = saveUrlListener;
05009                   }
05010                   if (m_copyState->m_msgWindow && m_copyState->m_undoMsgTxn)
05011                   {
05012                     nsCOMPtr<nsITransactionManager> txnMgr;
05013                     m_copyState->m_msgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
05014                     if (txnMgr)
05015                       txnMgr->DoTransaction(m_copyState->m_undoMsgTxn);
05016                   }
05017                   (void) OnCopyCompleted(m_copyState->m_srcSupport, aExitCode);
05018                 }
05019               }
05020               else
05021                 //clear the copyState if copy has failed
05022                 (void) OnCopyCompleted(m_copyState->m_srcSupport, aExitCode);              
05023             }
05024             break;
05025         case nsIImapUrl::nsImapRenameFolder:
05026           if (NS_FAILED(aExitCode))
05027           {
05028             nsCOMPtr <nsIAtom> folderRenameAtom;
05029             folderRenameAtom = do_GetAtom("RenameCompleted");
05030             NotifyFolderEvent(folderRenameAtom);
05031           }
05032           break;
05033         case nsIImapUrl::nsImapDeleteAllMsgs:
05034             if (NS_SUCCEEDED(aExitCode))
05035             {
05036               if (folderOpen)
05037                 UpdateFolder(msgWindow);
05038               else
05039               {
05040                 ChangeNumPendingTotalMessages(-mNumPendingTotalMessages);
05041                 ChangeNumPendingUnread(-mNumPendingUnreadMessages);
05042                 m_numStatusUnseenMessages = 0;
05043               }
05044 
05045             }
05046             break;
05047         case nsIImapUrl::nsImapListFolder:
05048             // check if folder is now verified - if not,
05049             // we should remove it?
05050             if (NS_SUCCEEDED(aExitCode) && !m_verifiedAsOnlineFolder)
05051             {
05052               nsCOMPtr<nsIMsgFolder> parent;
05053               rv = GetParent(getter_AddRefs(parent));
05054 
05055               if (NS_SUCCEEDED(rv) && parent)
05056               {
05057                 nsCOMPtr<nsIMsgImapMailFolder> imapParent = do_QueryInterface(parent);
05058                 if (imapParent)
05059                   imapParent->RemoveSubFolder(this);
05060               }
05061             }
05062           break;
05063         case nsIImapUrl::nsImapRefreshFolderUrls:
05064           // we finished getting an admin url for the folder.
05065             if (!m_adminUrl.IsEmpty())
05066               FolderPrivileges(msgWindow);
05067             break;
05068         case nsIImapUrl::nsImapCreateFolder:
05069           if (NS_FAILED(aExitCode))  //if success notification already done
05070           {
05071             nsCOMPtr <nsIAtom> folderCreateAtom;
05072             folderCreateAtom = do_GetAtom("FolderCreateFailed");
05073             NotifyFolderEvent(folderCreateAtom);
05074           }
05075           break;
05076         case nsIImapUrl::nsImapSubscribe:
05077           if (NS_SUCCEEDED(aExitCode) && msgWindow)
05078           {
05079             nsXPIDLCString canonicalFolderName;
05080             imapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(canonicalFolderName));
05081             nsCOMPtr <nsIMsgFolder> rootFolder;
05082             nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
05083             if(NS_SUCCEEDED(rv) && rootFolder)
05084             {
05085               nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
05086               if (imapRoot)
05087               {
05088                 nsCOMPtr <nsIMsgImapMailFolder> foundFolder;
05089                 rv = imapRoot->FindOnlineSubFolder(canonicalFolderName, getter_AddRefs(foundFolder));
05090                 if (NS_SUCCEEDED(rv) && foundFolder)
05091                 {
05092                   nsXPIDLCString uri;
05093                   nsCOMPtr <nsIMsgFolder> msgFolder = do_QueryInterface(foundFolder);
05094                   if (msgFolder)
05095                   {
05096                     msgFolder->GetURI(getter_Copies(uri));
05097                     msgWindow->SelectFolder(uri.get());
05098                   }
05099                 }
05100               }
05101             }
05102           }
05103           break;
05104         default:
05105             break;
05106         }
05107     }
05108     // give base class a chance to send folder loaded notification...
05109     rv = nsMsgDBFolder::OnStopRunningUrl(aUrl, aExitCode);
05110     // query it for a mailnews interface for now....
05111     if (mailUrl)
05112       rv = mailUrl->UnRegisterListener(this);
05113 
05114   }
05115   SetGettingNewMessages(PR_FALSE); // if we're not running a url, we must not be getting new mail :-)
05116 
05117   if (m_urlListener)
05118   {
05119     m_urlListener->OnStopRunningUrl(aUrl, aExitCode);
05120     m_urlListener = nsnull;
05121   }
05122   return rv;
05123 }
05124 
05125 void nsImapMailFolder::UpdatePendingCounts()
05126 {
05127   if (m_copyState)
05128   {
05129     if (!m_copyState->m_isCrossServerOp)
05130       ChangeNumPendingTotalMessages(m_copyState->m_totalCount);
05131     else
05132       ChangeNumPendingTotalMessages(1);
05133 
05134     // count the moves that were unread
05135     int numUnread = m_copyState->m_unreadCount;
05136   
05137     if (numUnread)
05138     {
05139       m_numStatusUnseenMessages += numUnread; // adjust last status count by this delta.
05140       ChangeNumPendingUnread(numUnread);
05141     }
05142     SummaryChanged();
05143   }
05144 } 
05145 
05146 
05147 
05148     // nsIImapExtensionSink methods
05149 
05150 NS_IMETHODIMP
05151 nsImapMailFolder::ClearFolderRights()
05152 {
05153   SetFolderNeedsACLListed(PR_FALSE);
05154   delete m_folderACL;
05155   m_folderACL = new nsMsgIMAPFolderACL(this);
05156   return NS_OK;
05157 }
05158 
05159 NS_IMETHODIMP
05160 nsImapMailFolder::AddFolderRights(const char *userName, const char *rights)
05161 {
05162   SetFolderNeedsACLListed(PR_FALSE);
05163   GetFolderACL()->SetFolderRightsForUser(userName, rights);
05164   return NS_OK;
05165 }
05166 
05167 NS_IMETHODIMP
05168 nsImapMailFolder::RefreshFolderRights()
05169 {
05170   if (GetFolderACL()->GetIsFolderShared())
05171     SetFlag(MSG_FOLDER_FLAG_PERSONAL_SHARED);
05172   else
05173     ClearFlag(MSG_FOLDER_FLAG_PERSONAL_SHARED);
05174   return NS_OK;
05175 }
05176 
05177 NS_IMETHODIMP
05178 nsImapMailFolder::SetCopyResponseUid(const char* msgIdString,
05179                                      nsIImapUrl * aUrl)
05180 {   // CopyMessages() only
05181   nsresult rv = NS_OK;
05182   nsRefPtr<nsImapMoveCopyMsgTxn> msgTxn;
05183   nsCOMPtr<nsISupports> copyState;
05184   
05185   if (aUrl)
05186     aUrl->GetCopyState(getter_AddRefs(copyState));
05187 
05188   if (copyState)
05189   {
05190       nsCOMPtr<nsImapMailCopyState> mailCopyState =
05191           do_QueryInterface(copyState, &rv);
05192       if (NS_FAILED(rv)) return rv;
05193       if (mailCopyState->m_undoMsgTxn)
05194         rv = mailCopyState->m_undoMsgTxn->QueryInterface(NS_GET_IID(nsImapMoveCopyMsgTxn), getter_AddRefs(msgTxn)); 
05195   }
05196   if (msgTxn)
05197       msgTxn->SetCopyResponseUid(msgIdString);
05198   
05199   return NS_OK;
05200 }    
05201 
05202 NS_IMETHODIMP
05203 nsImapMailFolder::StartMessage(nsIMsgMailNewsUrl * aUrl)
05204 {
05205   nsCOMPtr<nsIImapUrl> imapUrl (do_QueryInterface(aUrl));
05206   nsCOMPtr<nsISupports> copyState;
05207   NS_ENSURE_TRUE(imapUrl, NS_ERROR_FAILURE);
05208   
05209   imapUrl->GetCopyState(getter_AddRefs(copyState));
05210   if (copyState)
05211   {
05212     nsCOMPtr <nsICopyMessageStreamListener> listener = do_QueryInterface(copyState);
05213     if (listener)
05214       listener->StartMessage();
05215   }
05216 
05217   return NS_OK;
05218 }
05219 
05220 NS_IMETHODIMP
05221 nsImapMailFolder::EndMessage(nsIMsgMailNewsUrl * aUrl, nsMsgKey uidOfMessage)
05222 {
05223   nsCOMPtr<nsIImapUrl> imapUrl (do_QueryInterface(aUrl));
05224   nsCOMPtr<nsISupports> copyState;
05225   NS_ENSURE_TRUE(imapUrl, NS_ERROR_FAILURE);
05226   
05227   imapUrl->GetCopyState(getter_AddRefs(copyState));
05228   if (copyState)
05229   {
05230     nsCOMPtr <nsICopyMessageStreamListener> listener = do_QueryInterface(copyState);
05231     if (listener)
05232       listener->EndMessage(uidOfMessage);
05233   }
05234 
05235   return NS_OK;
05236 }
05237 
05238 #define WHITESPACE " \015\012"     // token delimiter
05239 
05240 NS_IMETHODIMP
05241 nsImapMailFolder::NotifySearchHit(nsIMsgMailNewsUrl * aUrl, 
05242                                   const char* searchHitLine)
05243 {
05244   nsresult rv = GetDatabase(nsnull /* don't need msg window, that's more for local mbox parsing */);
05245   if (!mDatabase || NS_FAILED(rv))
05246     return rv;
05247   // expect search results in the form of "* SEARCH <hit> <hit> ..."
05248                 // expect search results in the form of "* SEARCH <hit> <hit> ..."
05249   char *tokenString = nsCRT::strdup(searchHitLine);
05250   if (tokenString)
05251   {
05252       char *currentPosition = PL_strcasestr(tokenString, "SEARCH");
05253       if (currentPosition)
05254       {
05255         currentPosition += strlen("SEARCH");
05256         char *newStr;
05257           
05258         PRBool shownUpdateAlert = PR_FALSE;
05259         char *hitUidToken = nsCRT::strtok(currentPosition, WHITESPACE, &newStr);
05260         while (hitUidToken)
05261         {
05262           long naturalLong; // %l is 64 bits on OSF1
05263           sscanf(hitUidToken, "%ld", &naturalLong);
05264           nsMsgKey hitUid = (nsMsgKey) naturalLong;
05265       
05266           nsCOMPtr <nsIMsgDBHdr> hitHeader;
05267           rv = mDatabase->GetMsgHdrForKey(hitUid, getter_AddRefs(hitHeader));
05268           if (NS_SUCCEEDED(rv) && hitHeader)
05269           {
05270             nsCOMPtr <nsIMsgSearchSession> searchSession;
05271             nsCOMPtr <nsIMsgSearchAdapter> searchAdapter;
05272             aUrl->GetSearchSession(getter_AddRefs(searchSession));
05273             if (searchSession)
05274             {
05275               searchSession->GetRunningAdapter(getter_AddRefs(searchAdapter));
05276               if (searchAdapter)
05277                 searchAdapter->AddResultElement(hitHeader);
05278             }
05279           }
05280           else if (!shownUpdateAlert)
05281           {
05282           }
05283         
05284           hitUidToken = nsCRT::strtok(newStr, WHITESPACE, &newStr);
05285         }
05286     }
05287 
05288     nsCRT::free(tokenString);
05289   }
05290   else
05291     return NS_ERROR_OUT_OF_MEMORY;
05292 
05293   return NS_OK;
05294 }
05295 
05296 
05297 NS_IMETHODIMP
05298 nsImapMailFolder::SetAppendMsgUid(nsMsgKey aKey,
05299                                   nsIImapUrl * aUrl)
05300 {
05301   nsresult rv = NS_OK;
05302   nsCOMPtr<nsISupports> copyState;
05303 
05304   if (aUrl)
05305     aUrl->GetCopyState(getter_AddRefs(copyState));
05306   if (copyState)
05307   {
05308     nsCOMPtr<nsImapMailCopyState> mailCopyState = do_QueryInterface(copyState, &rv);
05309     if (NS_FAILED(rv)) return rv;
05310 
05311     if (mailCopyState->m_undoMsgTxn) // CopyMessages()
05312     {
05313         nsRefPtr<nsImapMoveCopyMsgTxn> msgTxn;
05314         rv = mailCopyState->m_undoMsgTxn->QueryInterface(NS_GET_IID(nsImapMoveCopyMsgTxn), getter_AddRefs(msgTxn)); 
05315         if (NS_SUCCEEDED(rv))
05316           msgTxn->AddDstKey(aKey);
05317     }
05318     else if (mailCopyState->m_listener) // CopyFileMessage();
05319                                         // Draft/Template goes here
05320        mailCopyState->m_listener->SetMessageKey(aKey);
05321   }
05322   return NS_OK;
05323 }    
05324 
05325 NS_IMETHODIMP
05326 nsImapMailFolder::GetMessageId(nsIImapUrl * aUrl,
05327                                nsACString &messageId)
05328 {
05329   nsresult rv = NS_OK;
05330   nsCOMPtr<nsISupports> copyState;
05331 
05332   if (aUrl)
05333     aUrl->GetCopyState(getter_AddRefs(copyState));
05334   if (copyState)
05335   {
05336     nsCOMPtr<nsImapMailCopyState> mailCopyState =
05337         do_QueryInterface(copyState, &rv);
05338     if (NS_FAILED(rv)) return rv;
05339     if (mailCopyState->m_listener)
05340     {
05341       nsCAutoString tempMessageId;
05342         rv = mailCopyState->m_listener->GetMessageId(&tempMessageId);
05343         messageId.Assign(tempMessageId);
05344     }
05345   }
05346   if (NS_SUCCEEDED(rv) && messageId.Length() > 0)
05347   {
05348       if (messageId.First() == '<')
05349           messageId.Cut(0, 1);
05350       if (messageId.Last() == '>')
05351           messageId.SetLength(messageId.Length() -1);
05352   }  
05353   return rv;
05354 }
05355 
05356 
05357 NS_IMETHODIMP
05358 nsImapMailFolder::AddSearchResult(nsIImapProtocol* aProtocol, 
05359                                   const char* searchHitLine)
05360 {
05361     return NS_ERROR_FAILURE;
05362 }
05363 
05364 NS_IMETHODIMP
05365 nsImapMailFolder::HeaderFetchCompleted(nsIImapProtocol* aProtocol)
05366 {
05367   nsCOMPtr <nsIMsgWindow> msgWindow; // we might need this for the filter plugins.
05368   if (mDatabase)
05369     mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
05370   SetSizeOnDisk(mFolderSize); 
05371   PRInt32 numNewBiffMsgs = 0;
05372   if (m_performingBiff)
05373     GetNumNewMessages(PR_FALSE, &numNewBiffMsgs);
05374 
05375   PRBool pendingMoves = m_moveCoalescer && m_moveCoalescer->HasPendingMoves();
05376   PlaybackCoalescedOperations();
05377   if (aProtocol)
05378   {
05379     // check if we should download message bodies because it's the inbox and 
05380     // the server is specified as one where where we download msg bodies automatically.
05381     // Or if we autosyncing all offline folders.
05382     nsCOMPtr<nsIImapIncomingServer> imapServer;
05383     nsresult rv = GetImapIncomingServer(getter_AddRefs(imapServer));
05384 
05385     PRBool autoDownloadNewHeaders = PR_FALSE;
05386     PRBool autoSyncOfflineStores = PR_FALSE;
05387 
05388     if (imapServer)
05389       imapServer->GetAutoSyncOfflineStores(&autoSyncOfflineStores);
05390     if (autoSyncOfflineStores || mFlags & MSG_FOLDER_FLAG_INBOX)
05391     {
05392       if (imapServer && mFlags & MSG_FOLDER_FLAG_INBOX && !autoSyncOfflineStores)
05393         imapServer->GetDownloadBodiesOnGetNewMail(&autoDownloadNewHeaders);
05394       // this isn't quite right - we only want to download bodies for new headers
05395       // but we don't know what the new headers are. We could query the inbox db
05396       // for new messages, if the above filter playback actually moves the filtered
05397       // messages before we get to this code.
05398       if (autoDownloadNewHeaders || autoSyncOfflineStores)
05399       {
05400           // acquire semaphore for offline store. If it fails, we won't download for offline use.
05401         if (NS_SUCCEEDED(AcquireSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this))))
05402           m_downloadingFolderForOfflineUse = PR_TRUE;
05403       }
05404     }
05405 
05406     if (m_downloadingFolderForOfflineUse)
05407     {
05408       nsMsgKeyArray keysToDownload;
05409       GetBodysToDownload(&keysToDownload);
05410       if (keysToDownload.GetSize() > 0)
05411         SetNotifyDownloadedLines(PR_TRUE);
05412 
05413       aProtocol->NotifyBodysToDownload(keysToDownload.GetArray(), keysToDownload.GetSize());
05414     }
05415     else
05416       aProtocol->NotifyBodysToDownload(nsnull, 0/*keysToFetch.GetSize() */);
05417 
05418     nsCOMPtr <nsIURI> runningUri;
05419     aProtocol->GetRunningUrl(getter_AddRefs(runningUri));
05420     if (runningUri)
05421     {
05422       nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(runningUri);
05423       if (mailnewsUrl)
05424         mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
05425     }
05426   }
05427 
05428   PRBool filtersRun;
05429   CallFilterPlugins(msgWindow, &filtersRun);
05430   if (!filtersRun && m_performingBiff && mDatabase && numNewBiffMsgs > 0 && 
05431       (!pendingMoves || !ShowPreviewText()))
05432   {
05433     if (!pendingMoves)
05434       SetHasNewMessages(PR_TRUE);
05435 
05436     // If we are performing biff for this folder, tell the
05437     // stand-alone biff about the new high water mark
05438     // We must ensure that the server knows that we are performing biff.
05439     // Otherwise the stand-alone biff won't fire.
05440     nsCOMPtr<nsIMsgIncomingServer> server;
05441     if (NS_SUCCEEDED(GetServer(getter_AddRefs(server))) && server)
05442       server->SetPerformingBiff(PR_TRUE);
05443     
05444     SetBiffState(nsIMsgFolder::nsMsgBiffState_NewMail);
05445     if (server)
05446       server->SetPerformingBiff(PR_FALSE);
05447     m_performingBiff = PR_FALSE;
05448   }
05449 
05450   if (m_filterList)
05451     (void)m_filterList->FlushLogIfNecessary();
05452  
05453   return NS_OK;
05454 }
05455 
05456 NS_IMETHODIMP
05457 nsImapMailFolder::SetBiffStateAndUpdate(nsMsgBiffState biffState)
05458 {
05459   SetBiffState(biffState);
05460   return NS_OK;
05461 }
05462 
05463 NS_IMETHODIMP
05464 nsImapMailFolder::GetUidValidity(PRInt32 *uidValidity)
05465 {
05466   NS_ENSURE_ARG(uidValidity);
05467   if (m_uidValidity == kUidUnknown)
05468   {
05469     nsCOMPtr<nsIMsgDatabase> db; 
05470     nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
05471     (void) GetDBFolderInfoAndDB(getter_AddRefs(dbFolderInfo), getter_AddRefs(db));
05472     if (db)
05473       db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
05474     
05475     if (dbFolderInfo)
05476       dbFolderInfo->GetImapUidValidity((PRInt32 *) &m_uidValidity);
05477   }
05478   *uidValidity = m_uidValidity;
05479   return NS_OK;
05480 }
05481 
05482 NS_IMETHODIMP
05483 nsImapMailFolder::SetUidValidity(PRInt32 uidValidity)
05484 {
05485   m_uidValidity = uidValidity;
05486   return NS_OK;
05487 }
05488 
05489 NS_IMETHODIMP
05490 nsImapMailFolder::FillInFolderProps(nsIMsgImapFolderProps *aFolderProps)
05491 {
05492   NS_ENSURE_ARG(aFolderProps);
05493   PRUint32 folderTypeStringID;
05494   PRUint32 folderTypeDescStringID = 0;
05495   PRUint32 folderQuotaStatusStringID;
05496   nsXPIDLString folderType;
05497   nsXPIDLString folderTypeDesc;
05498   nsXPIDLString folderQuotaStatusDesc;
05499   nsCOMPtr<nsIStringBundle> bundle;
05500   nsresult rv = IMAPGetStringBundle(getter_AddRefs(bundle));
05501   NS_ENSURE_SUCCESS(rv, rv);
05502 
05503   // get the host session list and get server capabilities.
05504   PRUint32 capability = kCapabilityUndefined;
05505 
05506   nsCOMPtr<nsIImapHostSessionList> hostSession = do_GetService(kCImapHostSessionList, &rv);
05507   // if for some bizarre reason this fails, we'll still fall through to the normal sharing code
05508   if (NS_SUCCEEDED(rv) && hostSession)
05509   {
05510     nsXPIDLCString serverKey;
05511     GetServerKey(getter_Copies(serverKey));
05512     hostSession->GetCapabilityForHost(serverKey, capability);
05513 
05514     // Figure out what to display in the Quota tab of the folder properties.
05515     // Does the server support quotas?
05516     if(capability & kQuotaCapability)
05517     {
05518       // Have we asked the server for quota information?
05519       if(m_folderQuotaCommandIssued)
05520       {
05521         // Has the server replied with storage quota info?
05522         if(m_folderQuotaDataIsValid)
05523         {
05524           // If so, set quota data
05525           folderQuotaStatusStringID = 0;
05526           aFolderProps->SetQuotaData(m_folderQuotaRoot, m_folderQuotaUsedKB, m_folderQuotaMaxKB);
05527         }
05528         else
05529         {
05530           // If not, there is no storage quota set on this folder
05531           folderQuotaStatusStringID = IMAP_QUOTA_STATUS_NOQUOTA;
05532         }
05533       }
05534       else
05535       {
05536         // The folder is not open, so no quota information is available
05537         folderQuotaStatusStringID = IMAP_QUOTA_STATUS_FOLDERNOTOPEN;
05538       }
05539     }
05540     else
05541     {
05542       // Either the server doesn't support quotas, or we don't know if it does
05543       // (e.g., because we don't have a connection yet). If the latter, we fall back
05544       // to saying that no information is available because the folder is not open.
05545       folderQuotaStatusStringID = (capability == kCapabilityUndefined) ?
05546         IMAP_QUOTA_STATUS_FOLDERNOTOPEN : IMAP_QUOTA_STATUS_NOTSUPPORTED;
05547     }
05548 
05549     if(folderQuotaStatusStringID == 0)
05550     {
05551       // Display quota data
05552       aFolderProps->ShowQuotaData(PR_TRUE);
05553     }
05554     else
05555     {
05556       // Hide quota data and show reason why it is not available
05557       aFolderProps->ShowQuotaData(PR_FALSE);
05558 
05559       rv = IMAPGetStringByID(folderQuotaStatusStringID, getter_Copies(folderQuotaStatusDesc));
05560       if (NS_SUCCEEDED(rv))
05561         aFolderProps->SetQuotaStatus(folderQuotaStatusDesc);
05562     }
05563 
05564     // See if the server supports ACL.
05565     // If not, just set the folder description to a string that says
05566     // the server doesn't support sharing, and return.
05567     if (! (capability & kACLCapability))
05568     {
05569       rv = IMAPGetStringByID(IMAP_SERVER_DOESNT_SUPPORT_ACL, getter_Copies(folderTypeDesc));
05570       if (NS_SUCCEEDED(rv))
05571         aFolderProps->SetFolderTypeDescription(folderTypeDesc);
05572       aFolderProps->ServerDoesntSupportACL();
05573       return NS_OK;
05574     }
05575   }
05576   if (mFlags & MSG_FOLDER_FLAG_IMAP_PUBLIC)
05577   {
05578     folderTypeStringID = IMAP_PUBLIC_FOLDER_TYPE_NAME;
05579     folderTypeDescStringID = IMAP_PUBLIC_FOLDER_TYPE_DESCRIPTION;
05580   }
05581   else if (mFlags & MSG_FOLDER_FLAG_IMAP_OTHER_USER)
05582   {
05583     folderTypeStringID = IMAP_OTHER_USERS_FOLDER_TYPE_NAME;
05584     nsXPIDLCString owner;
05585     nsXPIDLString uniOwner;
05586     GetFolderOwnerUserName(getter_Copies(owner));
05587     if (owner.IsEmpty())
05588     {
05589       rv = IMAPGetStringByID(folderTypeStringID, getter_Copies(uniOwner));
05590       // Another user's folder, for which we couldn't find an owner name
05591       NS_ASSERTION(PR_FALSE, "couldn't get owner name for other user's folder");
05592     }
05593     else
05594     {
05595       // is this right? It doesn't leak, does it?
05596       CopyASCIItoUTF16(owner, uniOwner);
05597     }
05598     const PRUnichar *params[] = { uniOwner.get() };
05599     rv = bundle->FormatStringFromID(IMAP_OTHER_USERS_FOLDER_TYPE_DESCRIPTION, params, 1, getter_Copies(folderTypeDesc));
05600   }
05601 
05602   else if (GetFolderACL()->GetIsFolderShared())
05603   {
05604     folderTypeStringID = IMAP_PERSONAL_SHARED_FOLDER_TYPE_NAME;
05605     folderTypeDescStringID = IMAP_PERSONAL_SHARED_FOLDER_TYPE_DESCRIPTION;
05606   }
05607   else
05608   {
05609     folderTypeStringID = IMAP_PERSONAL_SHARED_FOLDER_TYPE_NAME;
05610     folderTypeDescStringID = IMAP_PERSONAL_FOLDER_TYPE_DESCRIPTION;
05611   }
05612 
05613   rv = IMAPGetStringByID(folderTypeStringID, getter_Copies(folderType));
05614   if (NS_SUCCEEDED(rv))
05615     aFolderProps->SetFolderType(folderType);
05616 
05617   if (folderTypeDesc.IsEmpty() && folderTypeDescStringID != 0)
05618     rv = IMAPGetStringByID(folderTypeDescStringID, getter_Copies(folderTypeDesc));
05619   if (!folderTypeDesc.IsEmpty())
05620     aFolderProps->SetFolderTypeDescription(folderTypeDesc.get());
05621 
05622   nsXPIDLString rightsString;
05623   rv = CreateACLRightsStringForFolder(getter_Copies(rightsString));
05624   if (NS_SUCCEEDED(rv))
05625     aFolderProps->SetFolderPermissions(rightsString.get());
05626 
05627   return NS_OK;
05628 }
05629 
05630 NS_IMETHODIMP nsImapMailFolder::SetAclFlags(PRUint32 aclFlags)
05631 {
05632   nsresult rv = NS_OK;
05633   if (m_aclFlags != aclFlags)
05634   {
05635     nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
05636     PRBool dbWasOpen = (mDatabase != nsnull);
05637     rv = GetDatabase(nsnull);
05638 
05639     m_aclFlags = aclFlags;
05640     if (mDatabase)
05641     {
05642       rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
05643       if (NS_SUCCEEDED(rv) && dbFolderInfo)
05644         dbFolderInfo->SetUint32Property("aclFlags", aclFlags);
05645       // if setting the acl flags caused us to open the db, release the ref
05646       // because on startup, we might get acl on all folders,which will
05647       // leave a lot of db's open.
05648       if (!dbWasOpen)
05649       {
05650         mDatabase->Close(PR_TRUE /* commit changes */);
05651         mDatabase = nsnull;
05652       }
05653     }
05654   }
05655   return rv;
05656 }
05657 
05658 NS_IMETHODIMP nsImapMailFolder::GetAclFlags(PRUint32 *aclFlags)
05659 {
05660   NS_ENSURE_ARG_POINTER(aclFlags);
05661 
05662   nsresult rv = NS_OK;
05663 
05664   ReadDBFolderInfo(PR_FALSE); // update cache first.
05665   if (m_aclFlags == -1) // -1 means invalid value, so get it from db.
05666   {
05667     nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
05668     PRBool dbWasOpen = (mDatabase != nsnull);
05669     rv = GetDatabase(nsnull);
05670 
05671     if (mDatabase)
05672     {
05673       rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
05674       if (NS_SUCCEEDED(rv) && dbFolderInfo)
05675       {
05676         rv = dbFolderInfo->GetUint32Property("aclFlags", 0, aclFlags);
05677         m_aclFlags = *aclFlags;
05678       }
05679       // if getting the acl flags caused us to open the db, release the ref
05680       // because on startup, we might get acl on all folders,which will
05681       // leave a lot of db's open.
05682       if (!dbWasOpen)
05683       {
05684         mDatabase->Close(PR_TRUE /* commit changes */);
05685         mDatabase = nsnull;
05686       }
05687     }
05688   }
05689   else
05690     *aclFlags = m_aclFlags;
05691   return rv;
05692 }
05693 
05694 
05695 nsresult nsImapMailFolder::SetSupportedUserFlags(PRUint32 userFlags)
05696 {
05697   nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
05698   nsresult rv = GetDatabase(nsnull);
05699 
05700   m_supportedUserFlags = userFlags;
05701   if (mDatabase)
05702   {
05703     rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
05704     if (NS_SUCCEEDED(rv) && dbFolderInfo)
05705       dbFolderInfo->SetUint32Property("imapFlags", userFlags);
05706   }
05707 
05708 
05709   return rv;
05710 }
05711 
05712 nsresult nsImapMailFolder::GetSupportedUserFlags(PRUint32 *userFlags)
05713 {
05714   NS_ENSURE_ARG_POINTER(userFlags);
05715 
05716   nsresult rv = NS_OK;
05717 
05718   ReadDBFolderInfo(PR_FALSE); // update cache first.
05719   if (m_supportedUserFlags == 0) // 0 means invalid value, so get it from db.
05720   {
05721     nsCOMPtr<nsIDBFolderInfo> dbFolderInfo;
05722     rv = GetDatabase(nsnull);
05723 
05724     if (mDatabase)
05725     {
05726       rv = mDatabase->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
05727       if (NS_SUCCEEDED(rv) && dbFolderInfo)
05728       {
05729         rv = dbFolderInfo->GetUint32Property("imapFlags", 0, userFlags);
05730         m_supportedUserFlags = *userFlags;
05731       }
05732     }
05733   }
05734   else
05735     *userFlags = m_supportedUserFlags;
05736   return rv;
05737 }
05738 
05739 NS_IMETHODIMP nsImapMailFolder::GetCanIOpenThisFolder(PRBool *aBool)
05740 {
05741   NS_ENSURE_ARG_POINTER(aBool);
05742   PRBool noSelect;
05743   GetFlag(MSG_FOLDER_FLAG_IMAP_NOSELECT, &noSelect);
05744   *aBool = (noSelect) ? PR_FALSE : GetFolderACL()->GetCanIReadFolder();
05745   return NS_OK;
05746 }
05747 
05749 
05750 // This string is defined in the ACL RFC to be "anyone"
05751 #define IMAP_ACL_ANYONE_STRING "anyone"
05752 
05753 /* static */PRBool nsMsgIMAPFolderACL::FreeHashRights(nsHashKey *aKey, void *aData,
05754                                         void *closure)
05755 {
05756   PR_FREEIF(aData);
05757   return PR_TRUE;
05758 }
05759 
05760 nsMsgIMAPFolderACL::nsMsgIMAPFolderACL(nsImapMailFolder *folder)
05761 {
05762   NS_ASSERTION(folder, "need folder");
05763   m_folder = folder;
05764   m_rightsHash = new nsHashtable(24);
05765   m_aclCount = 0;
05766   BuildInitialACLFromCache();
05767 }
05768 
05769 nsMsgIMAPFolderACL::~nsMsgIMAPFolderACL()
05770 {
05771   m_rightsHash->Reset(FreeHashRights, nsnull);
05772   delete m_rightsHash;
05773 }
05774 
05775 // We cache most of our own rights in the MSG_FOLDER_PREF_* flags
05776 void nsMsgIMAPFolderACL::BuildInitialACLFromCache()
05777 {
05778   nsCAutoString myrights;
05779   
05780   PRUint32 startingFlags;
05781   m_folder->GetAclFlags(&startingFlags);
05782   
05783   if (startingFlags & IMAP_ACL_READ_FLAG)
05784     myrights += "r";
05785   if (startingFlags & IMAP_ACL_STORE_SEEN_FLAG)
05786     myrights += "s";
05787   if (startingFlags & IMAP_ACL_WRITE_FLAG)
05788     myrights += "w";
05789   if (startingFlags & IMAP_ACL_INSERT_FLAG)
05790     myrights += "i";
05791   if (startingFlags & IMAP_ACL_POST_FLAG)
05792     myrights += "p";
05793   if (startingFlags & IMAP_ACL_CREATE_SUBFOLDER_FLAG)
05794     myrights +="c";
05795   if (startingFlags & IMAP_ACL_DELETE_FLAG)
05796     myrights += "dt";
05797   if (startingFlags & IMAP_ACL_ADMINISTER_FLAG)
05798     myrights += "a";
05799   
05800   if (!myrights.IsEmpty())
05801     SetFolderRightsForUser(nsnull, myrights.get());
05802 }
05803 
05804 void nsMsgIMAPFolderACL::UpdateACLCache()
05805 {
05806   PRUint32 startingFlags = 0;
05807   m_folder->GetAclFlags(&startingFlags);
05808   
05809   if (GetCanIReadFolder())
05810     startingFlags |= IMAP_ACL_READ_FLAG;
05811   else
05812     startingFlags &= ~IMAP_ACL_READ_FLAG;
05813   
05814   if (GetCanIStoreSeenInFolder())
05815     startingFlags |= IMAP_ACL_STORE_SEEN_FLAG;
05816   else
05817     startingFlags &= ~IMAP_ACL_STORE_SEEN_FLAG;
05818   
05819   if (GetCanIWriteFolder())
05820     startingFlags |= IMAP_ACL_WRITE_FLAG;
05821   else
05822     startingFlags &= ~IMAP_ACL_WRITE_FLAG;
05823   
05824   if (GetCanIInsertInFolder())
05825     startingFlags |= IMAP_ACL_INSERT_FLAG;
05826   else
05827     startingFlags &= ~IMAP_ACL_INSERT_FLAG;
05828   
05829   if (GetCanIPostToFolder())
05830     startingFlags |= IMAP_ACL_POST_FLAG;
05831   else
05832     startingFlags &= ~IMAP_ACL_POST_FLAG;
05833   
05834   if (GetCanICreateSubfolder())
05835     startingFlags |= IMAP_ACL_CREATE_SUBFOLDER_FLAG;
05836   else
05837     startingFlags &= ~IMAP_ACL_CREATE_SUBFOLDER_FLAG;
05838   
05839   if (GetCanIDeleteInFolder())
05840     startingFlags |= IMAP_ACL_DELETE_FLAG;
05841   else
05842     startingFlags &= ~IMAP_ACL_DELETE_FLAG;
05843   
05844   if (GetCanIAdministerFolder())
05845     startingFlags |= IMAP_ACL_ADMINISTER_FLAG;
05846   else
05847     startingFlags &= ~IMAP_ACL_ADMINISTER_FLAG;
05848   
05849   m_folder->SetAclFlags(startingFlags);
05850 }
05851 
05852 PRBool nsMsgIMAPFolderACL::SetFolderRightsForUser(const char *userName, const char *rights)
05853 {
05854   PRBool ret = PR_FALSE;
05855   nsXPIDLCString myUserName;
05856   nsCOMPtr <nsIMsgIncomingServer> server;
05857 
05858   nsresult rv = m_folder->GetServer(getter_AddRefs(server));
05859   NS_ASSERTION(NS_SUCCEEDED(rv), "error getting server");
05860   if (NS_FAILED(rv)) 
05861     return PR_FALSE;
05862   // we need the real user name to match with what the imap server returns
05863   // in the acl response.
05864   server->GetRealUsername(getter_Copies(myUserName));
05865 
05866   nsCAutoString ourUserName;
05867   
05868   if (!userName)
05869     ourUserName.Assign(myUserName);
05870   else
05871     ourUserName.Assign(userName);
05872 
05873   if(ourUserName.IsEmpty())
05874     return ret;
05875 
05876   ToLowerCase(ourUserName);
05877   char *rightsWeOwn = PL_strdup(rights);
05878   nsCStringKey hashKey(ourUserName);
05879   if (rightsWeOwn)
05880   {
05881     char *oldValue = (char *) m_rightsHash->Get(&hashKey);
05882     if (oldValue)
05883     {
05884       PR_Free(oldValue);
05885       m_rightsHash->Remove(&hashKey);
05886       m_aclCount--;
05887       NS_ASSERTION(m_aclCount >= 0, "acl count can't go negative");
05888     }
05889     m_aclCount++;
05890     ret = (m_rightsHash->Put(&hashKey, rightsWeOwn) == 0);
05891   }
05892   
05893   if (myUserName.Equals(ourUserName) || ourUserName.EqualsLiteral(IMAP_ACL_ANYONE_STRING))
05894   {
05895     // if this is setting an ACL for me, cache it in the folder pref flags
05896     UpdateACLCache();
05897   }
05898   
05899   return ret;
05900 }
05901 
05902 const char *nsMsgIMAPFolderACL::GetRightsStringForUser(const char *inUserName)
05903 {
05904   nsXPIDLCString userName;
05905   userName.Assign(inUserName);
05906   if (userName.IsEmpty())
05907   {
05908     nsCOMPtr <nsIMsgIncomingServer> server;
05909 
05910     nsresult rv = m_folder->GetServer(getter_AddRefs(server));
05911     NS_ASSERTION(NS_SUCCEEDED(rv), "error getting server");
05912     if (NS_FAILED(rv)) return nsnull;
05913     // we need the real user name to match with what the imap server returns
05914     // in the acl response.
05915     server->GetRealUsername(getter_Copies(userName));
05916   }
05917   ToLowerCase(userName);
05918   nsCStringKey userKey(userName.get());
05919   
05920   return (const char *)m_rightsHash->Get(&userKey);
05921 }
05922 
05923 // First looks for individual user;  then looks for 'anyone' if the user isn't found.
05924 // Returns defaultIfNotFound, if neither are found.
05925 PRBool nsMsgIMAPFolderACL::GetFlagSetInRightsForUser(const char *userName, char flag, PRBool defaultIfNotFound)
05926 {
05927   const char *flags = GetRightsStringForUser(userName);
05928   if (!flags)
05929   {
05930     const char *anyoneFlags = GetRightsStringForUser(IMAP_ACL_ANYONE_STRING);
05931     if (!anyoneFlags)
05932       return defaultIfNotFound;
05933     else
05934       return (strchr(anyoneFlags, flag) != nsnull);
05935   }
05936   else
05937     return (strchr(flags, flag) != nsnull);
05938 }
05939 
05940 PRBool nsMsgIMAPFolderACL::GetCanUserLookupFolder(const char *userName)
05941 {
05942   return GetFlagSetInRightsForUser(userName, 'l', PR_FALSE);
05943 }
05944 
05945 PRBool nsMsgIMAPFolderACL::GetCanUserReadFolder(const char *userName)
05946 {
05947   return GetFlagSetInRightsForUser(userName, 'r', PR_FALSE);
05948 }
05949 
05950 PRBool nsMsgIMAPFolderACL::GetCanUserStoreSeenInFolder(const char *userName)
05951 {
05952   return GetFlagSetInRightsForUser(userName, 's', PR_FALSE);
05953 }
05954 
05955 PRBool nsMsgIMAPFolderACL::GetCanUserWriteFolder(const char *userName)
05956 {
05957   return GetFlagSetInRightsForUser(userName, 'w', PR_FALSE);
05958 }
05959 
05960 PRBool nsMsgIMAPFolderACL::GetCanUserInsertInFolder(const char *userName)
05961 {
05962   return GetFlagSetInRightsForUser(userName, 'i', PR_FALSE);
05963 }
05964 
05965 PRBool nsMsgIMAPFolderACL::GetCanUserPostToFolder(const char *userName)
05966 {
05967   return GetFlagSetInRightsForUser(userName, 'p', PR_FALSE);
05968 }
05969 
05970 PRBool nsMsgIMAPFolderACL::GetCanUserCreateSubfolder(const char *userName)
05971 {
05972   return GetFlagSetInRightsForUser(userName, 'c', PR_FALSE);
05973 }
05974 
05975 PRBool nsMsgIMAPFolderACL::GetCanUserDeleteInFolder(const char *userName)
05976 {
05977   return GetFlagSetInRightsForUser(userName, 'd', PR_FALSE)
05978     || GetFlagSetInRightsForUser(userName, 't', PR_FALSE);
05979 }
05980 
05981 PRBool nsMsgIMAPFolderACL::GetCanUserAdministerFolder(const char *userName)
05982 {
05983   return GetFlagSetInRightsForUser(userName, 'a', PR_FALSE);
05984 }
05985 
05986 PRBool nsMsgIMAPFolderACL::GetCanILookupFolder()
05987 {
05988   return GetFlagSetInRightsForUser(nsnull, 'l', PR_TRUE);
05989 }
05990 
05991 PRBool nsMsgIMAPFolderACL::GetCanIReadFolder()
05992 {
05993   return GetFlagSetInRightsForUser(nsnull, 'r', PR_TRUE);
05994 }
05995 
05996 PRBool nsMsgIMAPFolderACL::GetCanIStoreSeenInFolder()
05997 {
05998   return GetFlagSetInRightsForUser(nsnull, 's', PR_TRUE);
05999 }
06000 
06001 PRBool nsMsgIMAPFolderACL::GetCanIWriteFolder()
06002 {
06003   return GetFlagSetInRightsForUser(nsnull, 'w', PR_TRUE);
06004 }
06005 
06006 PRBool nsMsgIMAPFolderACL::GetCanIInsertInFolder()
06007 {
06008   return GetFlagSetInRightsForUser(nsnull, 'i', PR_TRUE);
06009 }
06010 
06011 PRBool nsMsgIMAPFolderACL::GetCanIPostToFolder()
06012 {
06013   return GetFlagSetInRightsForUser(nsnull, 'p', PR_TRUE);
06014 }
06015 
06016 PRBool nsMsgIMAPFolderACL::GetCanICreateSubfolder()
06017 {
06018   return GetFlagSetInRightsForUser(nsnull, 'c', PR_TRUE);
06019 }
06020 
06021 PRBool nsMsgIMAPFolderACL::GetCanIDeleteInFolder()
06022 {
06023   return GetFlagSetInRightsForUser(nsnull, 'd', PR_TRUE) ||
06024     GetFlagSetInRightsForUser(nsnull, 't', PR_TRUE);
06025 }
06026 
06027 PRBool nsMsgIMAPFolderACL::GetCanIAdministerFolder()
06028 {
06029   return GetFlagSetInRightsForUser(nsnull, 'a', PR_TRUE);
06030 }
06031 
06032 // We use this to see if the ACLs think a folder is shared or not.
06033 // We will define "Shared" in 5.0 to mean:
06034 // At least one user other than the currently authenticated user has at least one
06035 // explicitly-listed ACL right on that folder.
06036 PRBool nsMsgIMAPFolderACL::GetIsFolderShared()
06037 {
06038   // If we have more than one ACL count for this folder, which means that someone
06039   // other than ourself has rights on it, then it is "shared."
06040   if (m_aclCount > 1)
06041     return PR_TRUE;
06042   
06043   // Or, if "anyone" has rights to it, it is shared.
06044   nsCStringKey hashKey(IMAP_ACL_ANYONE_STRING);
06045   const char *anyonesRights = (const char *)m_rightsHash->Get(&hashKey);
06046   
06047   return (anyonesRights != nsnull);
06048 }
06049 
06050 PRBool nsMsgIMAPFolderACL::GetDoIHaveFullRightsForFolder()
06051 {
06052   return (GetCanIReadFolder() &&
06053     GetCanIWriteFolder() &&
06054     GetCanIInsertInFolder() &&
06055     GetCanIAdministerFolder() &&
06056     GetCanICreateSubfolder() &&
06057     GetCanIDeleteInFolder() &&
06058     GetCanILookupFolder() &&
06059     GetCanIStoreSeenInFolder() &&
06060     GetCanIPostToFolder());
06061 }
06062 
06063 // Returns a newly allocated string describing these rights
06064 nsresult nsMsgIMAPFolderACL::CreateACLRightsString(PRUnichar **rightsString)
06065 {
06066   nsAutoString rights;
06067   nsXPIDLString curRight;
06068   nsCOMPtr<nsIStringBundle> bundle;
06069   nsresult rv = IMAPGetStringBundle(getter_AddRefs(bundle));
06070   NS_ENSURE_SUCCESS(rv, rv);
06071 
06072   if (GetDoIHaveFullRightsForFolder())
06073   {
06074     return bundle->GetStringFromID(IMAP_ACL_FULL_RIGHTS, rightsString);
06075   }
06076   else
06077   {
06078     if (GetCanIReadFolder())
06079     {
06080       bundle->GetStringFromID(IMAP_ACL_READ_RIGHT, getter_Copies(curRight));
06081       rights.Append(curRight);
06082     }
06083     if (GetCanIWriteFolder())
06084     {
06085       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06086       bundle->GetStringFromID(IMAP_ACL_WRITE_RIGHT, getter_Copies(curRight));
06087       rights.Append(curRight);
06088     }
06089     if (GetCanIInsertInFolder())
06090     {
06091       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06092       bundle->GetStringFromID(IMAP_ACL_INSERT_RIGHT, getter_Copies(curRight));
06093       rights.Append(curRight);
06094     }
06095     if (GetCanILookupFolder())
06096     {
06097       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06098       bundle->GetStringFromID(IMAP_ACL_LOOKUP_RIGHT, getter_Copies(curRight));
06099       rights.Append(curRight);
06100     }
06101     if (GetCanIStoreSeenInFolder())
06102     {
06103       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06104       bundle->GetStringFromID(IMAP_ACL_SEEN_RIGHT, getter_Copies(curRight));
06105       rights.Append(curRight);
06106     }
06107     if (GetCanIDeleteInFolder())
06108     {
06109       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06110       bundle->GetStringFromID(IMAP_ACL_DELETE_RIGHT, getter_Copies(curRight));
06111       rights.Append(curRight);
06112     }
06113     if (GetCanICreateSubfolder())
06114     {
06115       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06116       bundle->GetStringFromID(IMAP_ACL_CREATE_RIGHT, getter_Copies(curRight));
06117       rights.Append(curRight);
06118     }
06119     if (GetCanIPostToFolder())
06120     {
06121       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06122       bundle->GetStringFromID(IMAP_ACL_POST_RIGHT, getter_Copies(curRight));
06123       rights.Append(curRight);
06124     }
06125     if (GetCanIAdministerFolder())
06126     {
06127       if (!rights.IsEmpty()) rights.AppendLiteral(", ");
06128       bundle->GetStringFromID(IMAP_ACL_ADMINISTER_RIGHT, getter_Copies(curRight));
06129       rights.Append(curRight);
06130     }
06131   }
06132   *rightsString = ToNewUnicode(rights);
06133   return rv;
06134 }
06135 
06136 NS_IMETHODIMP nsImapMailFolder::GetPath(nsIFileSpec ** aPathName)
06137 {
06138   nsresult rv;
06139   if (! m_pathName) 
06140   {
06141     m_pathName = new nsNativeFileSpec("");
06142     if (! m_pathName)
06143        return NS_ERROR_OUT_OF_MEMORY;
06144 
06145     rv = nsImapURI2Path(kImapRootURI, mURI.get(), *m_pathName);
06146     //    printf("constructing path %s\n", (const char *) *m_pathName);
06147     if (NS_FAILED(rv)) return rv;
06148   }
06149   rv = NS_NewFileSpecWithSpec(*m_pathName, aPathName);
06150   return NS_OK;
06151 }
06152 
06153 
06154 NS_IMETHODIMP nsImapMailFolder::SetPath(nsIFileSpec * aPathName)                
06155 {                                                                               
06156   nsMsgDBFolder::SetPath(aPathName);   // call base class so mPath will get set too
06157   if (!aPathName)
06158      return NS_ERROR_NULL_POINTER;
06159 
06160   // not sure why imap has m_pathName and doesn't just use mPath.
06161   if (!m_pathName)
06162   {
06163     m_pathName = new nsFileSpec("");
06164     if (! m_pathName)
06165       return NS_ERROR_OUT_OF_MEMORY;
06166   }
06167   return aPathName->GetFileSpec(m_pathName);                                  
06168 }                                                                               
06169                                                                                  
06170 
06171 nsresult nsImapMailFolder::DisplayStatusMsg(nsIImapUrl *aImapUrl, const PRUnichar *msg)
06172 {
06173   nsCOMPtr<nsIImapMockChannel> mockChannel;
06174   aImapUrl->GetMockChannel(getter_AddRefs(mockChannel));
06175   if (mockChannel)
06176   {
06177     nsCOMPtr<nsIProgressEventSink> progressSink;
06178     mockChannel->GetProgressEventSink(getter_AddRefs(progressSink));
06179     if (progressSink)
06180     {
06181         nsCOMPtr<nsIRequest> request = do_QueryInterface(mockChannel);
06182         if (!request) return NS_ERROR_FAILURE;
06183       progressSink->OnStatus(request, nsnull, NS_OK, msg);      // XXX i18n message
06184     }
06185   }
06186   return NS_OK;
06187 }
06188 
06189 NS_IMETHODIMP
06190 nsImapMailFolder::ProgressStatus(nsIImapProtocol* aProtocol,
06191                                  PRUint32 aMsgId, const PRUnichar *extraInfo)
06192 {
06193   nsXPIDLString progressMsg;
06194 
06195   nsCOMPtr<nsIMsgIncomingServer> server;
06196   nsresult rv = GetServer(getter_AddRefs(server));
06197   if (NS_SUCCEEDED(rv) && server)
06198   {
06199     nsCOMPtr<nsIImapServerSink> serverSink = do_QueryInterface(server);
06200     if (serverSink)
06201       serverSink->GetImapStringByID(aMsgId, getter_Copies(progressMsg));
06202   }
06203   if (progressMsg.IsEmpty())
06204     IMAPGetStringByID(aMsgId, getter_Copies(progressMsg));
06205 
06206   if (aProtocol && !progressMsg.IsEmpty())
06207   {
06208     nsCOMPtr <nsIImapUrl> imapUrl;
06209     aProtocol->GetRunningImapURL(getter_AddRefs(imapUrl));
06210     if (imapUrl)
06211     {
06212       if (extraInfo)
06213       {
06214         PRUnichar *printfString = nsTextFormatter::smprintf(progressMsg, extraInfo);
06215         if (printfString)
06216           progressMsg.Adopt(printfString);  
06217       }
06218       DisplayStatusMsg(imapUrl, progressMsg);
06219     }
06220   }
06221   return NS_OK;
06222 }
06223 
06224 NS_IMETHODIMP
06225 nsImapMailFolder::PercentProgress(nsIImapProtocol* aProtocol,
06226                                   const PRUnichar *aMessage, 
06227                        PRInt32 aCurrentProgress, PRInt32 aMaxProgress)
06228 {
06229   if (aProtocol)
06230   {
06231     nsCOMPtr <nsIImapUrl> imapUrl;
06232     aProtocol->GetRunningImapURL(getter_AddRefs(imapUrl));
06233     if (imapUrl)
06234     {
06235       nsCOMPtr<nsIImapMockChannel> mockChannel;
06236       imapUrl->GetMockChannel(getter_AddRefs(mockChannel));
06237       if (mockChannel)
06238       {
06239         nsCOMPtr<nsIProgressEventSink> progressSink;
06240         mockChannel->GetProgressEventSink(getter_AddRefs(progressSink));
06241         if (progressSink)
06242         {
06243             nsCOMPtr<nsIRequest> request = do_QueryInterface(mockChannel);
06244             if (!request) return NS_ERROR_FAILURE;
06245 
06246             // XXX handle 64-bit ints for real
06247             progressSink->OnProgress(request, nsnull,
06248                                      nsUint64(aCurrentProgress),
06249                                      nsUint64(aMaxProgress));
06250             if (aMessage)
06251               progressSink->OnStatus(request, nsnull, NS_OK, aMessage);      // XXX i18n message
06252         }
06253 
06254       }
06255     }
06256   }
06257 
06258   return NS_OK;
06259 }
06260 
06261 NS_IMETHODIMP
06262 nsImapMailFolder::CopyNextStreamMessage(PRBool copySucceeded, nsISupports *copyState)
06263 {
06264     //if copy has failed it could be either user interrupted it or for some other reason
06265     //don't do any subsequent copies or delete src messages if it is move
06266 
06267 
06268     if (!copySucceeded)
06269       return NS_OK;
06270 
06271     nsresult rv;
06272 
06273     nsCOMPtr<nsImapMailCopyState> mailCopyState = do_QueryInterface(copyState,
06274                                                                     &rv);
06275     if (NS_FAILED(rv)) return rv;
06276 
06277     if (!mailCopyState->m_streamCopy) 
06278       return NS_OK;
06279 
06280     if (mailCopyState->m_curIndex < mailCopyState->m_totalCount)
06281     {
06282         mailCopyState->m_message = do_QueryElementAt(mailCopyState->m_messages,
06283                                                      mailCopyState->m_curIndex,
06284                                                      &rv);
06285         if (NS_SUCCEEDED(rv))
06286         {
06287             PRBool isRead;
06288             mailCopyState->m_message->GetIsRead(&isRead);
06289             mailCopyState->m_unreadCount = (isRead) ? 0 : 1;
06290             rv = CopyStreamMessage(mailCopyState->m_message,
06291                                    this, mailCopyState->m_msgWindow, mailCopyState->m_isMove);
06292         }
06293     }
06294     else
06295     {
06296        if (mailCopyState->m_isMove) 
06297        {
06298           nsCOMPtr<nsIMsgFolder> srcFolder =
06299               do_QueryInterface(mailCopyState->m_srcSupport, &rv);
06300           if (NS_SUCCEEDED(rv) && srcFolder)
06301           {
06302             srcFolder->DeleteMessages(mailCopyState->m_messages, nsnull,
06303               PR_TRUE, PR_TRUE, nsnull, PR_FALSE);
06304             // we want to send this notification after the source messages have
06305             // been deleted.
06306             nsCOMPtr<nsIMsgLocalMailFolder> popFolder = do_QueryInterface(srcFolder); 
06307             if (popFolder)   //needed if move pop->imap to notify FE
06308               srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
06309           }
06310        }
06311     }
06312     return rv;
06313 }
06314 
06315 NS_IMETHODIMP
06316 nsImapMailFolder::SetUrlState(nsIImapProtocol* aProtocol,
06317                               nsIMsgMailNewsUrl* aUrl,
06318                               PRBool isRunning,
06319                               nsresult statusCode)
06320 {
06321   if (!isRunning)
06322   {
06323     ProgressStatus(aProtocol, IMAP_DONE, nsnull);
06324     m_urlRunning = PR_FALSE;
06325     // if no protocol, then we're reading from the mem or disk cache
06326     // and we don't want to end the offline download just yet.
06327     if (aProtocol)
06328     {
06329       EndOfflineDownload();
06330       if (m_downloadingFolderForOfflineUse)
06331       {
06332         ReleaseSemaphore(NS_STATIC_CAST(nsIMsgImapMailFolder*, this));
06333         m_downloadingFolderForOfflineUse = PR_FALSE;
06334       }
06335     }
06336   }
06337 
06338     if (aUrl)
06339         return aUrl->SetUrlState(isRunning, statusCode);
06340     return statusCode;
06341 }
06342 
06343 // used when copying from local mail folder, or other imap server)
06344 nsresult
06345 nsImapMailFolder::CopyMessagesWithStream(nsIMsgFolder* srcFolder,
06346                                 nsISupportsArray* messages,
06347                                 PRBool isMove,
06348                                 PRBool isCrossServerOp,
06349                                 nsIMsgWindow *msgWindow,
06350                                 nsIMsgCopyServiceListener* listener, 
06351                                 PRBool allowUndo)
06352 {
06353     nsresult rv = NS_ERROR_NULL_POINTER;
06354     if (!srcFolder || !messages) return rv;
06355 
06356     nsCOMPtr<nsISupports> aSupport(do_QueryInterface(srcFolder, &rv));
06357     if (NS_FAILED(rv)) return rv;
06358     rv = InitCopyState(aSupport, messages, isMove, PR_FALSE, isCrossServerOp, 
06359       /* new message flags, not used */0, listener, msgWindow, allowUndo);
06360     if(NS_FAILED(rv)) 
06361       return rv;
06362 
06363     m_copyState->m_streamCopy = PR_TRUE;
06364 
06365     // ** jt - needs to create server to server move/copy undo msg txn
06366     if (m_copyState->m_allowUndo)
06367     {
06368        nsCAutoString messageIds;
06369        nsMsgKeyArray srcKeyArray;
06370        nsCOMPtr<nsIUrlListener> urlListener;
06371 
06372        rv = QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
06373        rv = BuildIdsAndKeyArray(messages, messageIds, srcKeyArray);
06374 
06375        nsImapMoveCopyMsgTxn* undoMsgTxn = new nsImapMoveCopyMsgTxn;
06376 
06377        if (!undoMsgTxn || NS_FAILED(undoMsgTxn->Init(srcFolder, &srcKeyArray, messageIds.get(), this,
06378                                     PR_TRUE, isMove, m_eventQueue, urlListener)))
06379        {
06380          delete undoMsgTxn;
06381          return NS_ERROR_OUT_OF_MEMORY;
06382        }
06383        if (isMove)
06384        {
06385           if (mFlags & MSG_FOLDER_FLAG_TRASH)
06386             undoMsgTxn->SetTransactionType(nsIMessenger::eDeleteMsg);
06387           else
06388             undoMsgTxn->SetTransactionType(nsIMessenger::eMoveMsg);
06389        }
06390        else
06391        {
06392           undoMsgTxn->SetTransactionType(nsIMessenger::eCopyMsg);
06393        }
06394     
06395        rv = undoMsgTxn->QueryInterface(
06396          NS_GET_IID(nsImapMoveCopyMsgTxn), 
06397          getter_AddRefs(m_copyState->m_undoMsgTxn) );
06398     }
06399     nsCOMPtr<nsIMsgDBHdr> aMessage;
06400     aMessage = do_QueryElementAt(messages, 0, &rv);
06401     if (NS_SUCCEEDED(rv))
06402         CopyStreamMessage(aMessage, this, msgWindow, isMove);
06403 
06404     return rv; //we are clearing copy state in CopyMessages on failure
06405 }
06406 
06407 nsresult nsImapMailFolder::GetClearedOriginalOp(nsIMsgOfflineImapOperation *op, nsIMsgOfflineImapOperation **originalOp, nsIMsgDatabase **originalDB)
06408 {
06409   nsIMsgOfflineImapOperation *returnOp = nsnull;
06410   nsOfflineImapOperationType opType;
06411   op->GetOperation(&opType);
06412   NS_ASSERTION(opType & nsIMsgOfflineImapOperation::kMoveResult, "not an offline move op");
06413   
06414   nsXPIDLCString sourceFolderURI;
06415   op->GetSourceFolderURI(getter_Copies(sourceFolderURI));
06416   
06417   nsCOMPtr<nsIRDFResource> res;
06418   nsresult rv;
06419   
06420   nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv));
06421   if (NS_FAILED(rv)) 
06422     return rv; 
06423   rv = rdf->GetResource(sourceFolderURI, getter_AddRefs(res));
06424   if (NS_SUCCEEDED(rv))
06425   {
06426     nsCOMPtr<nsIMsgFolder> sourceFolder(do_QueryInterface(res, &rv));
06427     if (NS_SUCCEEDED(rv) && sourceFolder)
06428     {
06429       if (sourceFolder)
06430       {
06431         nsCOMPtr <nsIDBFolderInfo> folderInfo;
06432         sourceFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), originalDB);
06433         if (*originalDB)
06434         {
06435           nsMsgKey originalKey;
06436           op->GetMessageKey(&originalKey);
06437           rv = (*originalDB)->GetOfflineOpForKey(originalKey, PR_FALSE, &returnOp);
06438           if (NS_SUCCEEDED(rv) && returnOp)
06439           {
06440             nsXPIDLCString moveDestination;
06441             nsXPIDLCString thisFolderURI;
06442             
06443             GetURI(getter_Copies(thisFolderURI));
06444             
06445             returnOp->GetDestinationFolderURI(getter_Copies(moveDestination));
06446             if (!nsCRT::strcmp(moveDestination, thisFolderURI))
06447               returnOp->ClearOperation(nsIMsgOfflineImapOperation::kMoveResult);
06448           }
06449         }
06450       }
06451     }
06452   }
06453   NS_IF_ADDREF(returnOp);
06454   *originalOp = returnOp;
06455   return rv;
06456 }
06457 
06458 nsresult nsImapMailFolder::GetOriginalOp(nsIMsgOfflineImapOperation *op, nsIMsgOfflineImapOperation **originalOp, nsIMsgDatabase **originalDB)
06459 {
06460   nsIMsgOfflineImapOperation *returnOp = nsnull;
06461   
06462   nsXPIDLCString sourceFolderURI;
06463   op->GetSourceFolderURI(getter_Copies(sourceFolderURI));
06464        
06465   nsCOMPtr<nsIRDFResource> res;
06466   nsresult rv;
06467 
06468   nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv));
06469   if (NS_FAILED(rv)) 
06470     return rv; 
06471   rv = rdf->GetResource(sourceFolderURI, getter_AddRefs(res));
06472   if (NS_SUCCEEDED(rv))
06473   {
06474     nsCOMPtr<nsIMsgFolder> sourceFolder(do_QueryInterface(res, &rv));
06475     if (NS_SUCCEEDED(rv) && sourceFolder)
06476     {
06477            if (sourceFolder)
06478            {
06479         nsCOMPtr <nsIDBFolderInfo> folderInfo;
06480         sourceFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), originalDB);
06481                   if (*originalDB)
06482                   {
06483           nsMsgKey originalKey;
06484           op->GetMessageKey(&originalKey);
06485           rv = (*originalDB)->GetOfflineOpForKey(originalKey, PR_FALSE, &returnOp);
06486                   }
06487       }
06488     }
06489        }
06490   NS_IF_ADDREF(returnOp);
06491   *originalOp = returnOp;
06492   return rv;
06493 }
06494 
06495 nsresult nsImapMailFolder::CopyOfflineMsgBody(nsIMsgFolder *srcFolder, nsIMsgDBHdr *destHdr, nsIMsgDBHdr *origHdr)
06496 {
06497   nsCOMPtr<nsIOutputStream> outputStream;
06498   nsresult rv = GetOfflineStoreOutputStream(getter_AddRefs(outputStream));
06499   nsCOMPtr <nsISeekableStream> seekable;
06500 
06501   seekable = do_QueryInterface(outputStream);
06502 
06503   if (seekable)
06504   {
06505 
06506     nsMsgKey messageOffset;
06507     PRUint32 messageSize;
06508     origHdr->GetMessageOffset(&messageOffset);
06509     origHdr->GetOfflineMessageSize(&messageSize);
06510     if (!messageSize)
06511     {
06512       nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(srcFolder); 
06513       if (localFolder)   //can just use regular message size
06514         origHdr->GetMessageSize(&messageSize);
06515     }
06516     PRInt64 tellPos;
06517     seekable->Tell(&tellPos);
06518     nsInt64 curStorePos = tellPos;
06519     destHdr->SetMessageOffset((PRUint32) curStorePos);
06520     nsCOMPtr <nsIInputStream> offlineStoreInputStream;
06521     rv = srcFolder->GetOfflineStoreInputStream(getter_AddRefs(offlineStoreInputStream));
06522     if (NS_SUCCEEDED(rv) && offlineStoreInputStream)
06523     {
06524       nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(offlineStoreInputStream);
06525       NS_ASSERTION(seekStream, "non seekable stream - can't read from offline msg");
06526       if (seekStream)
06527       {
06528         rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, messageOffset);
06529         if (NS_SUCCEEDED(rv))
06530         {
06531           // now, copy the dest folder offline store msg to the temp file
06532           PRInt32 inputBufferSize = 10240;
06533           char *inputBuffer = (char *) PR_Malloc(inputBufferSize);
06534           PRInt32 bytesLeft;
06535           PRUint32 bytesRead, bytesWritten;
06536           bytesLeft = messageSize;
06537           rv = (inputBuffer) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
06538           while (bytesLeft > 0 && NS_SUCCEEDED(rv))
06539           {
06540             rv = offlineStoreInputStream->Read(inputBuffer, inputBufferSize, &bytesRead);
06541             if (NS_SUCCEEDED(rv) && bytesRead > 0)
06542             {
06543               rv = outputStream->Write(inputBuffer, PR_MIN((PRInt32) bytesRead, bytesLeft), &bytesWritten);
06544               NS_ASSERTION((PRInt32) bytesWritten == PR_MIN((PRInt32) bytesRead, bytesLeft), "wrote out incorrect number of bytes");
06545             }
06546             else
06547               break;
06548             bytesLeft -= bytesRead;
06549           }
06550           PR_FREEIF(inputBuffer);
06551           outputStream->Flush();
06552         }
06553       }
06554     }
06555     if (NS_SUCCEEDED(rv))
06556     {
06557       PRUint32 resultFlags;
06558       destHdr->OrFlags(MSG_FLAG_OFFLINE, &resultFlags);
06559       destHdr->SetOfflineMessageSize(messageSize);
06560 
06561     }
06562   }
06563   return rv;
06564 }
06565 
06566 // this imap folder is the destination of an offline move/copy.
06567 // We are either offline, or doing a pseudo-offline delete (where we do an offline
06568 // delete, load the next message, then playback the offline delete). 
06569 nsresult nsImapMailFolder::CopyMessagesOffline(nsIMsgFolder* srcFolder,
06570                                nsISupportsArray* messages,
06571                                PRBool isMove,
06572                                nsIMsgWindow *msgWindow,
06573                                nsIMsgCopyServiceListener* listener)
06574 {
06575   NS_ENSURE_ARG(messages);
06576   nsresult rv = NS_OK;
06577   nsresult stopit = 0;
06578   nsCOMPtr <nsIMsgDatabase> sourceMailDB;
06579   nsCOMPtr <nsIDBFolderInfo> srcDbFolderInfo;
06580   srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(srcDbFolderInfo), getter_AddRefs(sourceMailDB));
06581   PRBool deleteToTrash = PR_FALSE;
06582   PRBool deleteImmediately = PR_FALSE;
06583   PRUint32 srcCount;
06584   messages->Count(&srcCount);
06585   nsCOMPtr<nsIImapIncomingServer> imapServer;
06586   rv = GetImapIncomingServer(getter_AddRefs(imapServer));
06587 
06588   if (NS_SUCCEEDED(rv) && imapServer)
06589   {
06590     nsMsgImapDeleteModel deleteModel;
06591     imapServer->GetDeleteModel(&deleteModel);
06592     deleteToTrash = (deleteModel == nsMsgImapDeleteModels::MoveToTrash);
06593     deleteImmediately = (deleteModel == nsMsgImapDeleteModels::DeleteNoTrash);
06594   }    
06595   if (sourceMailDB)
06596   {
06597     // save the future ops in the source DB, if this is not a imap->local copy/move
06598     
06599     nsCOMPtr <nsITransactionManager> txnMgr;
06600     if (msgWindow)
06601       msgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
06602     if (txnMgr)
06603       txnMgr->BeginBatch();
06604     GetDatabase(nsnull);
06605     if (mDatabase) 
06606     {
06607       // get the highest key in the dest db, so we can make up our fake keys
06608       PRBool highWaterDeleted = PR_FALSE;
06609       nsMsgKey fakeBase = 1;
06610       nsCOMPtr <nsIDBFolderInfo> folderInfo;
06611       rv = mDatabase->GetDBFolderInfo(getter_AddRefs(folderInfo));
06612       NS_ENSURE_SUCCESS(rv, rv);
06613       nsMsgKey highWaterMark = nsMsgKey_None;
06614       folderInfo->GetHighWater(&highWaterMark);
06615       
06616       fakeBase += highWaterMark;
06617       
06618       // put fake message in destination db, delete source if move
06619       for (PRUint32 sourceKeyIndex=0; !stopit && (sourceKeyIndex < srcCount); sourceKeyIndex++)
06620       {
06621         PRBool       messageReturningHome = PR_FALSE;
06622         nsXPIDLCString sourceFolderURI;
06623         srcFolder->GetURI(getter_Copies(sourceFolderURI));
06624         nsXPIDLCString originalSrcFolderURI;
06625         if (sourceFolderURI.get())
06626           originalSrcFolderURI.Adopt(nsCRT::strdup(sourceFolderURI.get()));
06627         nsCOMPtr<nsIMsgDBHdr> message;
06628         message = do_QueryElementAt(messages, sourceKeyIndex);
06629         nsMsgKey originalKey;
06630         if (message)
06631         {
06632           rv = message->GetMessageKey(&originalKey);
06633         }
06634         else
06635         {
06636           NS_ASSERTION(PR_FALSE, "bad msg in src array");
06637           continue;
06638         }
06639         nsCOMPtr <nsIMsgOfflineImapOperation> sourceOp;
06640         rv = sourceMailDB->GetOfflineOpForKey(originalKey, PR_TRUE, getter_AddRefs(sourceOp));
06641         if (NS_SUCCEEDED(rv) && sourceOp)
06642         {
06643           srcFolder->SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
06644           nsCOMPtr <nsIMsgDatabase> originalDB;
06645           nsOfflineImapOperationType opType;
06646           sourceOp->GetOperation(&opType);
06647           // if we already have an offline op for this key, then we need to see if it was
06648           // moved into the source folder while offline
06649           if (opType == nsIMsgOfflineImapOperation::kMoveResult) // offline move
06650           {
06651             // gracious me, we are moving something we already moved while offline!
06652             // find the original operation and clear it!
06653             nsCOMPtr <nsIMsgOfflineImapOperation> originalOp;
06654             rv = GetClearedOriginalOp(sourceOp, getter_AddRefs(originalOp), getter_AddRefs(originalDB));
06655             if (originalOp)
06656             {
06657               nsXPIDLCString originalString;
06658               nsXPIDLCString srcFolderURI;
06659               
06660               srcFolder->GetURI(getter_Copies(srcFolderURI));
06661               sourceOp->GetSourceFolderURI(getter_Copies(originalString));
06662               sourceOp->GetMessageKey(&originalKey);
06663               originalSrcFolderURI.Adopt(originalString.get() ? nsCRT::strdup(originalString.get()) : 0);
06664               
06665               if (isMove)
06666                 sourceMailDB->RemoveOfflineOp(sourceOp);
06667               
06668               sourceOp = originalOp;
06669               if (!nsCRT::strcmp(originalSrcFolderURI, srcFolderURI))
06670               {
06671                 messageReturningHome = PR_TRUE;
06672                 originalDB->RemoveOfflineOp(originalOp);
06673               }
06674             }
06675           }
06676           
06677           if (!messageReturningHome)
06678           {
06679             nsXPIDLCString folderURI;
06680             GetURI(getter_Copies(folderURI));
06681             
06682             if (isMove)
06683             {
06684               PRUint32 msgSize;
06685               PRUint32 msgFlags;
06686               imapMessageFlagsType newImapFlags = 0;
06687               message->GetMessageSize(&msgSize);
06688               message->GetFlags(&msgFlags);
06689               sourceOp->SetDestinationFolderURI(folderURI); // offline move
06690               sourceOp->SetOperation(nsIMsgOfflineImapOperation::kMsgMoved);
06691               sourceOp->SetMsgSize(msgSize);
06692               newImapFlags = msgFlags & 0x7;
06693               if (msgFlags & MSG_FLAG_FORWARDED)
06694                 newImapFlags |=  kImapMsgForwardedFlag;
06695               sourceOp->SetNewFlags(newImapFlags);
06696             }
06697             else
06698               sourceOp->AddMessageCopyOperation(folderURI); // offline copy
06699 
06700            nsMsgKeyArray srcKeyArray;
06701            nsCOMPtr<nsIUrlListener> urlListener;
06702 
06703             sourceOp->GetOperation(&opType);
06704            srcKeyArray.Add(originalKey);
06705            rv = QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
06706            nsImapOfflineTxn *undoMsgTxn = new 
06707               nsImapOfflineTxn(srcFolder, &srcKeyArray, this, isMove, opType, message,
06708                 m_eventQueue, urlListener);
06709 
06710             if (undoMsgTxn)
06711             {
06712               if (isMove)
06713                 undoMsgTxn->SetTransactionType(nsIMessenger::eMoveMsg);
06714               else
06715                 undoMsgTxn->SetTransactionType(nsIMessenger::eCopyMsg);
06716               // we're adding this undo action before the delete is successful. This is evil,
06717               // but 4.5 did it as well.
06718               if (txnMgr)
06719                 txnMgr->DoTransaction(undoMsgTxn);
06720             }
06721           }
06722           PRBool hasMsgOffline = PR_FALSE;
06723           srcFolder->HasMsgOffline(originalKey, &hasMsgOffline);
06724 //          if (hasMsgOffline)
06725 //            CopyOfflineMsgBody(srcFolder, originalKey);
06726 
06727         }
06728         else
06729           stopit = NS_ERROR_FAILURE;
06730         
06731         
06732         nsCOMPtr <nsIMsgDBHdr> mailHdr;
06733         rv = sourceMailDB->GetMsgHdrForKey(originalKey, getter_AddRefs(mailHdr));
06734         if (NS_SUCCEEDED(rv) && mailHdr)
06735         {
06736           PRBool successfulCopy = PR_FALSE;
06737           nsMsgKey srcDBhighWaterMark;
06738           srcDbFolderInfo->GetHighWater(&srcDBhighWaterMark);
06739           highWaterDeleted = !highWaterDeleted && isMove && deleteToTrash &&
06740             (originalKey == srcDBhighWaterMark);
06741           
06742           nsCOMPtr <nsIMsgDBHdr> newMailHdr;
06743           rv = mDatabase->CopyHdrFromExistingHdr(fakeBase + sourceKeyIndex, mailHdr,
06744             PR_TRUE, getter_AddRefs(newMailHdr));
06745           if (!newMailHdr || NS_FAILED(rv))
06746           {
06747             NS_ASSERTION(PR_FALSE, "failed to copy hdr");
06748             stopit = rv;
06749           }
06750           
06751           if (NS_SUCCEEDED(stopit))
06752           {
06753             PRBool hasMsgOffline = PR_FALSE;
06754             srcFolder->HasMsgOffline(originalKey, &hasMsgOffline);
06755             if (hasMsgOffline)
06756               CopyOfflineMsgBody(srcFolder, newMailHdr, mailHdr);
06757 
06758             nsCOMPtr <nsIMsgOfflineImapOperation> destOp;
06759             mDatabase->GetOfflineOpForKey(fakeBase + sourceKeyIndex, PR_TRUE, getter_AddRefs(destOp));
06760             if (destOp)
06761             {
06762               // check if this is a move back to the original mailbox, in which case
06763               // we just delete the offline operation.
06764               if (messageReturningHome)
06765               {
06766                 mDatabase->RemoveOfflineOp(destOp);
06767               }
06768               else
06769               {
06770                 SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
06771                 destOp->SetSourceFolderURI(originalSrcFolderURI);
06772                 destOp->SetMessageKey(originalKey);
06773                 {
06774                   nsCOMPtr<nsIUrlListener> urlListener;
06775 
06776                   QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
06777                   nsMsgKeyArray keyArray;
06778                   keyArray.Add(fakeBase + sourceKeyIndex);
06779                   nsImapOfflineTxn *undoMsgTxn = new 
06780                     nsImapOfflineTxn(this, &keyArray, this, isMove, nsIMsgOfflineImapOperation::kAddedHeader,
06781                       newMailHdr, m_eventQueue, urlListener);
06782                  if (undoMsgTxn)
06783                  {
06784                    if (txnMgr)
06785                      txnMgr->DoTransaction(undoMsgTxn);
06786                  }
06787                 }
06788               }
06789             }
06790             else
06791               stopit = NS_ERROR_FAILURE;
06792           }
06793           successfulCopy = NS_SUCCEEDED(stopit);
06794           
06795           
06796           nsMsgKey msgKey;
06797           mailHdr->GetMessageKey(&msgKey);
06798           if (isMove && successfulCopy)   
06799           {
06800            nsMsgKeyArray srcKeyArray;
06801            nsCOMPtr<nsIUrlListener> urlListener;
06802 
06803            srcKeyArray.Add(msgKey);
06804            rv = QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
06805 
06806             nsOfflineImapOperationType opType = nsIMsgOfflineImapOperation::kDeletedMsg;
06807             if (!deleteToTrash)
06808               opType = nsIMsgOfflineImapOperation::kMsgMarkedDeleted;
06809             srcKeyArray.Add(msgKey);
06810             nsImapOfflineTxn *undoMsgTxn = new 
06811               nsImapOfflineTxn(srcFolder, &srcKeyArray, this, isMove, opType, mailHdr,
06812                 m_eventQueue, urlListener);
06813              if (undoMsgTxn)
06814              {
06815                if (isMove)
06816                {
06817                  if (mFlags & MSG_FOLDER_FLAG_TRASH)
06818                    undoMsgTxn->SetTransactionType(nsIMessenger::eDeleteMsg);
06819                  else
06820                    undoMsgTxn->SetTransactionType(nsIMessenger::eMoveMsg);
06821                }
06822                else
06823                {
06824                   undoMsgTxn->SetTransactionType(nsIMessenger::eCopyMsg);
06825                }
06826                if (txnMgr)
06827                  txnMgr->DoTransaction(undoMsgTxn);
06828              }
06829             if (deleteToTrash || deleteImmediately)
06830               sourceMailDB->DeleteMessage(msgKey, nsnull, PR_FALSE);
06831             else
06832               sourceMailDB->MarkImapDeleted(msgKey,PR_TRUE,nsnull); // offline delete
06833           }
06834           
06835           
06836           if (!successfulCopy)
06837             highWaterDeleted = PR_FALSE;
06838         }
06839       }
06840             
06841       if (isMove)
06842         sourceMailDB->Commit(nsMsgDBCommitType::kLargeCommit);
06843       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
06844       SummaryChanged();
06845       srcFolder->SummaryChanged();
06846     }
06847     if (txnMgr)
06848       txnMgr->EndBatch();
06849   }
06850 
06851   nsCOMPtr<nsISupports> srcSupport = do_QueryInterface(srcFolder);
06852   OnCopyCompleted(srcSupport, rv);
06853 
06854   if (NS_SUCCEEDED(rv) && isMove)
06855     srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
06856 
06857   return rv;
06858 }
06859 
06860 NS_IMETHODIMP
06861 nsImapMailFolder::CopyMessages(nsIMsgFolder* srcFolder,
06862                                nsISupportsArray* messages,
06863                                PRBool isMove,
06864                                nsIMsgWindow *msgWindow,
06865                                nsIMsgCopyServiceListener* listener,
06866                                PRBool isFolder, //isFolder for future use when we do cross-server folder move/copy
06867                                PRBool allowUndo)  
06868 {
06869   nsresult rv = NS_OK;
06870   nsCAutoString messageIds;
06871   nsMsgKeyArray srcKeyArray;
06872   nsCOMPtr<nsIUrlListener> urlListener;
06873   nsCOMPtr<nsISupports> srcSupport;
06874   nsCOMPtr<nsISupports> copySupport;
06875 
06876   if (!(mFlags & (MSG_FOLDER_FLAG_TRASH|MSG_FOLDER_FLAG_JUNK)))
06877     SetMRUTime();
06878 
06879   if (WeAreOffline())
06880     return CopyMessagesOffline(srcFolder, messages, isMove, msgWindow, listener);
06881 
06882   nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
06883   NS_ENSURE_SUCCESS(rv,rv);
06884 
06885   srcSupport = do_QueryInterface(srcFolder);
06886 
06887   nsCOMPtr <nsIMsgIncomingServer> srcServer;
06888   nsCOMPtr <nsIMsgIncomingServer> dstServer;
06889 
06890   rv = srcFolder->GetServer(getter_AddRefs(srcServer));
06891   if(NS_FAILED(rv)) goto done;
06892 
06893   rv = GetServer(getter_AddRefs(dstServer));
06894   if(NS_FAILED(rv)) goto done;
06895 
06896   NS_ENSURE_TRUE(dstServer, NS_ERROR_NULL_POINTER);
06897   PRBool sameServer;
06898   rv = dstServer->Equals(srcServer, &sameServer);
06899   if (NS_FAILED(rv)) goto done;
06900 
06901    PRUint32 supportedUserFlags;
06902    GetSupportedUserFlags(&supportedUserFlags);
06903 
06904    if (! (supportedUserFlags & kImapMsgSupportUserFlag))
06905    {
06906       PRUint32 count = 0;
06907       PRUint32 i;
06908 
06909       rv = messages->Count(&count);
06910       if (NS_FAILED(rv)) return rv;
06911 
06912       // make sure database is open to set special flags below
06913       if (!mDatabase)
06914         GetDatabase(nsnull);
06915 
06916       // check if any msg hdr has special flags or properties set
06917       // that we need to set on the dest hdr
06918       for (i = 0; i < count; i++)
06919       {
06920         nsCOMPtr <nsIMsgDBHdr> msgDBHdr = do_QueryElementAt(messages, i, &rv);
06921         if (mDatabase && msgDBHdr)
06922         {
06923           nsMsgLabelValue label;
06924           nsXPIDLCString junkScore, junkScoreOrigin;
06925           nsMsgPriorityValue priority;
06926           msgDBHdr->GetStringProperty("junkscore", getter_Copies(junkScore));
06927           msgDBHdr->GetStringProperty("junkscoreorigin", getter_Copies(junkScoreOrigin));
06928           if (!junkScore.IsEmpty()) // ignore already scored messages.
06929             mDatabase->SetAttributesOnPendingHdr(msgDBHdr, "junkscore", junkScore.get(), 0);
06930           if (!junkScoreOrigin.IsEmpty())
06931             mDatabase->SetAttributesOnPendingHdr(msgDBHdr, "junkscoreorigin", junkScoreOrigin.get(), 0);
06932           msgDBHdr->GetLabel(&label);
06933           if (label != 0)
06934           {
06935             nsCAutoString labelStr;
06936             labelStr.AppendInt(label);
06937             mDatabase->SetAttributesOnPendingHdr(msgDBHdr, "label", labelStr.get(), 0);
06938           }
06939          msgDBHdr->GetPriority(&priority);
06940          if(priority != 0)
06941           {
06942             nsCAutoString priorityStr;
06943             priorityStr.AppendInt(priority);
06944             mDatabase->SetAttributesOnPendingHdr(msgDBHdr, "priority", priorityStr.get(), 0);
06945           }
06946           nsXPIDLCString keywords;
06947           msgDBHdr->GetStringProperty("keywords", getter_Copies(keywords));
06948           if (!keywords.IsEmpty())
06949             mDatabase->SetAttributesOnPendingHdr(msgDBHdr, "keywords", keywords.get(), 0);
06950         }
06951       }
06952    }
06953   // if the folders aren't on the same server, do a stream base copy
06954   if (!sameServer) 
06955   {
06956     rv = CopyMessagesWithStream(srcFolder, messages, isMove, PR_TRUE, msgWindow, listener, allowUndo);
06957     goto done;
06958   }
06959 
06960   rv = BuildIdsAndKeyArray(messages, messageIds, srcKeyArray);
06961   if(NS_FAILED(rv)) goto done;
06962 
06963   rv = QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
06964 
06965   rv = InitCopyState(srcSupport, messages, isMove, PR_TRUE, PR_FALSE, 
06966     /* newMsgFlags, not used */0, listener, msgWindow, allowUndo);
06967   if (NS_FAILED(rv)) goto done;
06968 
06969   m_copyState->m_curIndex = m_copyState->m_totalCount;
06970 
06971   if (isMove)
06972     srcFolder->EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE/* dbBatching*/);  //disable message count notification 
06973 
06974   copySupport = do_QueryInterface(m_copyState);
06975   if (imapService)
06976   rv = imapService->OnlineMessageCopy(m_eventQueue,
06977                                             srcFolder, messageIds.get(),
06978                                             this, PR_TRUE, isMove,
06979                                             urlListener, nsnull,
06980                                             copySupport, msgWindow);
06981   if (m_copyState->m_allowUndo)
06982     if (NS_SUCCEEDED(rv))
06983     {
06984        nsImapMoveCopyMsgTxn* undoMsgTxn = new nsImapMoveCopyMsgTxn;
06985        if (!undoMsgTxn || NS_FAILED(undoMsgTxn->Init(srcFolder, &srcKeyArray, 
06986                                     messageIds.get(), this,
06987                                     PR_TRUE, isMove, m_eventQueue, urlListener)))
06988        {
06989          delete undoMsgTxn;
06990          return NS_ERROR_OUT_OF_MEMORY;
06991        }
06992        if (isMove)
06993        {
06994          if (mFlags & MSG_FOLDER_FLAG_TRASH)
06995            undoMsgTxn->SetTransactionType(nsIMessenger::eDeleteMsg);
06996          else
06997            undoMsgTxn->SetTransactionType(nsIMessenger::eMoveMsg);
06998        }
06999        else
07000        {
07001           undoMsgTxn->SetTransactionType(nsIMessenger::eCopyMsg);
07002        }
07003        rv = undoMsgTxn->QueryInterface(
07004          NS_GET_IID(nsImapMoveCopyMsgTxn), 
07005          getter_AddRefs(m_copyState->m_undoMsgTxn) );
07006     }
07007     else 
07008       NS_ASSERTION(PR_FALSE, "online copy failed");
07009 
07010 done:
07011     if (NS_FAILED(rv))
07012     {
07013       (void) OnCopyCompleted(srcSupport, PR_FALSE);
07014       if (isMove)
07015       {
07016         srcFolder->EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE/* dbBatching*/);  //enable message count notification 
07017         NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
07018       }
07019     }
07020     return rv;
07021 }
07022 
07023 class nsImapFolderCopyState : public nsIUrlListener, public nsIMsgCopyServiceListener
07024 {
07025 public:
07026   nsImapFolderCopyState(nsIMsgFolder *destParent, nsIMsgFolder *srcFolder,
07027                     PRBool isMoveFolder, nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener *listener);
07028   ~nsImapFolderCopyState();
07029 
07030   NS_DECL_ISUPPORTS
07031   NS_DECL_NSIURLLISTENER
07032   NS_DECL_NSIMSGCOPYSERVICELISTENER
07033 
07034   nsresult StartNextCopy();
07035   nsresult AdvanceToNextFolder(nsresult aStatus);
07036 protected:
07037   nsCOMPtr <nsIMsgFolder> m_destParent;
07038   nsCOMPtr <nsIMsgFolder> m_srcFolder;
07039   PRBool                  m_isMoveFolder;
07040   nsCOMPtr <nsIMsgCopyServiceListener> m_copySrvcListener;
07041   nsCOMPtr <nsIMsgWindow> m_msgWindow;
07042   PRInt32                 m_childIndex;
07043   nsCOMPtr <nsISupportsArray> m_srcChildFolders;
07044   nsCOMPtr <nsISupportsArray> m_destParents;
07045 
07046 };
07047 
07048 NS_IMPL_ISUPPORTS2(nsImapFolderCopyState, nsIUrlListener, nsIMsgCopyServiceListener)
07049 
07050 nsImapFolderCopyState::nsImapFolderCopyState(nsIMsgFolder *destParent, nsIMsgFolder *srcFolder,
07051                                              PRBool isMoveFolder, nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener *listener)
07052 {
07053   m_destParent = destParent;
07054   m_srcFolder = srcFolder;
07055   m_isMoveFolder = isMoveFolder;
07056   m_msgWindow = msgWindow;
07057   m_copySrvcListener = listener;
07058   m_childIndex = -1;
07059   m_srcChildFolders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
07060   m_destParents = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
07061 }
07062 
07063 nsImapFolderCopyState::~nsImapFolderCopyState()
07064 {
07065 }
07066 
07067 nsresult
07068 nsImapFolderCopyState::StartNextCopy()
07069 {
07070   nsresult rv;
07071 
07072 
07073   // first make sure dest folder exists.
07074   nsCOMPtr <nsIImapService> imapService = do_GetService (NS_IMAPSERVICE_CONTRACTID, &rv);
07075   if (NS_SUCCEEDED(rv))
07076   {
07077     nsXPIDLString folderName;
07078     m_srcFolder->GetName(getter_Copies(folderName));
07079 
07080     nsCOMPtr<nsIEventQueueService> pEventQService = 
07081       do_GetService(kEventQueueServiceCID, &rv); 
07082     nsCOMPtr <nsIEventQueue> eventQueue;
07083     if (NS_SUCCEEDED(rv) && pEventQService)
07084       pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
07085       getter_AddRefs(eventQueue));
07086 
07087     rv = imapService->EnsureFolderExists(eventQueue, m_destParent,
07088                             folderName.get(), 
07089                             this, nsnull);
07090   }
07091   return rv;
07092 }
07093 
07094 nsresult nsImapFolderCopyState::AdvanceToNextFolder(nsresult aStatus)
07095 {
07096   nsresult rv = NS_OK;
07097 
07098   m_childIndex++;
07099   PRUint32 childCount = 0;
07100   if (m_srcChildFolders)
07101     m_srcChildFolders->Count(&childCount);
07102 
07103   if (m_childIndex >= childCount)
07104   {
07105     if (m_copySrvcListener)
07106       rv = m_copySrvcListener->OnStopCopy(aStatus);
07107     Release();
07108   }
07109   else
07110   {
07111     m_destParent = do_QueryElementAt(m_destParents, m_childIndex, &rv);
07112     m_srcFolder = do_QueryElementAt(m_srcChildFolders, m_childIndex, &rv);
07113     rv = StartNextCopy();
07114   }
07115   return rv;
07116 }
07117 
07118 NS_IMETHODIMP
07119 nsImapFolderCopyState::OnStartRunningUrl(nsIURI *aUrl)
07120 {
07121   NS_PRECONDITION(aUrl, "sanity check - need to be be running non-null url");
07122   return NS_OK;
07123 }
07124 
07125 NS_IMETHODIMP
07126 nsImapFolderCopyState::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
07127 {
07128   if (NS_FAILED(aExitCode))
07129   {
07130     if (m_copySrvcListener)
07131       m_copySrvcListener->OnStopCopy(aExitCode);
07132     Release();
07133     return aExitCode; // or NS_OK???
07134   }
07135   nsresult rv = NS_OK;
07136   if (aUrl)
07137   {
07138     nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aUrl);
07139 
07140     if (imapUrl)
07141     {
07142       nsImapAction imapAction = nsIImapUrl::nsImapTest;
07143       imapUrl->GetImapAction(&imapAction);
07144 
07145       switch(imapAction)
07146       {
07147         case nsIImapUrl::nsImapEnsureExistsFolder:
07148         {
07149 
07150           nsCOMPtr<nsIMsgFolder> newMsgFolder;
07151 
07152           nsXPIDLString folderName;
07153           nsXPIDLCString utf7LeafName;
07154           m_srcFolder->GetName(getter_Copies(folderName));
07155           rv = CopyUTF16toMUTF7(folderName, utf7LeafName);
07156           rv = m_destParent->FindSubFolder(utf7LeafName, getter_AddRefs(newMsgFolder));
07157           NS_ENSURE_SUCCESS(rv,rv);
07158 
07159           // check if the source folder has children. If it does, list them 
07160           // into m_srcChildFolders, and set m_destParents for the 
07161           // corresponding indexes to the newly created folder.
07162           PRUint32 childCount;
07163           m_srcFolder->Count(&childCount);
07164 
07165           for (PRUint32 childIndex = 0; childIndex < childCount; childIndex++)
07166           {
07167             nsCOMPtr <nsISupports> child = do_QueryElementAt(m_srcFolder, childIndex, &rv);
07168             if (NS_SUCCEEDED(rv))
07169             {
07170               m_srcChildFolders->InsertElementAt(child, m_childIndex + childIndex + 1);
07171               m_destParents->InsertElementAt(newMsgFolder, m_childIndex + childIndex + 1);
07172             }
07173           }
07174 
07175           nsCOMPtr<nsISimpleEnumerator> messages;
07176           rv = m_srcFolder->GetMessages(m_msgWindow, getter_AddRefs(messages));
07177 
07178           nsCOMPtr<nsISupportsArray> msgSupportsArray;
07179           NS_NewISupportsArray(getter_AddRefs(msgSupportsArray));
07180 
07181           PRBool hasMoreElements;
07182           nsCOMPtr<nsISupports> aSupport;
07183 
07184           if (messages)
07185             messages->HasMoreElements(&hasMoreElements);
07186   
07187           if (!hasMoreElements)
07188             return AdvanceToNextFolder(NS_OK);
07189 
07190           while (hasMoreElements && NS_SUCCEEDED(rv))
07191           {
07192             rv = messages->GetNext(getter_AddRefs(aSupport));
07193             rv = msgSupportsArray->AppendElement(aSupport);
07194             messages->HasMoreElements(&hasMoreElements);
07195           }
07196   
07197           nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
07198           if (NS_SUCCEEDED(rv))
07199             rv = copyService->CopyMessages(m_srcFolder,
07200                                msgSupportsArray, newMsgFolder,
07201                                m_isMoveFolder,
07202                                this,
07203                                m_msgWindow,
07204                                PR_FALSE /* allowUndo */);
07205         }
07206         break;
07207       }
07208     }
07209   }
07210   return rv;
07211 }
07212 
07213 
07214 NS_IMETHODIMP nsImapFolderCopyState::OnStartCopy()
07215 {
07216   return NS_OK;
07217 }
07218 
07219 /* void OnProgress (in PRUint32 aProgress, in PRUint32 aProgressMax); */
07220 NS_IMETHODIMP nsImapFolderCopyState::OnProgress(PRUint32 aProgress, PRUint32 aProgressMax)
07221 {
07222     return NS_ERROR_NOT_IMPLEMENTED;
07223 }
07224 
07225 /* void SetMessageKey (in PRUint32 aKey); */
07226 NS_IMETHODIMP nsImapFolderCopyState::SetMessageKey(PRUint32 aKey)
07227 {
07228     return NS_ERROR_NOT_IMPLEMENTED;
07229 }
07230 
07231 /* [noscript] void GetMessageId (in nsCString aMessageId); */
07232 NS_IMETHODIMP nsImapFolderCopyState::GetMessageId(nsCString * aMessageId)
07233 {
07234     return NS_ERROR_NOT_IMPLEMENTED;
07235 }
07236 
07237 /* void OnStopCopy (in nsresult aStatus); */
07238 NS_IMETHODIMP nsImapFolderCopyState::OnStopCopy(nsresult aStatus)
07239 {
07240   if (NS_SUCCEEDED(aStatus))
07241     return AdvanceToNextFolder(aStatus);
07242   if (m_copySrvcListener)
07243     (void) m_copySrvcListener->OnStopCopy(aStatus);
07244   delete this;
07245   return NS_OK;
07246 
07247 }
07248 
07249 // "this" is the parent of the copied folder.
07250 NS_IMETHODIMP
07251 nsImapMailFolder::CopyFolder(nsIMsgFolder* srcFolder,
07252                                PRBool isMoveFolder,
07253                                nsIMsgWindow *msgWindow,
07254                                nsIMsgCopyServiceListener* listener)
07255 {
07256 
07257   NS_ENSURE_ARG_POINTER(srcFolder);
07258   
07259   nsresult rv = NS_OK;
07260 
07261   if (isMoveFolder)   //move folder permitted when dstFolder and the srcFolder are on same server
07262   {
07263     PRUint32 folderFlags = 0;    
07264     if (srcFolder)
07265       srcFolder->GetFlags(&folderFlags);
07266     
07267     // if our source folder is a virtual folder
07268     if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL) 
07269     {
07270       nsCOMPtr<nsIMsgFolder> newMsgFolder;
07271       nsXPIDLString folderName;
07272       srcFolder->GetName(getter_Copies(folderName));
07273       
07274       nsCAutoString tempSafeFolderName;
07275       tempSafeFolderName.AssignWithConversion(folderName.get());
07276       NS_MsgHashIfNecessary(tempSafeFolderName);
07277       
07278       nsAutoString safeFolderName;
07279       safeFolderName.AssignWithConversion(tempSafeFolderName);  
07280       srcFolder->ForceDBClosed();   
07281   
07282       nsCOMPtr<nsIFileSpec> oldPathSpec;
07283       rv = srcFolder->GetPath(getter_AddRefs(oldPathSpec));
07284       NS_ENSURE_SUCCESS(rv,rv);
07285   
07286       nsFileSpec oldPath;
07287       rv = oldPathSpec->GetFileSpec(&oldPath);
07288       NS_ENSURE_SUCCESS(rv,rv);
07289   
07290       nsLocalFolderSummarySpec  summarySpec(oldPath);
07291   
07292       nsCOMPtr<nsIFileSpec> newPathSpec;
07293       rv = GetPath(getter_AddRefs(newPathSpec));
07294       NS_ENSURE_SUCCESS(rv,rv);
07295   
07296       nsFileSpec newPath;
07297       rv = newPathSpec->GetFileSpec(&newPath);
07298       NS_ENSURE_SUCCESS(rv,rv);
07299   
07300       if (!newPath.IsDirectory())
07301       {
07302         AddDirectorySeparator(newPath);
07303         newPath.CreateDirectory();
07304       }
07305   
07306       rv = CheckIfFolderExists(folderName.get(), this, msgWindow);
07307       if(NS_FAILED(rv)) 
07308         return rv;
07309   
07310       rv = summarySpec.CopyToDir(newPath);
07311       NS_ENSURE_SUCCESS(rv, rv);
07312   
07313       rv = AddSubfolder(safeFolderName, getter_AddRefs(newMsgFolder));  
07314       NS_ENSURE_SUCCESS(rv, rv);
07315 
07316       newMsgFolder->SetPrettyName(folderName.get());
07317   
07318       PRUint32 flags;
07319       srcFolder->GetFlags(&flags);
07320       newMsgFolder->SetFlags(flags);
07321       
07322       NotifyItemAdded(newMsgFolder);
07323 
07324       // now remove the old folder
07325       nsCOMPtr<nsIMsgFolder> msgParent;
07326       srcFolder->GetParentMsgFolder(getter_AddRefs(msgParent));
07327       srcFolder->SetParent(nsnull);
07328       if (msgParent) 
07329       {
07330         msgParent->PropagateDelete(srcFolder, PR_FALSE, msgWindow);  // The files have already been moved, so delete storage PR_FALSE 
07331         oldPath.Delete(PR_FALSE);  //berkeley mailbox
07332         nsCOMPtr <nsIMsgDatabase> srcDB; // we need to force closed the source db
07333         srcFolder->Delete();
07334 
07335         nsCOMPtr<nsIFileSpec> parentPathSpec;
07336         rv = msgParent->GetPath(getter_AddRefs(parentPathSpec));
07337         NS_ENSURE_SUCCESS(rv,rv);
07338   
07339         nsFileSpec parentPath;
07340         rv = parentPathSpec->GetFileSpec(&parentPath);
07341         NS_ENSURE_SUCCESS(rv,rv);
07342 
07343         AddDirectorySeparator(parentPath); 
07344         nsDirectoryIterator i(parentPath, PR_FALSE);
07345         // i.Exists() checks if the directory is empty or not 
07346         if (parentPath.IsDirectory() && !i.Exists())
07347           parentPath.Delete(PR_TRUE);
07348       }
07349     }
07350     else // non-virtual folder
07351     {
07352       nsCOMPtr <nsIImapService> imapService = do_GetService (NS_IMAPSERVICE_CONTRACTID, &rv);
07353       if (NS_SUCCEEDED(rv))
07354       {
07355         nsCOMPtr <nsIUrlListener> urlListener = do_QueryInterface(srcFolder);
07356         PRBool match = PR_FALSE;
07357         PRBool confirmed = PR_FALSE;
07358         if (mFlags & MSG_FOLDER_FLAG_TRASH)
07359         {
07360           rv = srcFolder->MatchOrChangeFilterDestination(nsnull, PR_FALSE, &match);
07361           if (match)
07362           {
07363             srcFolder->ConfirmFolderDeletionForFilter(msgWindow, &confirmed);
07364             // should we return an error to copy service?
07365             // or send a notification?
07366             if (!confirmed) 
07367               return NS_OK;
07368           }
07369         }
07370         rv = imapService->MoveFolder(m_eventQueue,
07371                                      srcFolder,
07372                                      this,
07373                                      urlListener,
07374                                      msgWindow,
07375                                      nsnull);
07376       }
07377     }
07378   }
07379   else // copying folder (should only be across server?)
07380   {
07381     nsImapFolderCopyState *folderCopier = new nsImapFolderCopyState(
07382       this, srcFolder, isMoveFolder, msgWindow, listener);
07383     NS_ADDREF(folderCopier); // it owns itself.
07384     return folderCopier->StartNextCopy();
07385   }
07386   return rv;
07387   
07388 }
07389 
07390 NS_IMETHODIMP
07391 nsImapMailFolder::CopyFileMessage(nsIFileSpec* fileSpec,
07392                                   nsIMsgDBHdr* msgToReplace,
07393                                   PRBool isDraftOrTemplate,
07394                                   PRUint32 aNewMsgFlags,
07395                                   nsIMsgWindow *msgWindow,
07396                                   nsIMsgCopyServiceListener* listener)
07397 {
07398     nsresult rv = NS_ERROR_NULL_POINTER;
07399     nsMsgKey key = 0xffffffff;
07400     nsCAutoString messageId;
07401     nsCOMPtr<nsIUrlListener> urlListener;
07402     nsCOMPtr<nsISupportsArray> messages;
07403     nsCOMPtr<nsISupports> srcSupport = do_QueryInterface(fileSpec, &rv);
07404 
07405     rv = NS_NewISupportsArray(getter_AddRefs(messages));
07406     if (NS_FAILED(rv)) 
07407       return OnCopyCompleted(srcSupport, rv);
07408 
07409     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
07410     if (NS_FAILED(rv)) 
07411       return OnCopyCompleted(srcSupport, rv);
07412 
07413     rv = QueryInterface(NS_GET_IID(nsIUrlListener), getter_AddRefs(urlListener));
07414 
07415     if (msgToReplace)
07416     {
07417         rv = msgToReplace->GetMessageKey(&key);
07418         if (NS_SUCCEEDED(rv))
07419             messageId.AppendInt((PRInt32) key);
07420     }
07421 
07422     rv = InitCopyState(srcSupport, messages, PR_FALSE, isDraftOrTemplate,
07423                        PR_FALSE, aNewMsgFlags, listener, msgWindow, PR_FALSE);
07424     if (NS_FAILED(rv)) 
07425       return OnCopyCompleted(srcSupport, rv);
07426 
07427     m_copyState->m_streamCopy = PR_TRUE;
07428 
07429     nsCOMPtr<nsISupports> copySupport;
07430     if( m_copyState ) 
07431         copySupport = do_QueryInterface(m_copyState);
07432     if (!isDraftOrTemplate)
07433       m_copyState->m_totalCount = 1;
07434     rv = imapService->AppendMessageFromFile(m_eventQueue, fileSpec, this,
07435                                             messageId.get(),
07436                                             PR_TRUE, isDraftOrTemplate,
07437                                             urlListener, nsnull,
07438                                             copySupport,
07439                                             msgWindow);
07440     if (NS_FAILED(rv))
07441       return OnCopyCompleted(srcSupport, rv);
07442 
07443     return rv;
07444 }
07445 
07446 nsresult 
07447 nsImapMailFolder::CopyStreamMessage(nsIMsgDBHdr* message,
07448                                     nsIMsgFolder* dstFolder, // should be this
07449                                     nsIMsgWindow *aMsgWindow,
07450                                     PRBool isMove)
07451 {
07452     nsresult rv = NS_ERROR_NULL_POINTER;
07453     if (!m_copyState) return rv;
07454 
07455     nsCOMPtr<nsICopyMessageStreamListener> copyStreamListener = do_CreateInstance(NS_COPYMESSAGESTREAMLISTENER_CONTRACTID, &rv);
07456     NS_ENSURE_SUCCESS(rv,rv);
07457 
07458     nsCOMPtr<nsICopyMessageListener>
07459         copyListener(do_QueryInterface(dstFolder, &rv));
07460     if (NS_FAILED(rv)) return rv;
07461 
07462     nsCOMPtr<nsIMsgFolder>
07463         srcFolder(do_QueryInterface(m_copyState->m_srcSupport, &rv));
07464     if (NS_FAILED(rv)) return rv;
07465     rv = copyStreamListener->Init(srcFolder, copyListener, nsnull);
07466     if (NS_FAILED(rv)) return rv;
07467        
07468     nsCOMPtr<nsIMsgDBHdr> msgHdr(do_QueryInterface(message));
07469     if (!msgHdr) return NS_ERROR_FAILURE;
07470 
07471     nsXPIDLCString uri;
07472     srcFolder->GetUriForMsg(msgHdr, getter_Copies(uri));
07473 
07474     if (!m_copyState->m_msgService)
07475         rv = GetMessageServiceFromURI(uri, getter_AddRefs(m_copyState->m_msgService));
07476 
07477     if (NS_SUCCEEDED(rv) && m_copyState->m_msgService)
07478     {
07479       nsCOMPtr<nsIStreamListener>
07480               streamListener(do_QueryInterface(copyStreamListener, &rv));
07481       if(NS_FAILED(rv) || !streamListener)
07482         return NS_ERROR_NO_INTERFACE;
07483 
07484       // put up status message here, if copying more than one message.
07485       if (m_copyState->m_totalCount > 1)
07486       {
07487         nsXPIDLString dstFolderName, progressText;
07488         GetName(getter_Copies(dstFolderName));
07489         nsAutoString curMsgString;
07490         nsAutoString totalMsgString;
07491         totalMsgString.AppendInt(m_copyState->m_totalCount);
07492         curMsgString.AppendInt(m_copyState->m_curIndex + 1);
07493     
07494         const PRUnichar *formatStrings[3] = {curMsgString.get(),
07495                                               totalMsgString.get(),
07496                                               dstFolderName.get()
07497                                               };
07498 
07499         nsCOMPtr <nsIStringBundle> bundle;
07500         rv = IMAPGetStringBundle(getter_AddRefs(bundle));
07501         NS_ENSURE_SUCCESS(rv, rv);
07502         rv = bundle->FormatStringFromID(IMAP_COPYING_MESSAGE_OF,
07503                                           formatStrings, 3,
07504                                           getter_Copies(progressText));
07505         nsCOMPtr <nsIMsgStatusFeedback> statusFeedback;
07506         if (m_copyState->m_msgWindow)
07507           m_copyState->m_msgWindow->GetStatusFeedback(getter_AddRefs(statusFeedback));
07508         if (statusFeedback)
07509         {
07510           statusFeedback->ShowStatusString(progressText);
07511           PRInt32 percent;
07512           percent = (100 * m_copyState->m_curIndex) / (PRInt32) m_copyState->m_totalCount;
07513           {
07514             statusFeedback->ShowProgress(percent);
07515           }
07516         }
07517       }
07518       rv = m_copyState->m_msgService->CopyMessage(uri, streamListener,
07519                                                      isMove && !m_copyState->m_isCrossServerOp, nsnull, aMsgWindow, nsnull);
07520   }
07521   return rv;
07522 }
07523 
07524 nsImapMailCopyState::nsImapMailCopyState() :
07525     m_isMove(PR_FALSE), m_selectedState(PR_FALSE),
07526     m_isCrossServerOp(PR_FALSE), m_curIndex(0),
07527     m_totalCount(0), m_streamCopy(PR_FALSE), m_dataBuffer(nsnull),
07528     m_dataBufferSize(0), m_leftOver(0), m_allowUndo(PR_FALSE), 
07529     m_eatLF(PR_FALSE), m_newMsgFlags(0)
07530 {
07531 }
07532 
07533 nsImapMailCopyState::~nsImapMailCopyState()
07534 {
07535     PR_Free(m_dataBuffer);
07536     if (m_msgService && m_message)
07537     {
07538       nsCOMPtr <nsIMsgFolder> srcFolder = do_QueryInterface(m_srcSupport);
07539       if (srcFolder)
07540       {
07541         nsXPIDLCString uri;
07542         srcFolder->GetUriForMsg(m_message, getter_Copies(uri));
07543       }
07544     }
07545     if (m_tmpFileSpec)
07546     {
07547         PRBool isOpen = PR_FALSE;
07548         nsFileSpec  fileSpec;
07549         if (isOpen)
07550             m_tmpFileSpec->CloseStream();
07551         m_tmpFileSpec->GetFileSpec(&fileSpec);
07552         if (fileSpec.Valid())
07553             fileSpec.Delete(PR_FALSE);
07554     }
07555 }
07556 
07557 
07558 NS_IMPL_THREADSAFE_ISUPPORTS1(nsImapMailCopyState, nsImapMailCopyState)
07559 
07560 nsresult
07561 nsImapMailFolder::InitCopyState(nsISupports* srcSupport,
07562                                 nsISupportsArray* messages,
07563                                 PRBool isMove,
07564                                 PRBool selectedState,
07565                                 PRBool acrossServers,
07566                                 PRUint32 newMsgFlags,
07567                                 nsIMsgCopyServiceListener* listener,
07568                                 nsIMsgWindow *msgWindow,
07569                                 PRBool allowUndo)
07570 {
07571     nsresult rv = NS_OK;
07572 
07573     if (!srcSupport || !messages) return NS_ERROR_NULL_POINTER;
07574     NS_ASSERTION(!m_copyState, "move/copy already in progress");
07575     if (m_copyState) return NS_ERROR_FAILURE;
07576 
07577     nsImapMailCopyState* copyState = new nsImapMailCopyState();
07578     m_copyState = do_QueryInterface(copyState);
07579 
07580     if (!m_copyState) 
07581       return NS_ERROR_OUT_OF_MEMORY;
07582 
07583     m_copyState->m_isCrossServerOp = acrossServers;
07584     if (srcSupport)
07585         m_copyState->m_srcSupport = do_QueryInterface(srcSupport, &rv);
07586 
07587     if (NS_SUCCEEDED(rv))
07588     {
07589       m_copyState->m_messages = do_QueryInterface(messages, &rv);
07590       rv = messages->Count(&m_copyState->m_totalCount);
07591       if (!m_copyState->m_isCrossServerOp)
07592       {
07593         if (NS_SUCCEEDED(rv))
07594         {
07595             PRUint32 numUnread = 0;
07596             for (PRUint32 keyIndex=0; keyIndex < m_copyState->m_totalCount; keyIndex++)
07597             {
07598               nsCOMPtr<nsIMsgDBHdr> message =
07599                   do_QueryElementAt(m_copyState->m_messages, keyIndex, &rv);
07600               // if the key is not there, then assume what the caller tells us to.
07601               PRBool isRead = PR_FALSE;
07602               PRUint32 flags;
07603               if (message )
07604               {
07605                 message->GetFlags(&flags);
07606                 isRead = flags & MSG_FLAG_READ;
07607               }
07608 
07609               if (!isRead)
07610                 numUnread++;
07611             }
07612             m_copyState->m_unreadCount = numUnread;
07613         }
07614       }
07615       else
07616       {
07617         nsCOMPtr<nsIMsgDBHdr> message =
07618             do_QueryElementAt(m_copyState->m_messages,
07619                               m_copyState->m_curIndex, &rv);
07620           // if the key is not there, then assume what the caller tells us to.
07621         PRBool isRead = PR_FALSE;
07622         PRUint32 flags;
07623         if (message )
07624         {
07625           message->GetFlags(&flags);
07626           isRead = flags & MSG_FLAG_READ;
07627         }
07628 
07629         m_copyState->m_unreadCount = (isRead) ? 0 : 1;
07630       }
07631     }
07632     m_copyState->m_isMove = isMove;
07633     m_copyState->m_newMsgFlags = newMsgFlags;
07634     m_copyState->m_allowUndo = allowUndo;
07635     m_copyState->m_selectedState = selectedState;
07636     m_copyState->m_msgWindow = msgWindow;
07637     if (listener)
07638         m_copyState->m_listener = do_QueryInterface(listener, &rv);
07639         
07640     return rv;
07641 }
07642 
07643 nsresult
07644 nsImapMailFolder::OnCopyCompleted(nsISupports *srcSupport, nsresult rv)
07645 {
07646   m_copyState = nsnull;
07647   nsresult result;
07648   nsCOMPtr<nsIMsgCopyService> copyService = 
07649     do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &result);
07650   if (NS_SUCCEEDED(result))
07651     copyService->NotifyCompletion(srcSupport, this, rv);    
07652   return NS_OK;
07653 }
07654 
07655 NS_IMETHODIMP nsImapMailFolder::MatchName(nsString *name, PRBool *matches)
07656 {
07657   if (!matches)
07658     return NS_ERROR_NULL_POINTER;
07659     PRBool isInbox = mName.LowerCaseEqualsLiteral("inbox");
07660     if (isInbox)
07661         *matches = mName.Equals(*name, nsCaseInsensitiveStringComparator());
07662     else
07663         *matches = mName.Equals(*name);
07664         
07665   return NS_OK;
07666 }
07667 
07668 nsresult nsImapMailFolder::CreateBaseMessageURI(const char *aURI)
07669 {
07670   return nsCreateImapBaseMessageURI(aURI, &mBaseMessageURI);
07671 }
07672 
07673 NS_IMETHODIMP nsImapMailFolder::GetFolderURL(char **aFolderURL)
07674 {
07675   NS_ENSURE_ARG_POINTER(aFolderURL);
07676   nsCOMPtr<nsIMsgFolder> rootFolder;
07677   nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
07678   NS_ENSURE_SUCCESS(rv, rv);
07679   nsXPIDLCString rootURI;
07680   rootFolder->GetURI(getter_Copies(rootURI));
07681 
07682   NS_ASSERTION(mURI.Length() > rootURI.Length(), "Should match with a folder name!");
07683   nsAdoptingCString escapedName(nsEscape(mURI.get() + rootURI.Length(),
07684                                          url_Path));
07685   if (escapedName.IsEmpty()) 
07686       return NS_ERROR_OUT_OF_MEMORY;
07687 
07688   *aFolderURL = ToNewCString(rootURI + escapedName);
07689   if (!*aFolderURL)
07690       return NS_ERROR_OUT_OF_MEMORY;
07691 
07692   return NS_OK;
07693 }
07694 
07695 
07696 NS_IMETHODIMP nsImapMailFolder::GetFolderNeedsSubscribing(PRBool *bVal)
07697 {
07698     if (!bVal)
07699         return NS_ERROR_NULL_POINTER;
07700     *bVal = m_folderNeedsSubscribing;
07701     return NS_OK;
07702 }
07703 
07704 NS_IMETHODIMP nsImapMailFolder::SetFolderNeedsSubscribing(PRBool bVal)
07705 {
07706     m_folderNeedsSubscribing = bVal;
07707     return NS_OK;
07708 }
07709 
07710 nsMsgIMAPFolderACL * nsImapMailFolder::GetFolderACL()
07711 {
07712   if (!m_folderACL)
07713     m_folderACL = new nsMsgIMAPFolderACL(this);
07714   return m_folderACL;
07715 }
07716 
07717 nsresult nsImapMailFolder::CreateACLRightsStringForFolder(PRUnichar **rightsString)
07718 {
07719   NS_ENSURE_ARG_POINTER(rightsString);
07720   GetFolderACL();    // lazy create
07721   if (m_folderACL)
07722   {
07723     return m_folderACL->CreateACLRightsString(rightsString);
07724   }
07725   return NS_ERROR_NULL_POINTER;
07726 }
07727 
07728 
07729 NS_IMETHODIMP nsImapMailFolder::GetFolderNeedsACLListed(PRBool *bVal)
07730 {
07731   NS_ENSURE_ARG_POINTER(bVal);
07732   PRBool dontNeedACLListed = !m_folderNeedsACLListed;
07733   // if we haven't acl listed, and it's not a no select folder or the inbox,
07734   //  then we'll list the acl if it's not a namespace.
07735   if (m_folderNeedsACLListed && !(mFlags & (MSG_FOLDER_FLAG_IMAP_NOSELECT | MSG_FOLDER_FLAG_INBOX)))
07736     GetIsNamespace(&dontNeedACLListed);
07737 
07738   *bVal = !dontNeedACLListed;
07739   return NS_OK;
07740 }
07741 
07742 NS_IMETHODIMP nsImapMailFolder::SetFolderNeedsACLListed(PRBool bVal)
07743 {
07744     m_folderNeedsACLListed = bVal;
07745     return NS_OK;
07746 }
07747 
07748 NS_IMETHODIMP nsImapMailFolder::GetIsNamespace(PRBool *aResult)
07749 {
07750   NS_ENSURE_ARG_POINTER(aResult);
07751   nsresult rv = NS_OK;
07752   if (!m_namespace)
07753   {
07754 #ifdef DEBUG_bienvenu
07755     // Make sure this isn't causing us to open the database
07756     NS_ASSERTION(m_hierarchyDelimiter != kOnlineHierarchySeparatorUnknown, "hierarchy delimiter not set");
07757 #endif
07758 
07759     nsXPIDLCString onlineName;
07760     nsXPIDLCString serverKey;
07761     GetServerKey(getter_Copies(serverKey));
07762     GetOnlineName(getter_Copies(onlineName));
07763     PRUnichar hierarchyDelimiter;
07764     GetHierarchyDelimiter(&hierarchyDelimiter);
07765 
07766     nsCOMPtr<nsIImapHostSessionList> hostSession = 
07767              do_GetService(kCImapHostSessionList, &rv);
07768 
07769     if (NS_SUCCEEDED(rv) && hostSession)
07770     {
07771       m_namespace = nsIMAPNamespaceList::GetNamespaceForFolder(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter);
07772       if (m_namespace == nsnull)
07773       {
07774         if (mFlags & MSG_FOLDER_FLAG_IMAP_OTHER_USER)
07775         {
07776            rv = hostSession->GetDefaultNamespaceOfTypeForHost(serverKey.get(), kOtherUsersNamespace, m_namespace);
07777         }
07778         else if (mFlags & MSG_FOLDER_FLAG_IMAP_PUBLIC)
07779         {
07780           rv = hostSession->GetDefaultNamespaceOfTypeForHost(serverKey.get(), kPublicNamespace, m_namespace);
07781         }
07782         else 
07783         {
07784           rv = hostSession->GetDefaultNamespaceOfTypeForHost(serverKey.get(), kPersonalNamespace, m_namespace);
07785         }
07786       }
07787       NS_ASSERTION(m_namespace, "failed to get namespace");
07788       if (m_namespace)
07789       {
07790         nsIMAPNamespaceList::SuggestHierarchySeparatorForNamespace(m_namespace, (char) hierarchyDelimiter);
07791         m_folderIsNamespace = nsIMAPNamespaceList::GetFolderIsNamespace(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter, m_namespace);
07792       }
07793     }
07794   } 
07795   *aResult = m_folderIsNamespace;
07796   return rv;
07797 }
07798 
07799 NS_IMETHODIMP nsImapMailFolder::SetIsNamespace(PRBool isNamespace)
07800 {
07801   m_folderIsNamespace = isNamespace;
07802   return NS_OK;
07803 }
07804 
07805 NS_IMETHODIMP nsImapMailFolder::ResetNamespaceReferences()
07806 {
07807   nsXPIDLCString serverKey;
07808   nsXPIDLCString onlineName;
07809   GetServerKey(getter_Copies(serverKey));
07810   GetOnlineName(getter_Copies(onlineName));
07811   PRUnichar hierarchyDelimiter;
07812   GetHierarchyDelimiter(&hierarchyDelimiter);
07813   m_namespace = nsIMAPNamespaceList::GetNamespaceForFolder(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter);
07814 //  NS_ASSERTION(m_namespace, "resetting null namespace");
07815   if (m_namespace)
07816     m_folderIsNamespace = nsIMAPNamespaceList::GetFolderIsNamespace(serverKey.get(), onlineName.get(), (char) hierarchyDelimiter, m_namespace);
07817   else
07818     m_folderIsNamespace = PR_FALSE;
07819   
07820   nsCOMPtr<nsIEnumerator> aEnumerator;
07821   GetSubFolders(getter_AddRefs(aEnumerator));
07822   if (!aEnumerator)
07823     return NS_OK;
07824   nsCOMPtr<nsISupports> aSupport;
07825   nsresult rv = aEnumerator->First();
07826   while (NS_SUCCEEDED(rv))
07827   {
07828      rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
07829                      
07830      nsCOMPtr<nsIMsgImapMailFolder> folder = do_QueryInterface(aSupport, &rv);
07831      if (NS_FAILED(rv)) return rv;
07832      folder->ResetNamespaceReferences();
07833      rv = aEnumerator->Next();
07834   }
07835   return rv;
07836 }
07837 
07838 NS_IMETHODIMP nsImapMailFolder::FindOnlineSubFolder(const char *targetOnlineName, nsIMsgImapMailFolder **aResultFolder)
07839 {
07840   nsresult rv = NS_OK;
07841 
07842   nsXPIDLCString onlineName;
07843   GetOnlineName(getter_Copies(onlineName));
07844 
07845   if (onlineName.Equals(targetOnlineName))
07846   {
07847     return QueryInterface(NS_GET_IID(nsIMsgImapMailFolder), (void **) aResultFolder);
07848   }
07849   nsCOMPtr<nsIEnumerator> aEnumerator;
07850   GetSubFolders(getter_AddRefs(aEnumerator));
07851   if (!aEnumerator)
07852     return NS_OK;
07853   nsCOMPtr<nsISupports> aSupport;
07854   rv = aEnumerator->First();
07855   while (NS_SUCCEEDED(rv))
07856   {
07857      rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
07858                      
07859      nsCOMPtr<nsIMsgImapMailFolder> folder = do_QueryInterface(aSupport, &rv);
07860      if (NS_FAILED(rv)) return rv;
07861      rv = folder->FindOnlineSubFolder(targetOnlineName, aResultFolder);
07862      if (*aResultFolder)
07863        return rv;
07864      rv = aEnumerator->Next();
07865   }
07866   return rv;
07867 }
07868 
07869 NS_IMETHODIMP nsImapMailFolder::GetFolderNeedsAdded(PRBool *bVal)
07870 {
07871     if (!bVal)
07872         return NS_ERROR_NULL_POINTER;
07873     *bVal = m_folderNeedsAdded;
07874     return NS_OK;
07875 }
07876 
07877 NS_IMETHODIMP nsImapMailFolder::SetFolderNeedsAdded(PRBool bVal)
07878 {
07879     m_folderNeedsAdded = bVal;
07880     return NS_OK;
07881 }
07882 
07883 NS_IMETHODIMP nsImapMailFolder::GetFolderQuotaCommandIssued(PRBool *aCmdIssued)
07884 {
07885     NS_ENSURE_ARG_POINTER(aCmdIssued);
07886     *aCmdIssued = m_folderQuotaCommandIssued;
07887     return NS_OK;
07888 }
07889 
07890 NS_IMETHODIMP nsImapMailFolder::SetFolderQuotaCommandIssued(PRBool aCmdIssued)
07891 {
07892     m_folderQuotaCommandIssued = aCmdIssued;
07893     return NS_OK;
07894 }
07895 
07896 NS_IMETHODIMP nsImapMailFolder::SetFolderQuotaData(const nsACString &aFolderQuotaRoot, 
07897                                                    PRUint32 aFolderQuotaUsedKB, 
07898                                                     PRUint32 aFolderQuotaMaxKB)
07899 {
07900   m_folderQuotaDataIsValid = PR_TRUE;
07901   m_folderQuotaRoot = aFolderQuotaRoot;
07902   m_folderQuotaUsedKB = aFolderQuotaUsedKB;
07903   m_folderQuotaMaxKB = aFolderQuotaMaxKB;
07904   return NS_OK;
07905 }
07906 
07907 NS_IMETHODIMP nsImapMailFolder::GetQuota(PRBool* aValid,
07908                                          PRUint32* aUsed, PRUint32* aMax)
07909 {
07910   NS_ENSURE_ARG_POINTER(aValid);
07911   NS_ENSURE_ARG_POINTER(aUsed);
07912   NS_ENSURE_ARG_POINTER(aMax);
07913   *aValid = m_folderQuotaDataIsValid;
07914   *aUsed = m_folderQuotaUsedKB;
07915   *aMax = m_folderQuotaMaxKB;
07916   return NS_OK;
07917 }
07918 
07919 NS_IMETHODIMP nsImapMailFolder::PerformExpand(nsIMsgWindow *aMsgWindow)
07920 {
07921     nsresult rv;
07922     PRBool usingSubscription = PR_FALSE;
07923     nsCOMPtr<nsIImapIncomingServer> imapServer;
07924     rv = GetImapIncomingServer(getter_AddRefs(imapServer));
07925 
07926     if (NS_FAILED(rv) || !imapServer) return NS_ERROR_FAILURE;
07927     rv = imapServer->GetUsingSubscription(&usingSubscription);
07928     if (NS_SUCCEEDED(rv) && !usingSubscription)
07929     {
07930         nsCOMPtr<nsIImapService> imapService = 
07931                  do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
07932         if (NS_SUCCEEDED(rv))
07933             rv = imapService->DiscoverChildren(m_eventQueue, this, this,
07934                                                m_onlineFolderName.get(),
07935                                                nsnull);
07936     }
07937     return rv;
07938 }
07939 
07940 NS_IMETHODIMP nsImapMailFolder::RenameClient(nsIMsgWindow *msgWindow, nsIMsgFolder *msgFolder, const char* oldName, const char* newName )
07941 {
07942     nsresult rv = NS_OK;
07943     nsCOMPtr<nsIFileSpec> pathSpec;
07944     rv = GetPath(getter_AddRefs(pathSpec));
07945     if (NS_FAILED(rv)) return rv;
07946 
07947     nsFileSpec path;
07948     rv = pathSpec->GetFileSpec(&path);
07949     if (NS_FAILED(rv)) return rv;
07950 
07951     nsCOMPtr<nsIMsgImapMailFolder> oldImapFolder = do_QueryInterface(msgFolder, &rv);
07952     if (NS_FAILED(rv)) return rv;
07953 
07954     PRUnichar hierarchyDelimiter = '/';
07955     oldImapFolder->GetHierarchyDelimiter(&hierarchyDelimiter);
07956     PRInt32 boxflags=0;
07957     oldImapFolder->GetBoxFlags(&boxflags);
07958 
07959     nsAutoString newLeafName;
07960        nsAutoString newNameString;
07961     newNameString.AssignWithConversion(newName);
07962        newLeafName = newNameString;
07963        nsAutoString parentName; 
07964     nsAutoString folderNameStr;
07965     PRInt32 folderStart = newLeafName.RFindChar('/');  //internal use of hierarchyDelimiter is always '/'
07966     if (folderStart > 0)
07967     {
07968       newNameString.Right(newLeafName, newLeafName.Length() - folderStart - 1);
07969       CreateDirectoryForFolder(path);    //needed when we move a folder to a folder with no subfolders.
07970     }  
07971 
07972     // if we get here, it's really a leaf, and "this" is the parent.
07973     folderNameStr = newLeafName;
07974     
07975     // Create an empty database for this mail folder, set its name from the user  
07976     nsCOMPtr<nsIMsgDatabase> mailDBFactory;
07977     nsCOMPtr<nsIMsgFolder> child;
07978     nsCOMPtr <nsIMsgImapMailFolder> imapFolder;
07979 
07980     nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID);
07981     if (msgDBService)
07982     {
07983       nsCOMPtr<nsIMsgDatabase> unusedDB;
07984       nsCOMPtr <nsIFileSpec> dbFileSpec;
07985 
07986       nsCAutoString proposedDBName;
07987       proposedDBName.AssignWithConversion(newLeafName);
07988 
07989       // warning, path will be changed
07990       rv = CreateFileSpecForDB(proposedDBName.get(), path, getter_AddRefs(dbFileSpec));
07991       NS_ENSURE_SUCCESS(rv,rv);
07992 
07993       // it's OK to use openMailDBFromFileSpec and not OpenFolderDB here, since we don't use the DB.
07994       rv = msgDBService->OpenMailDBFromFileSpec(dbFileSpec, PR_TRUE, PR_TRUE, (nsIMsgDatabase **) getter_AddRefs(unusedDB));
07995 
07996       if (NS_SUCCEEDED(rv) && unusedDB)
07997       {
07998         //need to set the folder name
07999         nsCOMPtr <nsIDBFolderInfo> folderInfo;
08000         rv = unusedDB->GetDBFolderInfo(getter_AddRefs(folderInfo));
08001 
08002         //Now let's create the actual new folder
08003         rv = AddSubfolderWithPath(folderNameStr, dbFileSpec, getter_AddRefs(child));
08004         if (!child || NS_FAILED(rv)) return rv;
08005         nsXPIDLString unicodeName;
08006         rv = CopyMUTF7toUTF16(proposedDBName, unicodeName);
08007         if (NS_SUCCEEDED(rv))
08008           child->SetName(unicodeName);
08009         imapFolder = do_QueryInterface(child);
08010 
08011         if (imapFolder)
08012         {
08013           nsCAutoString onlineName(m_onlineFolderName); 
08014           if (!onlineName.IsEmpty())
08015           onlineName.Append(char(hierarchyDelimiter));
08016           onlineName.AppendWithConversion(folderNameStr);
08017           imapFolder->SetVerifiedAsOnlineFolder(PR_TRUE);
08018           imapFolder->SetOnlineName(onlineName.get());
08019           imapFolder->SetHierarchyDelimiter(hierarchyDelimiter);
08020           imapFolder->SetBoxFlags(boxflags);
08021 
08022         // store the online name as the mailbox name in the db folder info
08023         // I don't think anyone uses the mailbox name, so we'll use it
08024         // to restore the online name when blowing away an imap db.
08025            if (folderInfo)
08026            {
08027              nsAutoString unicodeOnlineName; unicodeOnlineName.AssignWithConversion(onlineName.get());
08028              folderInfo->SetMailboxName(unicodeOnlineName);
08029            }
08030            PRBool changed = PR_FALSE;
08031            msgFolder->MatchOrChangeFilterDestination(child, PR_FALSE /*caseInsensitive*/, &changed);
08032            if (changed)
08033              msgFolder->AlertFilterChanged(msgWindow);
08034         }
08035         unusedDB->SetSummaryValid(PR_TRUE);
08036         unusedDB->Commit(nsMsgDBCommitType::kLargeCommit);
08037         unusedDB->Close(PR_TRUE);
08038 
08039         child->RenameSubFolders(msgWindow, msgFolder);
08040        
08041         nsCOMPtr<nsIMsgFolder> msgParent;
08042         msgFolder->GetParentMsgFolder(getter_AddRefs(msgParent));
08043         msgFolder->SetParent(nsnull);
08044         msgParent->PropagateDelete(msgFolder, PR_TRUE, nsnull);
08045 
08046         // Reset online status now that the folder is renamed.
08047         nsCOMPtr <nsIMsgImapMailFolder> oldImapFolder = do_QueryInterface(msgFolder);
08048         if (oldImapFolder)
08049           oldImapFolder->SetVerifiedAsOnlineFolder(PR_FALSE);
08050 
08051         NotifyItemAdded(child);
08052       }
08053     }     
08054     return rv;
08055 }
08056 
08057 NS_IMETHODIMP nsImapMailFolder::RenameSubFolders(nsIMsgWindow *msgWindow, nsIMsgFolder *oldFolder)
08058 {
08059   nsresult rv = NS_OK;
08060   m_initialized = PR_TRUE;
08061   nsCOMPtr<nsIEnumerator> aEnumerator;
08062   oldFolder->GetSubFolders(getter_AddRefs(aEnumerator));
08063   nsCOMPtr<nsISupports> aSupport;
08064   rv = aEnumerator->First();
08065   while (NS_SUCCEEDED(rv))
08066   {
08067      rv = aEnumerator->CurrentItem(getter_AddRefs(aSupport));
08068                      
08069      nsCOMPtr<nsIMsgFolder>msgFolder = do_QueryInterface(aSupport);
08070      nsCOMPtr<nsIMsgImapMailFolder> folder = do_QueryInterface(msgFolder, &rv);
08071      if (NS_FAILED(rv)) return rv;
08072 
08073      PRUnichar hierarchyDelimiter = '/';
08074      folder->GetHierarchyDelimiter(&hierarchyDelimiter);
08075                             
08076      PRInt32 boxflags;
08077      folder->GetBoxFlags(&boxflags);
08078 
08079      PRBool verified;
08080      folder->GetVerifiedAsOnlineFolder(&verified);
08081                             
08082      nsCOMPtr<nsIFileSpec> oldPathSpec;
08083      rv = msgFolder->GetPath(getter_AddRefs(oldPathSpec));
08084      if (NS_FAILED(rv)) return rv;
08085 
08086      nsFileSpec oldPath;
08087      rv = oldPathSpec->GetFileSpec(&oldPath);
08088      if (NS_FAILED(rv)) return rv;
08089 
08090      nsCOMPtr<nsIFileSpec> newParentPathSpec;
08091      rv = GetPath(getter_AddRefs(newParentPathSpec));
08092      if (NS_FAILED(rv)) return rv;
08093 
08094      nsFileSpec newParentPath;
08095      rv = newParentPathSpec->GetFileSpec(&newParentPath);
08096      if (NS_FAILED(rv)) return rv;
08097 
08098      rv = AddDirectorySeparator(newParentPath);
08099      newParentPath += oldPath.GetLeafName();
08100      nsCString newPathStr(newParentPath.GetNativePathCString());
08101      nsCOMPtr<nsIFileSpec> newPathSpec;
08102      rv = NS_NewFileSpec(getter_AddRefs(newPathSpec));
08103      if (NS_FAILED(rv)) return rv;
08104      rv = newPathSpec->SetNativePath(newPathStr.get());
08105                 
08106      nsFileSpec newPath;
08107      rv = newPathSpec->GetFileSpec(&newPath);
08108      if (NS_FAILED(rv)) return rv;
08109 
08110      nsCOMPtr<nsIFileSpec> dbFileSpec;
08111      NS_NewFileSpecWithSpec(newPath, getter_AddRefs(dbFileSpec));
08112 
08113      nsCOMPtr<nsIMsgFolder> child;
08114                             
08115      nsXPIDLString folderName;
08116      rv = msgFolder->GetName(getter_Copies(folderName));
08117      if (folderName.IsEmpty() || NS_FAILED(rv)) return rv;
08118 
08119      nsXPIDLCString utf7LeafName;
08120      rv = CopyUTF16toMUTF7(folderName, utf7LeafName);
08121      NS_ENSURE_SUCCESS(rv, rv);
08122 
08123      // XXX : Fix this non-sense by fixing AddSubfolderWithPath
08124      nsAutoString unicodeLeafName;
08125      CopyASCIItoUTF16(utf7LeafName, unicodeLeafName);
08126 
08127      rv = AddSubfolderWithPath(unicodeLeafName, dbFileSpec, getter_AddRefs(child));
08128      
08129      if (!child || NS_FAILED(rv))