25589. r=timeless, sr=bienvenu, sspitzer. Adding feature drag and drop of folder.

Thanks to sspitzer and david for good review.


git-svn-id: svn://10.0.0.236/trunk@86107 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
naving%netscape.com 2001-02-02 20:21:52 +00:00
parent a7fd5e9473
commit 683df5eaa9
22 changed files with 914 additions and 191 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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");

View File

@ -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);
}

View File

@ -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<nsISupportsArray> 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,

View File

@ -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<nsIFileSpec> 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<nsIFolder> folder;
nsCOMPtr<nsIMsgFolder> curFolder;
nsCOMPtr<nsISupports> 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,

View File

@ -33,7 +33,8 @@
typedef enum _nsCopyRequestType
{
nsCopyMessagesType = 0x0,
nsCopyFileMessageType = 0x1
nsCopyFileMessageType = 0x1,
nsCopyFoldersType = 0x2
} nsCopyRequestType;
class nsCopyRequest;

View File

@ -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/*<nsIRDFResource>*/* 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/*<nsIRDFResource>*/* 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<nsIMsgCopyService> 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<nsISupports> supports;
nsCOMPtr<nsIMsgFolder> 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)

View File

@ -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;

View File

@ -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"

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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<nsIMsgFolder> 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<nsIFolder> rootFolder;
rv = GetRootFolder(getter_AddRefs(rootFolder));
parent = do_QueryInterface(rootFolder,&rv);
}
if (NS_SUCCEEDED(rv) && parent)
{
nsCOMPtr<nsIMsgImapMailFolder> folder;
folder = do_QueryInterface(me, &rv);
if (NS_SUCCEEDED(rv))
folder->RenameLocal(newName);
folder->RenameLocal(newName,parent);
nsCOMPtr<nsIFolder> parent ;
rv = me->GetParent(getter_AddRefs(parent));
if (NS_SUCCEEDED(rv) && parent)
{
nsCOMPtr<nsIMsgImapMailFolder> parentImapFolder = do_QueryInterface(parent);
nsCOMPtr<nsIMsgImapMailFolder> parentImapFolder = do_QueryInterface(parent);
if (parentImapFolder)
parentImapFolder->RenameClient(me,oldName, newName);
}

View File

@ -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<nsISimpleEnumerator> dirIterator;
rv = srcDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
if (NS_FAILED(rv)) return rv;
rv = dirIterator->HasMoreElements(&hasMore);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFile> 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<nsIFile> destClone;
rv = destDir->Clone(getter_AddRefs(destClone));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsILocalFile> 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<nsIFileSpec> oldPathSpec;
rv = GetPath(getter_AddRefs(oldPathSpec));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFolder> parent;
rv = GetParent(getter_AddRefs(parent));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgFolder> parentFolder = do_QueryInterface(parent);
nsCOMPtr<nsIFileSpec> 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<nsILocalFile> srcDir = (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsILocalFile> 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 <nsIImapService> imapService = do_GetService (kCImapService, &rv);
if (NS_SUCCEEDED(rv))
{
nsCOMPtr <nsIUrlListener> 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<nsIMsgImapMailFolder> 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<nsIFolder> parent;
msgFolder->GetParent(getter_AddRefs(parent));
nsCOMPtr<nsIMsgFolder> msgParent = do_QueryInterface(parent);
msgFolder->SetParent(nsnull);
PropagateDelete(msgFolder,PR_FALSE);
msgParent->PropagateDelete(msgFolder,PR_FALSE);
if(NS_SUCCEEDED(rv) && child)
{

View File

@ -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,

View File

@ -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,

View File

@ -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());

View File

@ -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))
{

View File

@ -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 <nsITransactionManager> 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<nsIFolder> newFolder;
nsCOMPtr<nsIMsgFolder> 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<nsISimpleEnumerator> messages;
rv = srcFolder->GetMessages(msgWindow, getter_AddRefs(messages));
nsCOMPtr<nsISupportsArray> msgSupportsArray;
NS_NewISupportsArray(getter_AddRefs(msgSupportsArray));
PRBool hasMoreElements;
nsCOMPtr<nsISupports> 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<nsIEnumerator> aEnumerator;
srcFolder->GetSubFolders(getter_AddRefs(aEnumerator));
nsCOMPtr<nsIMsgFolder>folder;
nsCOMPtr<nsISupports> 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<nsIFolder> newFolder;
nsCOMPtr<nsIMsgFolder> newMsgFolder;
nsXPIDLString idlName;
srcFolder->GetName(getter_Copies(idlName));
nsAutoString folderName;
folderName.Assign(idlName);
srcFolder->ForceDBClosed();
nsCOMPtr<nsIFileSpec> 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<nsIFileSpec> 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<nsISupports> supports = do_QueryInterface(newMsgFolder);
nsCOMPtr<nsISupports> parentSupports = do_QueryInterface(destFolder);
if (supports && parentSupports)
{
NotifyItemAdded(parentSupports, supports, "folderView");
}
}
nsCOMPtr<nsIEnumerator> aEnumerator;
srcFolder->GetSubFolders(getter_AddRefs(aEnumerator));
nsCOMPtr<nsIMsgFolder>folder;
nsCOMPtr<nsISupports> 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 <nsIFolder> parent;
nsCOMPtr<nsIMsgFolder> 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<nsIMsgFolder> 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<nsIMsgFolder> 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;
}

View File

@ -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);