Bug 262184: support Copy as a filter action (as in tbird 1.0). Finally

landing on the trunk, r=bienvenu, a=caillon.
This commit is contained in:
shaver%mozilla.org 2005-04-20 14:45:03 +00:00
Родитель 790d4e56c4
Коммит 1c6d83e837
11 изменённых файлов: 248 добавлений и 27 удалений

Просмотреть файл

@ -532,6 +532,70 @@
<menupopup/>
</menulist>
<menulist id="actionTargetFolder2"
containment="http://home.netscape.com/NC-rdf#child"
sortResource="http://home.netscape.com/NC-rdf#FolderTreeName"
sortDirection="ascending"
datasources="rdf:msgaccountmanager rdf:mailnewsfolders"
ref="msgaccounts:/">
<template>
<rule nc:CanFileMessagesOnServer="false">
<!-- don't show servers (nntp & any others) which do not allow message filing -->
</rule>
<rule nc:CanSearchMessages="false">
<!-- don't show servers (nntp & any others) which do not allow search -->
</rule>
<rule nc:CanFileMessages="true" iscontainer="true" isempty="false">
<menupopup>
<menu uri="..."
class="folderMenuItem menu-iconic"
oncommand="PickedMsgFolder(event.target,'actionTargetFolder2')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name">
<menupopup class="menulist-menupopup">
<menuitem label="&filemessageschoosethis.label;"
oncommand="PickedMsgFolder(event.target.parentNode.parentNode,'actionTargetFolder2')"/>
<menuseparator/>
</menupopup>
</menu>
</menupopup>
</rule>
<rule nc:CanFileMessages="false" iscontainer="true" isempty="false">
<menupopup>
<menu uri="..."
class="folderMenuItem menu-iconic"
oncommand="PickedMsgFolder(event.target,'actionTargetFolder2')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name">
<menupopup class="menulist-menupopup"/>
</menu>
</menupopup>
</rule>
<rule nc:CanFileMessages="true">
<menupopup>
<menuitem uri="..." value="..."
class="folderMenuItem menuitem-iconic"
oncommand="PickedMsgFolder(event.target,'actionTargetFolder2')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name"/>
</menupopup>
</rule>
</template>
<menupopup/>
</menulist>
<menulist id="runFiltersFolder"
containment="http://home.netscape.com/NC-rdf#child"
sortResource="http://home.netscape.com/NC-rdf#FolderTreeName"

Просмотреть файл

@ -79,5 +79,6 @@ interface nsMsgFilterAction {
const long LeaveOnPop3Server=13;
const long JunkScore=14;
const long FetchBodyFromPop3Server=15;
const long CopyToFolder=16;
};

Просмотреть файл

@ -48,6 +48,7 @@ var gFilter;
var gFilterList;
var gFilterNameElement;
var gActionTargetElement;
var gActionTargetCopyElement;
var gActionValueDeck;
var gActionPriority;
var gActionLabel;
@ -58,6 +59,7 @@ var nsMsgSearchScope = Components.interfaces.nsMsgSearchScope;
var gPrefBranch;
var gMailSession = null;
var gMoveToFolderCheckbox;
var gCopyToFolderCheckbox;
var gChangePriorityCheckbox;
var gLabelCheckbox;
var gJunkScoreCheckbox;
@ -260,11 +262,13 @@ function initializeFilterWidgets()
{
gFilterNameElement = document.getElementById("filterName");
gActionTargetElement = document.getElementById("actionTargetFolder");
gActionTargetCopyElement = document.getElementById("actionTargetFolder2");
gActionValueDeck = document.getElementById("actionValueDeck");
gActionPriority = document.getElementById("actionValuePriority");
gActionJunkScore = document.getElementById("actionValueJunkScore");
gActionLabel = document.getElementById("actionValueLabel");
gMoveToFolderCheckbox = document.getElementById("moveToFolder");
gCopyToFolderCheckbox = document.getElementById("copyToFolder");
gChangePriorityCheckbox = document.getElementById("changePriority");
gLabelCheckbox = document.getElementById("label");
gJunkScoreCheckbox = document.getElementById("setJunkScore");
@ -295,6 +299,14 @@ function initializeDialog(filter)
if (target)
SetFolderPicker(target, gActionTargetElement.id);
}
else if (filterAction.type == nsMsgFilterAction.CopyToFolder)
{
// preselect target folder
gCopyToFolderCheckbox.checked = true;
var target = filterAction.targetFolderUri;
if (target)
SetFolderPicker(target, gActionTargetCopyElement.id);
}
else if (filterAction.type == nsMsgFilterAction.ChangePriority)
{
gChangePriorityCheckbox.checked = true;
@ -435,6 +447,19 @@ function saveFilter()
}
}
if (gCopyToFolderCheckbox.checked)
{
if (gActionTargetCopyElement)
targetUri = gActionTargetCopyElement.getAttribute("uri");
if (!targetUri || targetUri == "")
{
if (gPromptService)
gPromptService.alert(window, null,
gFilterBundle.getString("mustSelectFolder"));
return false;
}
}
if (!gFilter)
{
gFilter = gFilterList.createFilter(filterName);
@ -464,6 +489,23 @@ function saveFilter()
filterAction.targetFolderUri = targetUri;
gFilter.appendAction(filterAction);
}
if (gCopyToFolderCheckbox.checked)
{
if (gActionTargetCopyElement)
targetUri = gActionTargetCopyElement.getAttribute("uri");
if (!targetUri || targetUri == "")
{
str = gFilterBundle.getString("mustSelectFolder");
window.alert(str);
return false;
}
filterAction = gFilter.createAction();
filterAction.type = nsMsgFilterAction.CopyToFolder;
filterAction.targetFolderUri = targetUri;
gFilter.appendAction(filterAction);
}
if (gChangePriorityCheckbox.checked)
{
@ -555,11 +597,6 @@ function saveFilter()
return true;
}
function onTargetFolderSelected(event)
{
SetFolderPicker(event.target.id, gActionTargetElement.id);
}
function SetUpFilterActionList(aScope)
{
var element, elements, i;
@ -646,7 +683,7 @@ function GetFirstSelectedMsgFolder()
return msgFolder;
}
function SearchNewFolderOkCallback(name,uri)
function SearchNewFolderOkCallback(name,uri,targetid)
{
var msgFolder = GetMsgFolderFromUri(uri, true);
var imapFolder = null;
@ -682,7 +719,7 @@ function SearchNewFolderOkCallback(name,uri)
if (!imapFolder)
{
var curFolder = uri+"/"+encodeURIComponent(name);
SetFolderPicker(curFolder, gActionTargetElement.id);
SetFolderPicker(curFolder, targetid);
}
}

Просмотреть файл

@ -107,7 +107,21 @@
<listcell>
<button id="newFolderButton" enablefornews="false" label="&newFolderButton.label;"
accesskey="&newFolderButton.accesskey;"
oncommand="MsgNewFolder(SearchNewFolderOkCallback);"/>
oncommand="MsgNewFolder(function (name,uri){ SearchNewFolderOkCallback(name,uri,'actionTargetFolder'); } )"/>
</listcell>
</listitem>
<listitem allowevents="true">
<listcell>
<checkbox id="copyToFolder" enablefornews="false" label="&copyToFolder.label;"/>
</listcell>
<listcell>
<menulist id="actionTargetFolder2" enablefornews="false" flex="1"/>
</listcell>
<listcell>
<button id="copyNewFolderButton" enablefornews="false" label="&newFolderButton.label;"
accesskey="&newFolderButton.accesskey;"
oncommand="MsgNewFolder(function (name,uri){ SearchNewFolderOkCallback(name,uri,'actionTargetFolder2'); } )"/>
</listcell>
</listitem>

Просмотреть файл

@ -17,6 +17,8 @@
<!ENTITY contains.label "contains">
<!ENTITY nocontains.label "doesn't contain">
<!ENTITY moveToFolder.label "Move to folder:">
<!ENTITY copyToFolder.label "Copy to folder:">
<!ENTITY changePriority.label "Change the priority to:">
<!ENTITY delete.label "Delete the message">
<!ENTITY markRead.label "Mark the message as read">

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -116,7 +116,8 @@ NS_IMETHODIMP
nsMsgRuleAction::SetTargetFolderUri(const char *aUri)
{
NS_ENSURE_ARG_POINTER(aUri);
NS_ENSURE_TRUE(m_type == nsMsgFilterAction::MoveToFolder,
NS_ENSURE_TRUE(m_type == nsMsgFilterAction::MoveToFolder ||
m_type == nsMsgFilterAction::CopyToFolder,
NS_ERROR_ILLEGAL_VALUE);
m_folderUri = aUri;
return NS_OK;
@ -126,7 +127,8 @@ NS_IMETHODIMP
nsMsgRuleAction::GetTargetFolderUri(char** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
NS_ENSURE_TRUE(m_type == nsMsgFilterAction::MoveToFolder,
NS_ENSURE_TRUE(m_type == nsMsgFilterAction::MoveToFolder ||
m_type == nsMsgFilterAction::CopyToFolder,
NS_ERROR_ILLEGAL_VALUE);
*aResult = ToNewCString(m_folderUri);
return NS_OK;
@ -260,6 +262,7 @@ nsMsgFilter::GetSortedActionList(nsISupportsArray *actionList)
PRUint32 numActions;
nsresult err = m_actionList->Count(&numActions);
NS_ENSURE_SUCCESS(err, err);
PRBool insertedFinalAction = PR_FALSE;
PRUint32 front = 0;
for (PRUint32 index =0; index < numActions; index++)
@ -271,9 +274,32 @@ nsMsgFilter::GetSortedActionList(nsISupportsArray *actionList)
nsMsgRuleActionType actionType;
action->GetType(&actionType);
//we always want MoveToFolder action to be last (or delete to trash)
if (actionType == nsMsgFilterAction::MoveToFolder || actionType == nsMsgFilterAction::Delete)
actionList->AppendElement(action);
if (actionType == nsMsgFilterAction::MoveToFolder || actionType == nsMsgFilterAction::Delete)
{
err = actionList->AppendElement(action);
NS_ENSURE_SUCCESS(err, err);
insertedFinalAction = PR_TRUE;
}
// Copy is always last, except for move/delete
else if (actionType == nsMsgFilterAction::CopyToFolder)
{
if (!insertedFinalAction)
{
err = actionList->AppendElement(action);
NS_ENSURE_SUCCESS(err, err);
}
else
{
// If we already have a move/delete action in place, we want to
// place ourselves just before that final action.
PRUint32 count;
actionList->Count(&count);
err = actionList->InsertElementAt(action, count - 2);
NS_ENSURE_SUCCESS(err, err);
}
}
else
{
actionList->InsertElementAt(action,front);
@ -416,14 +442,16 @@ NS_IMETHODIMP nsMsgFilter::LogRuleHit(nsIMsgRuleAction *aFilterAction, nsIMsgDBH
buffer += actionStr;
buffer += " ";
if (actionType == nsMsgFilterAction::MoveToFolder) {
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder) {
nsXPIDLCString actionFolderUri;
aFilterAction->GetTargetFolderUri(getter_Copies(actionFolderUri));
buffer += actionFolderUri.get();
}
buffer += "\n";
if (actionType == nsMsgFilterAction::MoveToFolder) {
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder) {
nsXPIDLCString msgId;
aMsgHdr->GetMessageId(getter_Copies(msgId));
buffer += " id = ";
@ -492,7 +520,7 @@ void nsMsgFilter::SetFilterScript(nsCString *fileName)
m_scriptFileName = *fileName;
}
nsresult nsMsgFilter::ConvertMoveToFolderValue(nsIMsgRuleAction *filterAction, nsCString &moveValue)
nsresult nsMsgFilter::ConvertMoveOrCopyToFolderValue(nsIMsgRuleAction *filterAction, nsCString &moveValue)
{
NS_ENSURE_ARG_POINTER(filterAction);
PRInt16 filterVersion = kFileVersion;
@ -652,6 +680,7 @@ nsresult nsMsgFilter::SaveRule(nsIOFileStream *aStream)
switch(actionType)
{
case nsMsgFilterAction::MoveToFolder:
case nsMsgFilterAction::CopyToFolder:
{
nsXPIDLCString imapTargetString;
action->GetTargetFolderUri(getter_Copies(imapTargetString));
@ -739,6 +768,7 @@ struct RuleActionsTableEntry
static struct RuleActionsTableEntry ruleActionsTable[] =
{
{ nsMsgFilterAction::MoveToFolder, nsMsgFilterType::Inbox, 0, "Move to folder"},
{ nsMsgFilterAction::CopyToFolder, nsMsgFilterType::Inbox, 0, "Copy to folder"},
{ nsMsgFilterAction::ChangePriority, nsMsgFilterType::Inbox, 0, "Change priority"},
{ nsMsgFilterAction::Delete, nsMsgFilterType::All, 0, "Delete"},
{ nsMsgFilterAction::MarkRead, nsMsgFilterType::All, 0, "Mark read"},

Просмотреть файл

@ -97,7 +97,7 @@ public:
void Dump();
#endif
nsresult ConvertMoveToFolderValue(nsIMsgRuleAction *filterAction, nsCString &relativePath);
nsresult ConvertMoveOrCopyToFolderValue(nsIMsgRuleAction *filterAction, nsCString &relativePath);
static const char *GetActionStr(nsMsgRuleActionType action);
static nsresult GetActionFilingStr(nsMsgRuleActionType action, nsCString &actionStr);
static nsMsgRuleActionType GetActionForFilingStr(nsCString &actionStr);

Просмотреть файл

@ -636,8 +636,11 @@ nsresult nsMsgFilterList::LoadTextFilters(nsIOFileStream *aStream)
{
nsMsgRuleActionType type;
currentFilterAction->GetType(&type);
if (type == nsMsgFilterAction::MoveToFolder)
err = m_curFilter->ConvertMoveToFolderValue(currentFilterAction, value);
if (type == nsMsgFilterAction::MoveToFolder ||
type == nsMsgFilterAction::CopyToFolder)
{
err = m_curFilter->ConvertMoveOrCopyToFolderValue(currentFilterAction, value);
}
else if (type == nsMsgFilterAction::ChangePriority)
{
nsMsgPriorityValue outPriority;
@ -1048,7 +1051,8 @@ NS_IMETHODIMP nsMsgFilterList::MatchOrChangeFilterTarget(const char *oldFolderUr
else
continue;
if (actionType == nsMsgFilterAction::MoveToFolder)
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder)
{
rv = filterAction->GetTargetFolderUri(getter_Copies(folderUri));
if (NS_SUCCEEDED(rv) && folderUri)

Просмотреть файл

@ -508,7 +508,8 @@ nsresult nsMsgFilterAfterTheFact::ApplyFilter()
continue;
nsXPIDLCString actionTargetFolderUri;
if (actionType == nsMsgFilterAction::MoveToFolder)
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder)
{
filterAction->GetTargetFolderUri(getter_Copies(actionTargetFolderUri));
if (actionTargetFolderUri.IsEmpty())
@ -544,8 +545,9 @@ nsresult nsMsgFilterAfterTheFact::ApplyFilter()
applyMoreActions = PR_FALSE;
break;
case nsMsgFilterAction::MoveToFolder:
case nsMsgFilterAction::CopyToFolder:
{
// if moving to a different file, do it.
// if moving or copying to a different file, do it.
nsXPIDLCString uri;
rv = m_curFolder->GetURI(getter_Copies(uri));
@ -582,10 +584,11 @@ nsresult nsMsgFilterAfterTheFact::ApplyFilter()
}
nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
if (copyService)
return copyService->CopyMessages(m_curFolder, m_searchHitHdrs, destIFolder, PR_TRUE, this, m_msgWindow, PR_FALSE);
return copyService->CopyMessages(m_curFolder, m_searchHitHdrs, destIFolder, actionType == nsMsgFilterAction::MoveToFolder, this, m_msgWindow, PR_FALSE);
}
//we have already moved the hdrs so we can't apply more actions
applyMoreActions = PR_FALSE;
if (actionType == nsMsgFilterAction::MoveToFolder)
applyMoreActions = PR_FALSE;
}
break;

Просмотреть файл

@ -3204,7 +3204,8 @@ NS_IMETHODIMP nsImapMailFolder::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWindo
continue;
if (NS_SUCCEEDED(filterAction->GetType(&actionType)))
{
if (actionType == nsMsgFilterAction::MoveToFolder)
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder)
{
filterAction->GetTargetFolderUri(getter_Copies(actionTargetFolderUri));
if (actionTargetFolderUri.IsEmpty())
@ -3272,6 +3273,42 @@ NS_IMETHODIMP nsImapMailFolder::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWindo
*applyMore = PR_FALSE;
}
break;
case nsMsgFilterAction::CopyToFolder:
{
nsXPIDLCString uri;
rv = GetURI(getter_Copies(uri));
if (NS_STATIC_CAST(const char *, actionTargetFolderUri) &&
strcmp(uri, actionTargetFolderUri))
{
// XXXshaver I'm not actually 100% what the right semantics are for
// MDNs and copied messages, but I suspect deep down inside that
// we probably want to suppress them only on the copies.
msgHdr->GetFlags(&msgFlags);
if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && !isRead)
{
msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED);
msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags);
}
nsCOMPtr<nsISupportsArray> messageArray;
NS_NewISupportsArray(getter_AddRefs(messageArray));
messageArray->AppendElement(msgHdr);
nsCOMPtr<nsIMsgFolder> dstFolder;
rv = GetExistingFolder(actionTargetFolderUri,
getter_AddRefs(dstFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgCopyService> copyService =
do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = copyService->CopyMessages(this, messageArray, dstFolder,
PR_FALSE, nsnull, msgWindow, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
}
}
break;
case nsMsgFilterAction::MarkRead:
{
nsMsgKeyArray keysToFlag;

Просмотреть файл

@ -75,6 +75,7 @@
#include "nsMsgSearchCore.h"
#include "nsMailHeaders.h"
#include "nsIMsgMailSession.h"
#include "nsIMsgCopyService.h"
static NS_DEFINE_CID(kCMailDB, NS_MAILDB_CID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
@ -1655,7 +1656,8 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi
if (NS_SUCCEEDED(filterAction->GetType(&actionType)))
{
if (actionType == nsMsgFilterAction::MoveToFolder)
if (actionType == nsMsgFilterAction::MoveToFolder ||
actionType == nsMsgFilterAction::CopyToFolder)
{
filterAction->GetTargetFolderUri(getter_Copies(actionTargetFolderUri));
if (actionTargetFolderUri.IsEmpty())
@ -1722,6 +1724,33 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi
}
*applyMore = PR_FALSE;
break;
case nsMsgFilterAction::CopyToFolder:
{
nsXPIDLCString uri;
rv = m_rootFolder->GetURI(getter_Copies(uri));
if (NS_STATIC_CAST(const char*, actionTargetFolderUri) &&
strcmp(uri, actionTargetFolderUri))
{
nsCOMPtr<nsISupportsArray> messageArray;
NS_NewISupportsArray(getter_AddRefs(messageArray));
messageArray->AppendElement(msgHdr);
nsCOMPtr<nsIMsgFolder> dstFolder;
rv = GetExistingFolder(actionTargetFolderUri,
getter_AddRefs(dstFolder));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgCopyService> copyService =
do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = copyService->CopyMessages(m_rootFolder, messageArray, dstFolder,
PR_FALSE, nsnull, msgWindow, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
}
}
break;
case nsMsgFilterAction::MarkRead:
msgIsNew = PR_FALSE;
MarkFilteredMessageRead(msgHdr);
@ -1815,7 +1844,7 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi
default:
break;
}
if (loggingEnabled && actionType != nsMsgFilterAction::MoveToFolder && actionType != nsMsgFilterAction::Delete)
if (loggingEnabled && actionType != nsMsgFilterAction::MoveToFolder && actionType != nsMsgFilterAction::Delete)
(void)filter->LogRuleHit(filterAction, msgHdr);
}
}