diff --git a/mozilla/mailnews/base/public/nsIMessenger.idl b/mozilla/mailnews/base/public/nsIMessenger.idl index fd904a722a7..1d1e9fc9781 100644 --- a/mozilla/mailnews/base/public/nsIMessenger.idl +++ b/mozilla/mailnews/base/public/nsIMessenger.idl @@ -61,7 +61,11 @@ interface nsIMessenger : nsISupports { in nsIRDFResource dstFolder, in nsISupportsArray messages, in boolean isMove); - + void CopyFolders(in nsIRDFCompositeDataSource database, + in nsIRDFResource dstFolder, + in nsISupportsArray folders, + in boolean isMoveFolder); + void OpenURL(in string url); void RenameFolder(in nsIRDFCompositeDataSource db, in nsIRDFResource folder, in wstring name); diff --git a/mozilla/mailnews/base/public/nsIMsgCopyService.idl b/mozilla/mailnews/base/public/nsIMsgCopyService.idl index b36464f0c2b..c17d1729e40 100644 --- a/mozilla/mailnews/base/public/nsIMsgCopyService.idl +++ b/mozilla/mailnews/base/public/nsIMsgCopyService.idl @@ -51,7 +51,13 @@ interface nsIMsgCopyService : nsISupports { /** * */ - void CopyFileMessage(in nsIFileSpec fileSpec, + void CopyFolders( in nsISupportsArray folders, + in nsIMsgFolder dstFolder, + in boolean isMove, + in nsIMsgCopyServiceListener listener, + in nsIMsgWindow msgWindow); + + void CopyFileMessage(in nsIFileSpec fileSpec, in nsIMsgFolder dstFolder, in nsIMessage msgToReplace, in boolean isDraftOrTemplate, diff --git a/mozilla/mailnews/base/public/nsIMsgFolder.idl b/mozilla/mailnews/base/public/nsIMsgFolder.idl index 1070d84989f..d16a7160e58 100644 --- a/mozilla/mailnews/base/public/nsIMsgFolder.idl +++ b/mozilla/mailnews/base/public/nsIMsgFolder.idl @@ -284,7 +284,10 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne void copyMessages(in nsIMsgFolder srcFolder, in nsISupportsArray messages, in boolean isMove, in nsIMsgWindow msgWindow, - in nsIMsgCopyServiceListener listener); + in nsIMsgCopyServiceListener listener, in boolean isFolder); + + void copyFolder(in nsIMsgFolder srcFolder, in boolean isMoveFolder, + in nsIMsgWindow msgWindow, in nsIMsgCopyServiceListener listener ); void copyFileMessage(in nsIFileSpec fileSpec, in nsIMessage msgToReplace, in boolean isDraft, in nsIMsgWindow msgWindow, diff --git a/mozilla/mailnews/base/resources/content/commandglue.js b/mozilla/mailnews/base/resources/content/commandglue.js index 6ff7c974b42..aa1d7ded0a7 100644 --- a/mozilla/mailnews/base/resources/content/commandglue.js +++ b/mozilla/mailnews/base/resources/content/commandglue.js @@ -86,10 +86,6 @@ function LoadMessageByUri(uri) function ChangeFolderByDOMNode(folderNode) { - if (folderNode.getAttribute('NoSelect') == "true" ) { - ClearThreadPane(); - return; - } var uri = folderNode.getAttribute('id'); dump(uri + "\n"); diff --git a/mozilla/mailnews/base/resources/content/messengerdnd.js b/mozilla/mailnews/base/resources/content/messengerdnd.js index 1588ad2b8d4..d0764ebc89e 100644 --- a/mozilla/mailnews/base/resources/content/messengerdnd.js +++ b/mozilla/mailnews/base/resources/content/messengerdnd.js @@ -23,6 +23,7 @@ */ var ctrlKeydown = false; +var gSrcCanRename; function debugDump(msg) { @@ -50,13 +51,15 @@ function GetRDFService() function DragOverTree(event) { - if (event.target.localName != "treecell" && - event.target.localName != "treeitem") { - event.preventBubble(); - return false; - } + if (event.target.localName != "treecell" && + event.target.localName != "treeitem") { + event.preventBubble(); + return false; + } + + var msgFlavor = false; + var folderFlavor = false; - var validFlavor = false; var dragSession = null; var dragService = GetDragService(); @@ -65,47 +68,143 @@ function DragOverTree(event) dragSession = dragService.getCurrentSession(); if ( !dragSession ) return(false); - if ( dragSession.isDataFlavorSupported("text/nsmessage") ) validFlavor = true; + if ( dragSession.isDataFlavorSupported("text/nsmessage") ) msgFlavor = true; + if ( dragSession.isDataFlavorSupported("text/nsfolder") ) folderFlavor = true; + + var treeItem = event.target.parentNode.parentNode; + if (!treeItem) return(false); + + var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); + if ( !trans ) return(false); + + + if (msgFlavor) + { + var isServer = treeItem.getAttribute("IsServer"); + if (isServer == "true") + { + debugDump("***isServer == true\n"); + return(false); + } + var canFileMessages = treeItem.getAttribute("CanFileMessages"); + if (canFileMessages != "true") + { + debugDump("***canFileMessages == false\n"); + return(false); + } + var noSelect = treeItem.getAttribute("NoSelect"); + if (noSelect == "true") + { + debugDump("***NoSelect == true\n"); + return(false); + + } + + } + + if (folderFlavor) + { + debugDump("***isFolderFlavor == true \n"); + + if (event.ctrlKey) //ctrlkey does not apply to folder drag + return(false); + + var canCreateSubfolders = treeItem.getAttribute('CanCreateSubfolders'); + if ( canCreateSubfolders == "false") // if cannot create subfolders then a folder cannot be dropped here + { + debugDump("***canCreateSubfolders == false \n"); + return(false); + } + var serverType = treeItem.getAttribute('ServerType'); + if ( serverType != "none" && gSrcCanRename == "false") + { //folders that cannot be renamed can be dropped only on local folders. + return(false); + } + + var targetID = treeItem.getAttribute("id"); + var targetNode = RDF.GetResource(targetID, true); + if (!targetNode) return(false); + var targetfolder = targetNode.QueryInterface(Components.interfaces.nsIMsgFolder); + var targetServer = targetfolder.server; + + trans.addDataFlavor("text/nsfolder"); + + for ( var i = 0; i < dragSession.numDropItems; ++i ) + { + dragSession.getData ( trans, i ); + var dataObj = new Object(); + var bestFlavor = new Object(); + var len = new Object(); + trans.getAnyTransferData ( bestFlavor, dataObj, len ); + if ( dataObj ) dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsWString); + if ( !dataObj ) continue; + + // pull the URL out of the data object + var sourceID = dataObj.data.substring(0, len.value); + if (!sourceID) continue; + + var sourceNode = RDF.GetResource(sourceID, true); + var folder = sourceNode.QueryInterface(Components.interfaces.nsIFolder); + var sourceResource = folder.QueryInterface(Components.interfaces.nsIRDFResource); + var sourcefolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder); + var sourceServer = sourcefolder.server; + + if (sourceNode == targetNode) + return (false); + + if (sourceServer != targetServer && targetServer.type == "imap") //don't allow drop on different imap servers. + return (false); + + if (targetfolder.URI == sourcefolder.parent.URI) //don't allow immediate child to be dropped to it's parent + { + debugDump(targetfolder.URI + "\n"); + debugDump(sourcefolder.parent.URI + "\n"); + return (false); + } + + var isAncestor = sourcefolder.isAncestorOf(targetfolder); + if (isAncestor) // don't allow parent to be dropped on its ancestors + return (false); + + } + } + //XXX other flavors here... // touch the attribute on the treeItem to trigger the repaint with the drop feedback // (recall that it is two levels above the target, which is a treeCell). - if ( validFlavor ) + if ( msgFlavor || folderFlavor ) { - //XXX this is really slow and likes to refresh N times per second. - event.target.parentNode.parentNode.setAttribute ( "dd-triggerrepaint", 0 ); - dragSession.canDrop = true; - event.preventBubble(); // do not propagate message - return true; + //XXX this is really slow and likes to refresh N times per second. + event.target.parentNode.parentNode.setAttribute ( "dd-triggerrepaint", 0 ); + dragSession.canDrop = true; + event.preventBubble(); // do not propagate message + return true; } return false; } -function BeginDragFolderTree(event) +function BeginDragTree(event, tree, flavor) { - debugDump("BeginDragFolderTree\n"); - if (event.target.localName != "treecell" && - event.target.localName != "treeitem") - return false; - return(false); -} - -function BeginDragThreadTree(event) -{ - debugDump("BeginDragThreadTree\n"); - if (event.target.localName != "treecell" && - event.target.localName != "treeitem") - return false; - - //XXX we rely on a capturer to already have determined which item the mouse was over - //XXX and have set an attribute. - - // if the click is on the tree proper, ignore it. We only care about clicks on items. - - var tree = GetThreadTree(); if ( event.target == tree ) - return(true); // continue propagating the event + return(true); // continue propagating the event + var treeItem = event.target.parentNode.parentNode; + if (!treeItem) return(false); + + if (flavor == "text/nsfolder") + { + + gSrcCanRename = treeItem.getAttribute('CanRename'); //used in DragOverTree + + var serverType = treeItem.getAttribute('ServerType') // do not allow the drag when news is the source + if ( serverType == "nntp") + { + debugDump("***serverType == nntp \n"); + return(false); + } + } + var childWithDatabase = tree; if ( ! childWithDatabase ) return(false); @@ -114,11 +213,6 @@ function BeginDragThreadTree(event) var rdf = GetRDFService(); if ((!rdf) || (!database)) { debugDump("CAN'T GET DATABASE\n"); return(false); } - if (event.ctrlKey) - ctrlKeydown = true; - else - ctrlKeydown = false; - var dragStarted = false; var dragService = GetDragService(); @@ -132,20 +226,21 @@ function BeginDragThreadTree(event) debugDump("selArray.length = " + count + "\n"); for ( var i = 0; i < count; ++i ) { + var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if ( !trans ) return(false); var genTextData = Components.classes["@mozilla.org/supports-wstring;1"].createInstance(Components.interfaces.nsISupportsWString); if (!genTextData) return(false); - trans.addDataFlavor("text/nsmessage"); + trans.addDataFlavor(flavor); // get id (url) var id = selArray[i].getAttribute("id"); genTextData.data = id; debugDump(" ID #" + i + " = " + id + "\n"); - trans.setTransferData ( "text/nsmessage", genTextData, id.length * 2 ); // doublebyte byte data + trans.setTransferData ( flavor, genTextData, id.length * 2 ); // doublebyte byte data // put it into the transferable as an |nsISupports| var genTrans = trans.QueryInterface(Components.interfaces.nsISupports); @@ -154,12 +249,44 @@ function BeginDragThreadTree(event) var nsIDragService = Components.interfaces.nsIDragService; dragService.invokeDragSession ( event.target, transArray, null, nsIDragService.DRAGDROP_ACTION_COPY + - nsIDragService.DRAGDROP_ACTION_MOVE ); + nsIDragService.DRAGDROP_ACTION_MOVE ); + dragStarted = true; return(!dragStarted); // don't propagate the event if a drag has begun } +function BeginDragFolderTree(event) +{ + debugDump("BeginDragFolderTree\n"); + if (event.target.localName != "treecell" && + event.target.localName != "treeitem") + return false; + + var tree = GetFolderTree(); + + return BeginDragTree(event, tree, "text/nsfolder"); + +} + + +function BeginDragThreadTree(event) +{ + debugDump("BeginDragThreadTree\n"); + if (event.target.localName != "treecell" && + event.target.localName != "treeitem") + return false; + + //XXX we rely on a capturer to already have determined which item the mouse was over + //XXX and have set an attribute. + + // if the click is on the tree proper, ignore it. We only care about clicks on items. + + var tree = GetThreadTree(); + + return BeginDragTree(event, tree, "text/nsmessage"); +} + function DropOnFolderTree(event) { debugDump("DropOnTree\n"); @@ -196,24 +323,6 @@ function DropOnFolderTree(event) debugDump("***targetID = " + targetID + "\n"); //make sure target is a folder - var isServer = treeItem.getAttribute("IsServer"); - if (isServer == "true") - { - debugDump("***isServer == true\n"); - return(false); - } - var canFileMessages = treeItem.getAttribute("CanFileMessages"); - if (canFileMessages != "true") - { - debugDump("***canFileMessages == false\n"); - return(false); - } - var noSelect = treeItem.getAttribute("NoSelect"); - if (noSelect == "true") - { - debugDump("***NoSelect == true\n"); - return(false); - } var dragService = GetDragService(); if ( !dragService ) return(false); @@ -223,11 +332,29 @@ function DropOnFolderTree(event) var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if ( !trans ) return(false); - trans.addDataFlavor("text/nsmessage"); - var isNews = false; - var messageList = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray); + var list = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray); + var dropMessage = false; + if (dragSession.isDataFlavorSupported("text/nsmessage")) + { + dropMessage = true; + debugDump( "dropMessage == true \n"); + } + + var dropFolder = false; + if (dragSession.isDataFlavorSupported("text/nsfolder")) + { + dropFolder = true; + debugDump( "dropFolder == true \n"); + } + + if ( dropMessage ) + trans.addDataFlavor("text/nsmessage"); + else if ( dropFolder ) + trans.addDataFlavor("text/nsfolder"); + + var listCount =0; for ( var i = 0; i < dragSession.numDropItems; ++i ) { dragSession.getData ( trans, i ); @@ -248,64 +375,97 @@ function DropOnFolderTree(event) var sourceNode = RDF.GetResource(sourceID, true); if (!sourceNode) continue; - - // Prevent dropping of a node before, after, or on itself - if (sourceNode == targetNode) continue; - messageList.AppendElement(sourceNode); + // Prevent dropping of a node before, after, or on itself + if (sourceNode == targetNode) + continue; + else + listCount ++; + + list.AppendElement(sourceNode); } - isNews = isNewsURI(sourceID); + if (listCount < 1) + return false; + var isSourceNews = false; + isSourceNews = isNewsURI(sourceID); + var targetNode = RDF.GetResource(targetID, true); if (!targetNode) return(false); var targetfolder = targetNode.QueryInterface(Components.interfaces.nsIMsgFolder); var targetServer = targetfolder.server; - var message = sourceNode.QueryInterface(Components.interfaces.nsIMessage); - var folder = message.msgFolder; - var sourceRescource = folder.QueryInterface(Components.interfaces.nsIRDFResource); - var sourcefolder = sourceRescource.QueryInterface(Components.interfaces.nsIMsgFolder); - var sourceServer = sourcefolder.server; - var nextMessage; - var messageTree; + if (dropMessage) + { + var message = sourceNode.QueryInterface(Components.interfaces.nsIMessage); + var folder = message.msgFolder; + var sourceResource = folder.QueryInterface(Components.interfaces.nsIRDFResource); + var sourcefolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder); + var sourceServer = sourcefolder.server; + var nextMessage; + var messageTree; - if (isNews) //news to pop or imap is always a copy - { - try - { - messenger.CopyMessages(treeDatabase, - sourceRescource, - targetNode, messageList, false); - } - catch(e) - { - dump ( "Exception : CopyMessages \n"); - } - } - else - { + if (isSourceNews) //news to pop or imap is always a copy + { + try + { + messenger.CopyMessages(treeDatabase, + sourceResource, + targetNode, list, false); + } + catch(e) + { + dump ( "Exception : CopyMessages \n"); + } + } + else + { //temperary for single mail window, not working when supporting multiple mail windows - if (!ctrlKeydown) - { - messageTree = GetThreadTree(); - nextMessage = GetNextMessageAfterDelete(messageTree.selectedItems); - if(nextMessage) - gNextMessageAfterDelete = nextMessage.getAttribute('id'); - else - gNextMessageAfterDelete = null; - } - try { - messenger.CopyMessages(treeDatabase, - sourceRescource, - targetNode, messageList, !ctrlKeydown); - } - catch(e) - { - gNextMessageAfterDelete = null; - dump ( "Exception : CopyMessages \n"); - } + if (!ctrlKeydown) + { + messageTree = GetThreadTree(); + nextMessage = GetNextMessageAfterDelete(messageTree.selectedItems); + if(nextMessage) + gNextMessageAfterDelete = nextMessage.getAttribute('id'); + else + gNextMessageAfterDelete = null; + } + try { + messenger.CopyMessages(treeDatabase, + sourceResource, + targetNode, list, !ctrlKeydown); + } + catch(e) + { + gNextMessageAfterDelete = null; + dump ( "Exception : CopyMessages \n"); + } + } + } + else if (dropFolder) + { + + var sourceNode = RDF.GetResource(sourceID, true); + folder = sourceNode.QueryInterface(Components.interfaces.nsIFolder); + sourceResource = folder.QueryInterface(Components.interfaces.nsIRDFResource); + sourcefolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder); + sourceServer = sourcefolder.server; + var moveFolder = false; + + if (sourceServer == targetServer) + moveFolder = true; + + try + { + messenger.CopyFolders(treeDatabase,targetNode,list,moveFolder); + } + catch(e) + { + dump ("Exception : CopyFolder \n"); + } } + return(false); } diff --git a/mozilla/mailnews/base/src/nsMessenger.cpp b/mozilla/mailnews/base/src/nsMessenger.cpp index 438bf2e8567..72a75d190df 100644 --- a/mozilla/mailnews/base/src/nsMessenger.cpp +++ b/mozilla/mailnews/base/src/nsMessenger.cpp @@ -1125,6 +1125,29 @@ nsMessenger::CopyMessages(nsIRDFCompositeDataSource *database, } +NS_IMETHODIMP +nsMessenger::CopyFolders(nsIRDFCompositeDataSource *database, + nsIRDFResource *dstResource, + nsISupportsArray *argumentArray, // nsIFolders + PRBool isMoveFolder) +{ + nsresult rv; + + if(!dstResource || !argumentArray) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr folderArray; + + rv = NS_NewISupportsArray(getter_AddRefs(folderArray)); + + NS_ENSURE_SUCCESS(rv,rv); + + folderArray->AppendElement(dstResource); + + return DoCommand(database, isMoveFolder ? (char *)NC_RDF_MOVEFOLDER : (char *)NC_RDF_COPYFOLDER, folderArray, argumentArray); + +} + NS_IMETHODIMP nsMessenger::RenameFolder(nsIRDFCompositeDataSource* db, nsIRDFResource* folderResource, diff --git a/mozilla/mailnews/base/src/nsMsgCopyService.cpp b/mozilla/mailnews/base/src/nsMsgCopyService.cpp index 928c21eb46d..1524f43a6ce 100644 --- a/mozilla/mailnews/base/src/nsMsgCopyService.cpp +++ b/mozilla/mailnews/base/src/nsMsgCopyService.cpp @@ -218,9 +218,17 @@ nsMsgCopyService::DoNextCopy() rv = copyRequest->m_dstFolder->CopyMessages (copySource->m_msgFolder, copySource->m_messageArray, copyRequest->m_isMoveOrDraftOrTemplate, - copyRequest->m_msgWindow, copyRequest->m_listener); + copyRequest->m_msgWindow, copyRequest->m_listener, PR_FALSE); //isFolder operation PR_FALSE } + else if (copyRequest->m_requestType == nsCopyFoldersType ) + { + copySource->m_processed = PR_TRUE; + rv = copyRequest->m_dstFolder->CopyFolder + (copySource->m_msgFolder, + copyRequest->m_isMoveOrDraftOrTemplate, + copyRequest->m_msgWindow, copyRequest->m_listener); + } else if (copyRequest->m_requestType == nsCopyFileMessageType) { nsCOMPtr aSpec(do_QueryInterface(copyRequest->m_srcSupport, &rv)); @@ -369,6 +377,57 @@ done: return rv; } +NS_IMETHODIMP +nsMsgCopyService::CopyFolders( nsISupportsArray* folders, + nsIMsgFolder* dstFolder, + PRBool isMove, + nsIMsgCopyServiceListener* listener, + nsIMsgWindow* window) +{ + nsCopyRequest* copyRequest; + nsCopySource* copySource = nsnull; + nsresult rv = NS_ERROR_NULL_POINTER; + PRUint32 cnt; + nsCOMPtr folder; + nsCOMPtr curFolder; + nsCOMPtr support; + + if (!folders || !dstFolder) return rv; + + rv = folders->Count(&cnt); //if cnt is zero it cannot to get this point, will be detected earlier + if ( cnt > 1) + NS_ASSERTION((NS_SUCCEEDED(rv)),"More than one folders to copy"); + + support = getter_AddRefs(folders->ElementAt(0)); + + copyRequest = new nsCopyRequest(); + if (!copyRequest) return NS_ERROR_OUT_OF_MEMORY; + + rv = copyRequest->Init(nsCopyFoldersType, support, dstFolder, + isMove, listener, window); + NS_ENSURE_SUCCESS(rv,rv); + + folder = do_QueryInterface(support, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + curFolder = do_QueryInterface(folder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + copySource = copyRequest->AddNewCopySource(curFolder); + if (!copySource) + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv)) + { + delete copyRequest; + NS_ENSURE_SUCCESS(rv, rv); + } + else + rv = DoCopy(copyRequest); + + return rv; +} + NS_IMETHODIMP nsMsgCopyService::CopyFileMessage(nsIFileSpec* fileSpec, nsIMsgFolder* dstFolder, diff --git a/mozilla/mailnews/base/src/nsMsgCopyService.h b/mozilla/mailnews/base/src/nsMsgCopyService.h index 361579c6bfe..1a8f23ef999 100644 --- a/mozilla/mailnews/base/src/nsMsgCopyService.h +++ b/mozilla/mailnews/base/src/nsMsgCopyService.h @@ -33,7 +33,8 @@ typedef enum _nsCopyRequestType { nsCopyMessagesType = 0x0, - nsCopyFileMessageType = 0x1 + nsCopyFileMessageType = 0x1, + nsCopyFoldersType = 0x2 } nsCopyRequestType; class nsCopyRequest; diff --git a/mozilla/mailnews/base/src/nsMsgFolderDataSource.cpp b/mozilla/mailnews/base/src/nsMsgFolderDataSource.cpp index da1cfe89e2b..fb8f1772dd2 100644 --- a/mozilla/mailnews/base/src/nsMsgFolderDataSource.cpp +++ b/mozilla/mailnews/base/src/nsMsgFolderDataSource.cpp @@ -83,6 +83,8 @@ nsIRDFResource* nsMsgFolderDataSource::kNC_NewFolder= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_GetNewMessages= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_Copy= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_Move= nsnull; +nsIRDFResource* nsMsgFolderDataSource::kNC_CopyFolder= nsnull; +nsIRDFResource* nsMsgFolderDataSource::kNC_MoveFolder= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_MarkAllMessagesRead= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_Compact= nsnull; nsIRDFResource* nsMsgFolderDataSource::kNC_Rename= nsnull; @@ -133,6 +135,8 @@ nsMsgFolderDataSource::nsMsgFolderDataSource() rdf->GetResource(NC_RDF_GETNEWMESSAGES, &kNC_GetNewMessages); rdf->GetResource(NC_RDF_COPY, &kNC_Copy); rdf->GetResource(NC_RDF_MOVE, &kNC_Move); + rdf->GetResource(NC_RDF_COPYFOLDER, &kNC_CopyFolder); + rdf->GetResource(NC_RDF_MOVEFOLDER, &kNC_MoveFolder); rdf->GetResource(NC_RDF_MARKALLMESSAGESREAD, &kNC_MarkAllMessagesRead); rdf->GetResource(NC_RDF_COMPACT, &kNC_Compact); @@ -187,6 +191,8 @@ nsMsgFolderDataSource::~nsMsgFolderDataSource (void) NS_RELEASE2(kNC_GetNewMessages, refcnt); NS_RELEASE2(kNC_Copy, refcnt); NS_RELEASE2(kNC_Move, refcnt); + NS_RELEASE2(kNC_CopyFolder, refcnt); + NS_RELEASE2(kNC_MoveFolder, refcnt); NS_RELEASE2(kNC_MarkAllMessagesRead, refcnt); NS_RELEASE2(kNC_Compact, refcnt); NS_RELEASE2(kNC_Rename, refcnt); @@ -562,6 +568,8 @@ nsMsgFolderDataSource::GetAllCommands(nsIRDFResource* source, cmds->AppendElement(kNC_GetNewMessages); cmds->AppendElement(kNC_Copy); cmds->AppendElement(kNC_Move); + cmds->AppendElement(kNC_CopyFolder); + cmds->AppendElement(kNC_MoveFolder); cmds->AppendElement(kNC_MarkAllMessagesRead); cmds->AppendElement(kNC_Compact); cmds->AppendElement(kNC_Rename); @@ -604,6 +612,8 @@ nsMsgFolderDataSource::IsCommandEnabled(nsISupportsArray/**/* aS (aCommand == kNC_NewFolder) || (aCommand == kNC_Copy) || (aCommand == kNC_Move) || + (aCommand == kNC_CopyFolder) || + (aCommand == kNC_MoveFolder) || (aCommand == kNC_GetNewMessages) || (aCommand == kNC_MarkAllMessagesRead) || (aCommand == kNC_Compact) || @@ -664,6 +674,14 @@ nsMsgFolderDataSource::DoCommand(nsISupportsArray/**/* aSources, { rv = DoCopyToFolder(folder, aArguments, mWindow, PR_TRUE); } + else if((aCommand == kNC_CopyFolder)) + { + rv = DoFolderCopyToFolder(folder, aArguments, mWindow, PR_FALSE); + } + else if((aCommand == kNC_MoveFolder)) + { + rv = DoFolderCopyToFolder(folder, aArguments, mWindow, PR_TRUE); + } else if((aCommand == kNC_MarkAllMessagesRead)) { rv = folder->MarkAllMessagesRead(); @@ -1536,6 +1554,50 @@ nsresult nsMsgFolderDataSource::DoCopyToFolder(nsIMsgFolder *dstFolder, nsISuppo //return NS_OK; } +nsresult nsMsgFolderDataSource::DoFolderCopyToFolder(nsIMsgFolder *dstFolder, nsISupportsArray *arguments, + nsIMsgWindow *msgWindow, PRBool isMoveFolder) +{ + nsresult rv; + PRUint32 itemCount; + rv = arguments->Count(&itemCount); + if (NS_FAILED(rv)) return rv; + + //need at least one item to copy + if(itemCount < 1) + return NS_ERROR_FAILURE; + + if (!isMoveFolder) // copy folder not on the same server + { + //Call copyservice with dstFolder, srcFolder, folders and isMoveFolder + nsCOMPtr copyService = do_GetService(kMsgCopyServiceCID, &rv); + if(NS_SUCCEEDED(rv)) + { + rv = copyService->CopyFolders(arguments, dstFolder, isMoveFolder, + nsnull, msgWindow); + + } + } + else //within the same server therefore no need for copy service + { + + nsCOMPtr supports; + nsCOMPtr msgFolder; + for (PRUint32 i=0;i< itemCount; i++) + { + supports = getter_AddRefs(arguments->ElementAt(i)); + msgFolder = do_QueryInterface(supports,&rv); + if (NS_SUCCEEDED(rv)) + { + rv = dstFolder->CopyFolder(msgFolder, isMoveFolder , msgWindow, nsnull); + NS_ASSERTION((NS_SUCCEEDED(rv)),"Copy folder failed."); + } + } + } + + return rv; + //return NS_OK; +} + nsresult nsMsgFolderDataSource::DoDeleteFromFolder( nsIMsgFolder *folder, nsISupportsArray *arguments, nsIMsgWindow *msgWindow, PRBool reallyDelete) diff --git a/mozilla/mailnews/base/src/nsMsgFolderDataSource.h b/mozilla/mailnews/base/src/nsMsgFolderDataSource.h index 8b88303a5b2..26bc131f961 100644 --- a/mozilla/mailnews/base/src/nsMsgFolderDataSource.h +++ b/mozilla/mailnews/base/src/nsMsgFolderDataSource.h @@ -148,6 +148,9 @@ protected: nsresult DoCopyToFolder(nsIMsgFolder *dstFolder, nsISupportsArray *arguments, nsIMsgWindow *msgWindow, PRBool isMove); + nsresult DoFolderCopyToFolder(nsIMsgFolder *dstFolder, nsISupportsArray *arguments, + nsIMsgWindow *msgWindow, PRBool isMoveFolder); + nsresult DoNewFolder(nsIMsgFolder *folder, nsISupportsArray *arguments); @@ -209,6 +212,8 @@ protected: static nsIRDFResource* kNC_GetNewMessages; static nsIRDFResource* kNC_Copy; static nsIRDFResource* kNC_Move; + static nsIRDFResource* kNC_CopyFolder; + static nsIRDFResource* kNC_MoveFolder; static nsIRDFResource* kNC_MarkAllMessagesRead; static nsIRDFResource* kNC_Compact; static nsIRDFResource* kNC_Rename; diff --git a/mozilla/mailnews/base/src/nsMsgRDFUtils.h b/mozilla/mailnews/base/src/nsMsgRDFUtils.h index af653fe9895..efe584bd8fd 100644 --- a/mozilla/mailnews/base/src/nsMsgRDFUtils.h +++ b/mozilla/mailnews/base/src/nsMsgRDFUtils.h @@ -102,6 +102,8 @@ typedef struct _nsMsgRDFNotification { #define NC_RDF_GETNEWMESSAGES NC_NAMESPACE_URI "GetNewMessages" #define NC_RDF_COPY NC_NAMESPACE_URI "Copy" #define NC_RDF_MOVE NC_NAMESPACE_URI "Move" +#define NC_RDF_COPYFOLDER NC_NAMESPACE_URI "CopyFolder" +#define NC_RDF_MOVEFOLDER NC_NAMESPACE_URI "MoveFolder" #define NC_RDF_MARKALLMESSAGESREAD NC_NAMESPACE_URI "MarkAllMessagesRead" #define NC_RDF_MARKTHREADREAD NC_NAMESPACE_URI "MarkThreadRead" #define NC_RDF_COMPACT NC_NAMESPACE_URI "Compact" diff --git a/mozilla/mailnews/base/util/nsMsgFolder.cpp b/mozilla/mailnews/base/util/nsMsgFolder.cpp index 203360835b9..546760153a7 100644 --- a/mozilla/mailnews/base/util/nsMsgFolder.cpp +++ b/mozilla/mailnews/base/util/nsMsgFolder.cpp @@ -931,6 +931,7 @@ NS_IMETHODIMP nsMsgFolder::GetChildWithURI(const char *uri, PRBool deep, nsIMsgF if(NS_FAILED(rv)) return rv; // case-insensitive compare is probably LCD across OS filesystems + PRBool equal = (folderURI && nsCRT::strcasecmp(folderURI, uri)==0); nsMemory::Free(folderURI); if (equal) @@ -2156,8 +2157,19 @@ nsMsgFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray *messages, PRBool isMove, nsIMsgWindow *window, + nsIMsgCopyServiceListener* listener, + PRBool isFolder) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsMsgFolder::CopyFolder(nsIMsgFolder* srcFolder, + PRBool isMoveFolder, + nsIMsgWindow *window, nsIMsgCopyServiceListener* listener) { + NS_ASSERTION(PR_FALSE, "should be overridden by child class"); return NS_ERROR_NOT_IMPLEMENTED; } @@ -2479,3 +2491,4 @@ NS_IMETHODIMP nsMsgFolder::GetMessageHeader(nsMsgKey msgKey, nsIMsgDBHdr **aMsgH return rv; } + diff --git a/mozilla/mailnews/base/util/nsMsgFolder.h b/mozilla/mailnews/base/util/nsMsgFolder.h index 0d6e23c2158..637fbe8e2cd 100644 --- a/mozilla/mailnews/base/util/nsMsgFolder.h +++ b/mozilla/mailnews/base/util/nsMsgFolder.h @@ -140,7 +140,8 @@ hasMessages); NS_IMETHOD GetFoldersWithFlag(PRUint32 flags, PRUint32 resultsize, PRUint32 *numFolders, nsIMsgFolder **result); NS_IMETHOD GetExpansionArray(nsISupportsArray *expansionArray); // NS_IMETHOD DeleteMessages(nsISupportsArray *message, nsITransactionManager *txnMgr, PRBool deleteStorage); - NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsISupportsArray *messages, PRBool isMove, nsIMsgWindow *window, nsIMsgCopyServiceListener *listener); + NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsISupportsArray *messages, PRBool isMove, nsIMsgWindow *window, nsIMsgCopyServiceListener *listener, PRBool isFolder); + NS_IMETHOD CopyFolder(nsIMsgFolder *srcFolder,PRBool isMoveFolder, nsIMsgWindow *window, nsIMsgCopyServiceListener *listener); NS_IMETHOD CopyFileMessage(nsIFileSpec *fileSpec, nsIMessage *msgToReplace, PRBool isDraft, nsIMsgWindow *window, nsIMsgCopyServiceListener *listener); NS_IMETHOD AcquireSemaphore(nsISupports *semHolder); NS_IMETHOD ReleaseSemaphore(nsISupports *semHolder); diff --git a/mozilla/mailnews/imap/public/nsIMsgImapMailFolder.idl b/mozilla/mailnews/imap/public/nsIMsgImapMailFolder.idl index f5b5cf6ea4c..5614244c143 100644 --- a/mozilla/mailnews/imap/public/nsIMsgImapMailFolder.idl +++ b/mozilla/mailnews/imap/public/nsIMsgImapMailFolder.idl @@ -31,7 +31,7 @@ interface nsIMsgImapMailFolder : nsISupports { void RemoveSubFolder(in nsIMsgFolder folder); void CreateClientSubfolderInfo(in string folderName, in wchar hierarchyDelimiter, in long flags); void List(); - void RenameLocal(in string newname); + void RenameLocal(in string newname, in nsIMsgFolder parent); void PrepareToRename(); void PerformExpand(in nsIMsgWindow aMsgWindow); void RecursiveCloseActiveConnections(in nsIImapIncomingServer aImapServer); diff --git a/mozilla/mailnews/imap/src/nsImapIncomingServer.cpp b/mozilla/mailnews/imap/src/nsImapIncomingServer.cpp index ee631459d2c..12bb3659d2b 100644 --- a/mozilla/mailnews/imap/src/nsImapIncomingServer.cpp +++ b/mozilla/mailnews/imap/src/nsImapIncomingServer.cpp @@ -1101,16 +1101,30 @@ NS_IMETHODIMP nsImapIncomingServer::OnlineFolderRename(const char *oldName, cons rv = GetFolder(oldName, getter_AddRefs(me)); if (NS_FAILED(rv)) return rv; + nsCOMPtr parent ; + + nsCAutoString newNameString(newName); + nsCAutoString parentName; + PRInt32 folderStart = newNameString.RFindChar('/'); + if (folderStart > 0) + { + newNameString.Left(parentName, folderStart); + rv = GetFolder(parentName.get(),getter_AddRefs(parent)); + } + else // root is the parent + { + nsCOMPtr rootFolder; + rv = GetRootFolder(getter_AddRefs(rootFolder)); + parent = do_QueryInterface(rootFolder,&rv); + } + if (NS_SUCCEEDED(rv) && parent) + { nsCOMPtr folder; folder = do_QueryInterface(me, &rv); if (NS_SUCCEEDED(rv)) - folder->RenameLocal(newName); + folder->RenameLocal(newName,parent); - nsCOMPtr parent ; - rv = me->GetParent(getter_AddRefs(parent)); - if (NS_SUCCEEDED(rv) && parent) - { - nsCOMPtr parentImapFolder = do_QueryInterface(parent); + nsCOMPtr parentImapFolder = do_QueryInterface(parent); if (parentImapFolder) parentImapFolder->RenameClient(me,oldName, newName); } diff --git a/mozilla/mailnews/imap/src/nsImapMailFolder.cpp b/mozilla/mailnews/imap/src/nsImapMailFolder.cpp index c541cfa4d0d..cccce5d29d7 100644 --- a/mozilla/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mozilla/mailnews/imap/src/nsImapMailFolder.cpp @@ -90,6 +90,73 @@ static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); #define FOUR_K 4096 +/* + Copies the contents of srcDir into destDir. + destDir will be created if it doesn't exist. +*/ + +static +nsresult RecursiveCopy(nsIFile* srcDir, nsIFile* destDir) +{ + nsresult rv; + PRBool isDir; + + rv = srcDir->IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + if (!isDir) return NS_ERROR_INVALID_ARG; + + PRBool exists; + rv = destDir->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = destDir->Create(nsIFile::DIRECTORY_TYPE, 0775); + if (NS_FAILED(rv)) return rv; + + PRBool hasMore = PR_FALSE; + nsCOMPtr dirIterator; + rv = srcDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); + if (NS_FAILED(rv)) return rv; + + rv = dirIterator->HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr dirEntry; + + while (hasMore) + { + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); + if (NS_SUCCEEDED(rv)) + { + rv = dirEntry->IsDirectory(&isDir); + if (NS_SUCCEEDED(rv)) + { + if (isDir) + { + nsCOMPtr destClone; + rv = destDir->Clone(getter_AddRefs(destClone)); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr newChild(do_QueryInterface(destClone)); + nsXPIDLCString leafName; + dirEntry->GetLeafName(getter_Copies(leafName)); + newChild->AppendRelativePath(leafName); + rv = newChild->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = newChild->Create(nsIFile::DIRECTORY_TYPE, 0775); + rv = RecursiveCopy(dirEntry, newChild); + } + } + else + rv = dirEntry->CopyTo(destDir, nsnull); + } + + } + rv = dirIterator->HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + } + + return rv; +} + nsImapMailFolder::nsImapMailFolder() : m_initialized(PR_FALSE),m_haveDiscoveredAllFolders(PR_FALSE), m_haveReadNameFromDB(PR_FALSE), @@ -1092,14 +1159,14 @@ NS_IMETHODIMP nsImapMailFolder::PrepareToRename() return NS_OK; } -NS_IMETHODIMP nsImapMailFolder::RenameLocal(const char *newName) +NS_IMETHODIMP nsImapMailFolder::RenameLocal(const char *newName, nsIMsgFolder *parent) { nsCAutoString leafname(newName); + nsCAutoString parentName; // newName always in the canonical form "greatparent/parentname/leafname" PRInt32 leafpos = leafname.RFindChar('/'); - if (leafpos >0) + if (leafpos >0) leafname.Cut(0, leafpos+1); - m_msgParser = null_nsCOMPtr(); PrepareToRename(); NotifyStoreClosedAllHeaders(); @@ -1109,10 +1176,18 @@ NS_IMETHODIMP nsImapMailFolder::RenameLocal(const char *newName) nsCOMPtr oldPathSpec; rv = GetPath(getter_AddRefs(oldPathSpec)); if (NS_FAILED(rv)) return rv; - nsCOMPtr parent; - rv = GetParent(getter_AddRefs(parent)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr parentFolder = do_QueryInterface(parent); + + nsCOMPtr parentPathSpec; + rv = parent->GetPath(getter_AddRefs(parentPathSpec)); + NS_ENSURE_SUCCESS(rv,rv); + + nsFileSpec parentPath; + rv = parentPathSpec->GetFileSpec(&parentPath); + NS_ENSURE_SUCCESS(rv,rv); + + if (!parentPath.IsDirectory()) + AddDirectorySeparator(parentPath); + PRUint32 cnt = 0; nsFileSpec dirSpec; @@ -1133,7 +1208,39 @@ NS_IMETHODIMP nsImapMailFolder::RenameLocal(const char *newName) { newNameStr = leafname; newNameStr += ".sbd"; - dirSpec.Rename(newNameStr.GetBuffer()); + char *leafName = dirSpec.GetLeafName(); + if (nsCRT::strcmp(leafName, newNameStr) != 0 ) + { + dirSpec.Rename(newNameStr.GetBuffer()); // in case of rename operation leaf names will differ + nsCRT::free(leafName); + return rv; + } + nsCRT::free(leafName); + + parentPath += newNameStr; //only for move we need to progress further in case the parent differs + + if (!parentPath.IsDirectory()) + parentPath.CreateDirectory(); + else + NS_ASSERTION(0,"Directory already exists."); + + nsCOMPtr srcDir = (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr destDir = (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCString oldPathStr (dirSpec.GetNativePathCString()); + srcDir->InitWithPath(oldPathStr.GetBuffer()); + + nsCString newPathStr (parentPath.GetNativePathCString()); + destDir->InitWithPath(newPathStr.GetBuffer()); + + rv = RecursiveCopy(srcDir, destDir); + + NS_ENSURE_SUCCESS(rv,rv); + + dirSpec.Delete(PR_TRUE); // moving folders } return rv; } @@ -1702,7 +1809,7 @@ NS_IMETHODIMP nsImapMailFolder::DeleteMessages(nsISupportsArray *messages, rv = QueryInterface(NS_GET_IID(nsIMsgFolder), getter_AddRefs(srcFolder)); - rv = trashFolder->CopyMessages(srcFolder, messages, PR_TRUE, msgWindow, nsnull); + rv = trashFolder->CopyMessages(srcFolder, messages, PR_TRUE, msgWindow, nsnull,PR_FALSE); } } return rv; @@ -1825,7 +1932,7 @@ nsImapMailFolder::DeleteSubFolders(nsISupportsArray* folders, nsIMsgWindow *msgW } } - if (confirmed) + if (confirmed && deleteNoTrash) //delete subfolders only if you are deleting things from trash return nsMsgFolder::DeleteSubFolders(folders, nsnull); else return rv; @@ -2443,6 +2550,7 @@ NS_IMETHODIMP nsImapMailFolder::EndCopy(PRBool copySucceeded) m_copyState->m_selectedState, urlListener, nsnull, copySupport); + } return rv; } @@ -4677,7 +4785,8 @@ nsImapMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* messages, PRBool isMove, nsIMsgWindow *msgWindow, - nsIMsgCopyServiceListener* listener) + nsIMsgCopyServiceListener* listener, + PRBool isFolder) //isFolder for future use when we do cross-server folder move/copy { nsresult rv = NS_OK; nsCAutoString messageIds; @@ -4770,6 +4879,38 @@ done: return rv; } +NS_IMETHODIMP +nsImapMailFolder::CopyFolder(nsIMsgFolder* srcFolder, + PRBool isMoveFolder, + nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener* listener) +{ + + NS_ENSURE_ARG_POINTER(srcFolder); + + nsresult rv = NS_OK; + + if (isMoveFolder) //move folder permitted when dstFolder and the srcFolder are on same server + { + nsCOMPtr imapService = do_GetService (kCImapService, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr urlListener = do_QueryInterface(srcFolder); + rv = imapService->MoveFolder(m_eventQueue, + srcFolder, + this, + urlListener, + nsnull); + } + + } + else + NS_ASSERTION(0,"isMoveFolder is false. Trying to copy to a different server."); + + return rv; + +} + nsresult nsImapMailFolder::SetTransactionManager(nsITransactionManager* txnMgr) { @@ -5075,7 +5216,7 @@ NS_IMETHODIMP nsImapMailFolder::RenameClient( nsIMsgFolder *msgFolder, const cha nsFileSpec path; rv = pathSpec->GetFileSpec(&path); if (NS_FAILED(rv)) return rv; - + nsCOMPtr oldImapFolder = do_QueryInterface(msgFolder, &rv); if (NS_FAILED(rv)) return rv; @@ -5084,17 +5225,18 @@ NS_IMETHODIMP nsImapMailFolder::RenameClient( nsIMsgFolder *msgFolder, const cha PRInt32 boxflags=0; oldImapFolder->GetBoxFlags(&boxflags); - nsAutoString newLeafName; - newLeafName.AssignWithConversion(newName); - nsAutoString parentName = newLeafName; + nsAutoString newLeafName; + nsAutoString newNameString; + newNameString.AssignWithConversion(newName); + newLeafName = newNameString; + nsAutoString parentName; nsAutoString folderNameStr; PRInt32 folderStart = newLeafName.RFindChar('/'); //internal use of hierarchyDelimiter is always '/' if (folderStart > 0) { - parentName.Right(newLeafName, newLeafName.Length() - folderStart - 1); - rv = AddDirectorySeparator(path); - } - + newNameString.Right(newLeafName, newLeafName.Length() - folderStart - 1); + CreateDirectoryForFolder(path); //needed when we move a folder to a folder with no subfolders. + } // if we get here, it's really a leaf, and "this" is the parent. folderNameStr = newLeafName; @@ -5165,8 +5307,11 @@ NS_IMETHODIMP nsImapMailFolder::RenameClient( nsIMsgFolder *msgFolder, const cha } } + nsCOMPtr parent; + msgFolder->GetParent(getter_AddRefs(parent)); + nsCOMPtr msgParent = do_QueryInterface(parent); msgFolder->SetParent(nsnull); - PropagateDelete(msgFolder,PR_FALSE); + msgParent->PropagateDelete(msgFolder,PR_FALSE); if(NS_SUCCEEDED(rv) && child) { diff --git a/mozilla/mailnews/imap/src/nsImapMailFolder.h b/mozilla/mailnews/imap/src/nsImapMailFolder.h index d7b841eeaae..ae8f043c1b3 100644 --- a/mozilla/mailnews/imap/src/nsImapMailFolder.h +++ b/mozilla/mailnews/imap/src/nsImapMailFolder.h @@ -168,6 +168,8 @@ public: NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsISupportsArray* messages, PRBool isMove, nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener* listener, PRBool isFolder); + NS_IMETHOD CopyFolder(nsIMsgFolder *srcFolder, PRBool isMove, nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener* listener); NS_IMETHOD CopyFileMessage(nsIFileSpec* fileSpec, nsIMessage* msgToReplace, diff --git a/mozilla/mailnews/imap/src/nsImapMoveCoalescer.cpp b/mozilla/mailnews/imap/src/nsImapMoveCoalescer.cpp index 184d9f492b6..7fa42383603 100644 --- a/mozilla/mailnews/imap/src/nsImapMoveCoalescer.cpp +++ b/mozilla/mailnews/imap/src/nsImapMoveCoalescer.cpp @@ -132,7 +132,7 @@ nsresult nsImapMoveCoalescer::PlaybackMoves(nsIEventQueue *eventQueue) } rv = destFolder->CopyMessages(m_sourceFolder, messages, PR_TRUE, m_msgWindow, - /*nsIMsgCopyServiceListener* listener*/ nsnull); + /*nsIMsgCopyServiceListener* listener*/ nsnull, PR_FALSE); // rv = imapService->OnlineMessageCopy(eventQueue, // m_sourceFolder, messageIds.GetBuffer(), // destFolder, PR_TRUE, PR_TRUE, diff --git a/mozilla/mailnews/imap/src/nsImapProtocol.cpp b/mozilla/mailnews/imap/src/nsImapProtocol.cpp index 92e0b99f191..54da86056ab 100644 --- a/mozilla/mailnews/imap/src/nsImapProtocol.cpp +++ b/mozilla/mailnews/imap/src/nsImapProtocol.cpp @@ -5452,8 +5452,9 @@ void nsImapProtocol::OnMoveFolderHierarchy(const char * sourceMailbox) leafName = oldBoxName; // this is a root level box else oldBoxName.Right(leafName, length-(leafStart+1)); - - newBoxName.Append(onlineDirSeparator); + + if ( newBoxName.Length() > 0 ) + newBoxName.Append(onlineDirSeparator); newBoxName.Append(leafName); PRBool renamed = RenameHierarchyByHand(sourceMailbox, newBoxName.GetBuffer()); diff --git a/mozilla/mailnews/imap/src/nsImapService.cpp b/mozilla/mailnews/imap/src/nsImapService.cpp index 60e3e254536..0c50fb7cab4 100644 --- a/mozilla/mailnews/imap/src/nsImapService.cpp +++ b/mozilla/mailnews/imap/src/nsImapService.cpp @@ -2033,8 +2033,11 @@ nsImapService::MoveFolder(nsIEventQueue* eventQueue, nsIMsgFolder* srcFolder, urlSpec.Append('>'); folderName = ""; GetFolderName(dstFolder, getter_Copies(folderName)); - urlSpec.Append(hierarchySeparator); - urlSpec.Append((const char *) folderName); + if ( folderName && folderName[0]) + { + urlSpec.Append(hierarchySeparator); + urlSpec.Append((const char *) folderName); + } rv = uri->SetSpec((char*) urlSpec.GetBuffer()); if (NS_SUCCEEDED(rv)) { diff --git a/mozilla/mailnews/local/src/nsLocalMailFolder.cpp b/mozilla/mailnews/local/src/nsLocalMailFolder.cpp index 1c11980e26c..0d91645be32 100644 --- a/mozilla/mailnews/local/src/nsLocalMailFolder.cpp +++ b/mozilla/mailnews/local/src/nsLocalMailFolder.cpp @@ -1493,7 +1493,7 @@ nsMsgLocalMailFolder::InitCopyState(nsISupports* aSupport, nsISupportsArray* messages, PRBool isMove, nsIMsgCopyServiceListener* listener, - nsIMsgWindow *msgWindow) + nsIMsgWindow *msgWindow, PRBool isFolder) { nsresult rv = NS_OK; nsFileSpec path; @@ -1539,6 +1539,7 @@ nsMsgLocalMailFolder::InitCopyState(nsISupports* aSupport, if (NS_FAILED(rv)) goto done; mCopyState->m_curCopyIndex = 0; mCopyState->m_isMove = isMove; + mCopyState->m_isFolder = isFolder; rv = messages->Count(&mCopyState->m_totalMsgCount); if (listener) mCopyState->m_listener = do_QueryInterface(listener, &rv); @@ -1571,13 +1572,13 @@ NS_IMETHODIMP nsMsgLocalMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* messages, PRBool isMove, nsIMsgWindow *msgWindow, - nsIMsgCopyServiceListener* listener) + nsIMsgCopyServiceListener* listener, PRBool isFolder) { if (!srcFolder || !messages) return NS_ERROR_NULL_POINTER; nsCOMPtr txnMgr; - if (msgWindow) + if (msgWindow && !isFolder) // no undo for folder move/copy { msgWindow->GetTransactionManager(getter_AddRefs(txnMgr)); @@ -1595,7 +1596,7 @@ nsMsgLocalMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* // don't update the counts in the dest folder until it is all over EnableNotifications(allMessageCountNotifications, PR_FALSE); - rv = InitCopyState(aSupport, messages, isMove, listener, msgWindow); + rv = InitCopyState(aSupport, messages, isMove, listener, msgWindow, isFolder); if (NS_FAILED(rv)) return rv; char *uri = nsnull; rv = srcFolder->GetURI(&uri); @@ -1618,35 +1619,39 @@ nsMsgLocalMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* } // undo stuff - nsLocalMoveCopyMsgTxn* msgTxn = nsnull; - - msgTxn = new nsLocalMoveCopyMsgTxn(srcFolder, this, isMove); - - if (msgTxn) - rv = - msgTxn->QueryInterface(NS_GET_IID(nsLocalMoveCopyMsgTxn), - getter_AddRefs(mCopyState->m_undoMsgTxn)); - else - rv = NS_ERROR_OUT_OF_MEMORY; - - if (NS_FAILED(rv)) + if (!isFolder) //no undo for folder move/copy { - ClearCopyState(); - } - else - { - msgTxn->SetMsgWindow(msgWindow); - if (isMove) - { - if (mFlags & MSG_FOLDER_FLAG_TRASH) - msgTxn->SetTransactionType(nsIMessenger::eDeleteMsg); + nsLocalMoveCopyMsgTxn* msgTxn = nsnull; + + msgTxn = new nsLocalMoveCopyMsgTxn(srcFolder, this, isMove); + + if (msgTxn) + rv = + msgTxn->QueryInterface(NS_GET_IID(nsLocalMoveCopyMsgTxn), + getter_AddRefs(mCopyState->m_undoMsgTxn)); else - msgTxn->SetTransactionType(nsIMessenger::eMoveMsg); - } - else - { - msgTxn->SetTransactionType(nsIMessenger::eCopyMsg); - } + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv)) + { + ClearCopyState(); + } + else + { + msgTxn->SetMsgWindow(msgWindow); + if (isMove) + { + if (mFlags & MSG_FOLDER_FLAG_TRASH) + msgTxn->SetTransactionType(nsIMessenger::eDeleteMsg); + else + msgTxn->SetTransactionType(nsIMessenger::eMoveMsg); + } + else + { + msgTxn->SetTransactionType(nsIMessenger::eCopyMsg); + } + } + } PRUint32 numMsgs = 0; messages->Count(&numMsgs); if (numMsgs > 1 && protocolType.EqualsIgnoreCase("imap")) @@ -1667,9 +1672,212 @@ nsMsgLocalMailFolder::CopyMessages(nsIMsgFolder* srcFolder, nsISupportsArray* ClearCopyState(); } } - } return rv; } +// for srcFolder that are on different server than the dstFolder. +nsresult +nsMsgLocalMailFolder::CopyFolderAcrossServer(nsIMsgFolder *destFolder, nsIMsgFolder* srcFolder, nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener *listener ) +{ + + nsresult rv; + nsCOMPtr newFolder; + nsCOMPtr newMsgFolder; + + nsXPIDLString folderName; + srcFolder->GetName(getter_Copies(folderName)); + + rv = destFolder->CreateSubfolder(folderName,msgWindow); + if (NS_FAILED(rv)) return rv; + + destFolder->FindSubFolder(NS_ConvertUCS2toUTF8(folderName.get()), getter_AddRefs(newFolder)); + + newMsgFolder = do_QueryInterface(newFolder,&rv); + + nsCOMPtr messages; + rv = srcFolder->GetMessages(msgWindow, getter_AddRefs(messages)); + + nsCOMPtr msgSupportsArray; + NS_NewISupportsArray(getter_AddRefs(msgSupportsArray)); + + PRBool hasMoreElements; + nsCOMPtr aSupport; + + if (messages) + messages->HasMoreElements(&hasMoreElements); + + while (hasMoreElements && NS_SUCCEEDED(rv)) + { + rv = messages->GetNext(getter_AddRefs(aSupport)); + rv = msgSupportsArray->AppendElement(aSupport); + messages->HasMoreElements(&hasMoreElements); + } + + PRUint32 numMsgs=0; + msgSupportsArray->Count(&numMsgs); + + if (numMsgs > 0 ) //if only srcFolder has messages.. + newMsgFolder->CopyMessages(srcFolder, msgSupportsArray, PR_FALSE, msgWindow, listener, PR_TRUE); + else + DoNextSubFolder(newMsgFolder, srcFolder, msgWindow, listener); + + return NS_OK; // otherwise the front-end will say Exception::CopyFolder +} + +nsresult //Continue with next subfolder +nsMsgLocalMailFolder::DoNextSubFolder(nsIMsgFolder *newMsgFolder, + nsIMsgFolder *srcFolder, + nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener *listener ) +{ + nsresult rv; + nsCOMPtr aEnumerator; + srcFolder->GetSubFolders(getter_AddRefs(aEnumerator)); + nsCOMPtrfolder; + nsCOMPtr aSupports; + rv = aEnumerator->First(); + while (NS_SUCCEEDED(rv)) + { + rv = aEnumerator->CurrentItem(getter_AddRefs(aSupports)); + folder = do_QueryInterface(aSupports); + rv = aEnumerator->Next(); + if (folder) + CopyFolderAcrossServer(newMsgFolder,folder, msgWindow, listener); + + } + return rv; +} + +NS_IMETHODIMP +nsMsgLocalMailFolder::CopyFolder( nsIMsgFolder* srcFolder, PRBool isMoveFolder, + nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener* listener) +{ + nsresult rv; + NS_ENSURE_ARG_POINTER(srcFolder); + + if (isMoveFolder) // isMoveFolder == true when "this" and srcFolder are on same server + rv = CopyFolderLocal(this, srcFolder, isMoveFolder, msgWindow, listener ); + else + rv = CopyFolderAcrossServer(this, srcFolder, msgWindow, listener ); + + return rv; +} + + +nsresult +nsMsgLocalMailFolder::CopyFolderLocal( nsIMsgFolder *destFolder, nsIMsgFolder *srcFolder, PRBool isMoveFolder, + nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener *listener ) +{ + + nsresult rv; + nsCOMPtr newFolder; + nsCOMPtr newMsgFolder; + + nsXPIDLString idlName; + srcFolder->GetName(getter_Copies(idlName)); + nsAutoString folderName; + folderName.Assign(idlName); + + srcFolder->ForceDBClosed(); + + nsCOMPtr oldPathSpec; + rv = srcFolder->GetPath(getter_AddRefs(oldPathSpec)); + NS_ENSURE_SUCCESS(rv,rv); + + nsFileSpec oldPath; + rv = oldPathSpec->GetFileSpec(&oldPath); + NS_ENSURE_SUCCESS(rv,rv); + + nsLocalFolderSummarySpec summarySpec(oldPath); + + nsCOMPtr newPathSpec; + rv = destFolder->GetPath(getter_AddRefs(newPathSpec)); + NS_ENSURE_SUCCESS(rv,rv); + + nsFileSpec newPath; + rv = newPathSpec->GetFileSpec(&newPath); + NS_ENSURE_SUCCESS(rv,rv); + + if (!newPath.IsDirectory()) + { + AddDirectorySeparator(newPath); + newPath.CreateDirectory(); + } + + PRBool exists = PR_FALSE; + nsFileSpec checkPath = newPath; + + checkPath += folderName; + exists=checkPath.Exists(); + + if (exists) + { + if (msgWindow) + AlertFolderExists(msgWindow); + return NS_MSG_FOLDER_EXISTS; + } + + nsFileSpec path = oldPath; + + path.MoveToDir(newPath); + summarySpec.MoveToDir(newPath); + + destFolder->AddSubfolder(&folderName, getter_AddRefs(newMsgFolder)); + + PRUint32 flags; + srcFolder->GetFlags(&flags); + newMsgFolder->SetFlags(flags); + + if (newMsgFolder) + { + newMsgFolder->SetName(folderName.GetUnicode()); + nsCOMPtr supports = do_QueryInterface(newMsgFolder); + nsCOMPtr parentSupports = do_QueryInterface(destFolder); + + if (supports && parentSupports) + { + NotifyItemAdded(parentSupports, supports, "folderView"); + } + } + + nsCOMPtr aEnumerator; + srcFolder->GetSubFolders(getter_AddRefs(aEnumerator)); + nsCOMPtrfolder; + nsCOMPtr supports; + rv = aEnumerator->First(); + while (NS_SUCCEEDED(rv)) + { + rv = aEnumerator->CurrentItem(getter_AddRefs(supports)); + folder = do_QueryInterface(supports); + rv = aEnumerator->Next(); + if (folder) + CopyFolderLocal(newMsgFolder,folder, PR_FALSE, msgWindow, listener); // PR_FALSE needed to avoid un-necessary deletions + + } + + if (isMoveFolder ) + { + nsCOMPtr parent; + nsCOMPtr msgParent; + srcFolder->GetParent(getter_AddRefs(parent)); + srcFolder->SetParent(nsnull); + if (parent) + { + msgParent = do_QueryInterface(parent); + if (msgParent) + msgParent->PropagateDelete(srcFolder, PR_FALSE); // The files have already been moved, so delete storage PR_FALSE + if (!oldPath.IsDirectory()) + { + AddDirectorySeparator(oldPath); + oldPath.Delete(PR_TRUE); //delete the .sbd directory and it's content. All subfolders have been moved + } + } + } + + return NS_OK; +} NS_IMETHODIMP nsMsgLocalMailFolder::CopyFileMessage(nsIFileSpec* fileSpec, nsIMessage* @@ -1698,7 +1906,7 @@ nsMsgLocalMailFolder::CopyFileMessage(nsIFileSpec* fileSpec, nsIMessage* } rv = InitCopyState(fileSupport, messages, msgToReplace ? PR_TRUE:PR_FALSE, - listener, msgWindow); + listener, msgWindow, PR_FALSE); if (NS_FAILED(rv)) goto done; parseMsgState = new nsParseMailMessageState(); @@ -2158,6 +2366,11 @@ NS_IMETHODIMP nsMsgLocalMailFolder::EndCopy(PRBool copySucceeded) nsresult result; if(!mCopyState->m_isMove) { + nsCOMPtr srcFolder; + srcFolder = do_QueryInterface(mCopyState->m_srcSupport); + if (mCopyState->m_isFolder) + DoNextSubFolder(this, srcFolder, nsnull, nsnull); //Copy all subfolders then notify completion + NS_WITH_SERVICE(nsIMsgCopyService, copyService, kMsgCopyServiceCID, &result); @@ -2168,10 +2381,8 @@ NS_IMETHODIMP nsMsgLocalMailFolder::EndCopy(PRBool copySucceeded) mTxnMgr->Do(mCopyState->m_undoMsgTxn); - nsCOMPtr srcFolder; - srcFolder = do_QueryInterface(mCopyState->m_srcSupport); - if (srcFolder) - srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom); + if (srcFolder && !mCopyState->m_isFolder) + srcFolder->NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom); ClearCopyState(); } @@ -2765,3 +2976,4 @@ nsMsgLocalMailFolder::setSubfolderFlag(PRUnichar* aFolderName, return NS_OK; } + diff --git a/mozilla/mailnews/local/src/nsLocalMailFolder.h b/mozilla/mailnews/local/src/nsLocalMailFolder.h index 4938c5863dd..2bc4dce1910 100644 --- a/mozilla/mailnews/local/src/nsLocalMailFolder.h +++ b/mozilla/mailnews/local/src/nsLocalMailFolder.h @@ -62,6 +62,7 @@ struct nsLocalMailCopyState nsIMsgMessageService* m_messageService; PRUint32 m_totalMsgCount; PRBool m_isMove; + PRBool m_isFolder; // isFolder move/copy PRBool m_dummyEnvelopeNeeded; char m_dataBuffer[FOUR_K+1]; PRUint32 m_leftOver; @@ -134,6 +135,8 @@ public: deleteStorage, PRBool isMove); NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsISupportsArray* messages, PRBool isMove, nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener* listener, PRBool isFolder ); + NS_IMETHOD CopyFolder(nsIMsgFolder *srcFolder, PRBool isMoveFolder, nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener* listener); NS_IMETHOD CopyFileMessage(nsIFileSpec* fileSpec, nsIMessage* msgToReplace, PRBool isDraftOrTemplate, @@ -144,6 +147,13 @@ public: protected: + nsresult CopyFolderLocal(nsIMsgFolder *destFolder, nsIMsgFolder *srcFolder, PRBool isMoveFolder, nsIMsgWindow *msgWindow, + nsIMsgCopyServiceListener* listener); + nsresult CopyFolderAcrossServer(nsIMsgFolder *destFolder, nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener); + + nsresult DoNextSubFolder(nsIMsgFolder *newMsgFolder, nsIMsgFolder *srcFolder, + nsIMsgWindow *msgWindow, nsIMsgCopyServiceListener *listener ); + nsresult CreateSubFolders(nsFileSpec &path); nsresult AddDirectorySeparator(nsFileSpec &path); nsresult GetDatabase(nsIMsgWindow *aMsgWindow); @@ -161,7 +171,8 @@ protected: nsresult DeleteMessage(nsIMessage *message, nsIMsgWindow *msgWindow, PRBool deleteStorage); - // copy message helper + + // copy message helper nsresult CopyMessageTo(nsIMessage *message, nsIMsgFolder *dstFolder, nsIMsgWindow *msgWindow, PRBool isMove); @@ -173,7 +184,7 @@ protected: virtual const char* GetIncomingServerType(); nsresult SetTransactionManager(nsITransactionManager* txnMgr); nsresult InitCopyState(nsISupports* aSupport, nsISupportsArray* messages, - PRBool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow *msgWindow); + PRBool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow *msgWindow, PRBool isMoveFolder); void ClearCopyState(); virtual nsresult CreateBaseMessageURI(const char *aURI);