add support for unlimited number of tags per profile and per message, replace labels with tags, sr=mscott, sspitzer 114656
This commit is contained in:
Родитель
a03e79b499
Коммит
44aee4259f
|
@ -214,12 +214,6 @@ var DefaultController =
|
||||||
case "cmd_applyFilters":
|
case "cmd_applyFilters":
|
||||||
case "cmd_runJunkControls":
|
case "cmd_runJunkControls":
|
||||||
case "cmd_deleteJunk":
|
case "cmd_deleteJunk":
|
||||||
case "cmd_label0":
|
|
||||||
case "cmd_label1":
|
|
||||||
case "cmd_label2":
|
|
||||||
case "cmd_label3":
|
|
||||||
case "cmd_label4":
|
|
||||||
case "cmd_label5":
|
|
||||||
case "button_file":
|
case "button_file":
|
||||||
case "cmd_file":
|
case "cmd_file":
|
||||||
case "cmd_emptyTrash":
|
case "cmd_emptyTrash":
|
||||||
|
@ -346,12 +340,6 @@ var DefaultController =
|
||||||
case "button_mark":
|
case "button_mark":
|
||||||
case "cmd_markAsRead":
|
case "cmd_markAsRead":
|
||||||
case "cmd_markThreadAsRead":
|
case "cmd_markThreadAsRead":
|
||||||
case "cmd_label0":
|
|
||||||
case "cmd_label1":
|
|
||||||
case "cmd_label2":
|
|
||||||
case "cmd_label3":
|
|
||||||
case "cmd_label4":
|
|
||||||
case "cmd_label5":
|
|
||||||
return GetNumSelectedMessages() > 0;
|
return GetNumSelectedMessages() > 0;
|
||||||
case "button_previous":
|
case "button_previous":
|
||||||
case "button_next":
|
case "button_next":
|
||||||
|
@ -646,24 +634,6 @@ var DefaultController =
|
||||||
return;
|
return;
|
||||||
case "cmd_deleteJunk":
|
case "cmd_deleteJunk":
|
||||||
deleteJunkInFolder();
|
deleteJunkInFolder();
|
||||||
return;
|
|
||||||
case "cmd_label0":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label0);
|
|
||||||
return;
|
|
||||||
case "cmd_label1":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label1);
|
|
||||||
return;
|
|
||||||
case "cmd_label2":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label2);
|
|
||||||
return;
|
|
||||||
case "cmd_label3":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label3);
|
|
||||||
return;
|
|
||||||
case "cmd_label4":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label4);
|
|
||||||
return;
|
|
||||||
case "cmd_label5":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label5);
|
|
||||||
return;
|
return;
|
||||||
case "cmd_emptyTrash":
|
case "cmd_emptyTrash":
|
||||||
MsgEmptyTrash();
|
MsgEmptyTrash();
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# Håkan Waara <hwaara@chello.se>
|
# Håkan Waara <hwaara@chello.se>
|
||||||
# Jan Varga <varga@nixcorp.com>
|
# Jan Varga <varga@nixcorp.com>
|
||||||
# Seth Spitzer <sspitzer@netscape.com>
|
# Seth Spitzer <sspitzer@netscape.com>
|
||||||
# David Bienvenu <bienvenu@netscape.com>
|
# David Bienvenu <bienvenu@nventure.com>
|
||||||
#
|
#
|
||||||
# Alternatively, the contents of this file may be used under the terms of
|
# Alternatively, the contents of this file may be used under the terms of
|
||||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -554,58 +554,92 @@ function SetMenuItemLabel(menuItemId, customLabel)
|
||||||
menuItem.setAttribute('label', customLabel);
|
menuItem.setAttribute('label', customLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function InitMessageLabel(menuType)
|
function TagCurMessage(key)
|
||||||
{
|
{
|
||||||
var color;
|
// ###need to do all selected messsages
|
||||||
|
var msgHdr = gDBView.hdrForFirstSelectedMessage;
|
||||||
|
var messages = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
|
||||||
|
messages.AppendElement(msgHdr);
|
||||||
|
msgHdr.folder.addKeywordToMessages(messages, key);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
function UnTagCurMessage(key)
|
||||||
|
{
|
||||||
|
// ###need to do all selected messsages
|
||||||
|
var msgHdr = gDBView.hdrForFirstSelectedMessage;
|
||||||
|
var messages = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
|
||||||
|
messages.AppendElement(msgHdr);
|
||||||
|
msgHdr.folder.removeKeywordFromMessages(messages, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function AddTag()
|
||||||
|
{
|
||||||
|
var args = {result: "", okCallback: AddTagCallback};
|
||||||
|
var dialog = window.openDialog(
|
||||||
|
"chrome://messenger/content/newTagDialog.xul",
|
||||||
|
"",
|
||||||
|
"chrome,titlebar,modal",
|
||||||
|
args);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AddTagCallback(name, color)
|
||||||
|
{
|
||||||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
|
||||||
|
tagService.addTag(name, color);
|
||||||
|
TagCurMessage(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function InitMessageTags(menuType)
|
||||||
|
{
|
||||||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
|
||||||
|
var allTags = tagService.tagEnumerator;
|
||||||
|
var allKeys = tagService.keyEnumerator;
|
||||||
|
// remove any existing entries...
|
||||||
|
var menuItemId = menuType + "-tagpopup";
|
||||||
|
var menupopupNode = document.getElementById(menuItemId);
|
||||||
|
for (var i = menupopupNode.childNodes.length - 1; i >= 0; --i)
|
||||||
|
menupopupNode.removeChild(menupopupNode.childNodes[i]);
|
||||||
|
|
||||||
|
// now rebuild the list
|
||||||
|
var msgHdr = gDBView.hdrForFirstSelectedMessage;
|
||||||
|
var curKeys = msgHdr.getStringProperty("keywords");
|
||||||
|
var newMenuItem;
|
||||||
|
|
||||||
|
var curMsgHdrKeyArray = curKeys.split(" ");
|
||||||
|
|
||||||
|
while (allTags.hasMore())
|
||||||
|
{
|
||||||
|
var tag = allTags.getNext();
|
||||||
|
var key = allKeys.getNext();
|
||||||
|
// TODO we want to either remove or "check" the tags that already exist
|
||||||
|
newMenuItem = document.createElement('menuitem');
|
||||||
|
newMenuItem.setAttribute('label', tag);
|
||||||
|
newMenuItem.setAttribute('value', key);
|
||||||
|
newMenuItem.setAttribute('type', 'checkbox');
|
||||||
|
var keySet = false;
|
||||||
|
for ( var index = 0; index < curMsgHdrKeyArray.length; index++ )
|
||||||
{
|
{
|
||||||
var isChecked = true;
|
if (key == curMsgHdrKeyArray[index])
|
||||||
var checkedLabel = gDBView.hdrForFirstSelectedMessage.label;
|
{
|
||||||
}
|
keySet = true;
|
||||||
catch(ex)
|
break;
|
||||||
{
|
}
|
||||||
isChecked = false;
|
|
||||||
}
|
}
|
||||||
|
// if we already have this tag, we should change the command to "UnTag"
|
||||||
|
var command = ((keySet) ? "Un" : "") + "TagCurMessage(" + "'" + key + "');";
|
||||||
|
newMenuItem.setAttribute('oncommand', command);
|
||||||
|
newMenuItem.setAttribute('checked', keySet);
|
||||||
|
menupopupNode.appendChild(newMenuItem);
|
||||||
|
}
|
||||||
|
var menuseparator = document.createElement('menuseparator');
|
||||||
|
menupopupNode.appendChild(menuseparator);
|
||||||
|
|
||||||
for (var label = 0; label <= 5; label++)
|
newMenuItem = document.createElement('menuitem');
|
||||||
{
|
newMenuItem.setAttribute('label', gMessengerBundle.getString("newTag"));
|
||||||
try
|
newMenuItem.setAttribute('oncommand', "AddTag()");
|
||||||
{
|
menupopupNode.appendChild(newMenuItem);
|
||||||
var prefString = gPrefBranch.getComplexValue("mailnews.labels.description." + label,
|
|
||||||
Components.interfaces.nsIPrefLocalizedString);
|
|
||||||
var formattedPrefString = gMessengerBundle.getFormattedString("labelMenuItemFormat" + label,
|
|
||||||
[prefString], 1);
|
|
||||||
var menuItemId = menuType + "-labelMenuItem" + label;
|
|
||||||
var menuItem = document.getElementById(menuItemId);
|
|
||||||
|
|
||||||
SetMenuItemLabel(menuItemId, formattedPrefString);
|
|
||||||
if (isChecked && label == checkedLabel)
|
|
||||||
menuItem.setAttribute("checked", "true");
|
|
||||||
else
|
|
||||||
menuItem.setAttribute("checked", "false");
|
|
||||||
|
|
||||||
// commented out for now until UE decides on how to show the Labels menu items.
|
|
||||||
// This code will color either the text or background for the Labels menu items.
|
|
||||||
/*****
|
|
||||||
if (label != 0)
|
|
||||||
{
|
|
||||||
color = prefBranch.getCharPref("mailnews.labels.color." + label);
|
|
||||||
// this colors the text of the menuitem only.
|
|
||||||
//menuItem.setAttribute("style", ("color: " + color));
|
|
||||||
|
|
||||||
// this colors the background of the menuitem and
|
|
||||||
// when selected, text becomes white.
|
|
||||||
//menuItem.setAttribute("style", ("color: #FFFFFF"));
|
|
||||||
//menuItem.setAttribute("style", ("background-color: " + color));
|
|
||||||
}
|
|
||||||
****/
|
|
||||||
}
|
|
||||||
catch(ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.commandDispatcher.updateCommands('create-menu-label');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function InitMessageMark()
|
function InitMessageMark()
|
||||||
|
|
|
@ -606,45 +606,8 @@
|
||||||
</rule>
|
</rule>
|
||||||
</template>
|
</template>
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="threadPaneContext-labels" label="&labelMenu.label;" accesskey="&labelMenu.accesskey;">
|
<menu id="threadPaneContext-tags" label="&tagMenu.label;" accesskey="&tagMenu.accesskey;">
|
||||||
<menupopup onpopupshowing="InitMessageLabel('threadPaneContext')">
|
<menupopup id="threadPaneContext-tagpopup" onpopupshowing="InitMessageTags('threadPaneContext')">
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem0"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd0.accesskey;"
|
|
||||||
observes="cmd_label0"/>
|
|
||||||
<menuseparator/>
|
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem1"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd1.accesskey;"
|
|
||||||
observes="cmd_label1"/>
|
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem2"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd2.accesskey;"
|
|
||||||
observes="cmd_label2"/>
|
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem3"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd3.accesskey;"
|
|
||||||
observes="cmd_label3"/>
|
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem4"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd4.accesskey;"
|
|
||||||
observes="cmd_label4"/>
|
|
||||||
<menuitem
|
|
||||||
id="threadPaneContext-labelMenuItem5"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd5.accesskey;"
|
|
||||||
observes="cmd_label5"/>
|
|
||||||
</menupopup>
|
</menupopup>
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="threadPaneContext-mark" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
<menu id="threadPaneContext-mark" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
||||||
|
@ -948,46 +911,9 @@
|
||||||
</rule>
|
</rule>
|
||||||
</template>
|
</template>
|
||||||
</menu>
|
</menu>
|
||||||
<menuseparator id="messagePaneContext-sep-labels-1"/>
|
<menuseparator id="messagePaneContext-sep-tags-1"/>
|
||||||
<menu id="messagePaneContext-labels" label="&labelMenu.label;" accesskey="&labelMenu.accesskey;">
|
<menu id="messagePaneContext-tags" label="&tagMenu.label;" accesskey="&tagMenu.accesskey;">
|
||||||
<menupopup onpopupshowing="InitMessageLabel('messagePaneContext')">
|
<menupopup id="messagePaneContext-tagpopup" onpopupshowing="InitMessageTags('messagePaneContext')">
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem0"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd0.accesskey;"
|
|
||||||
observes="cmd_label0"/>
|
|
||||||
<menuseparator/>
|
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem1"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd1.accesskey;"
|
|
||||||
observes="cmd_label1"/>
|
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem2"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd2.accesskey;"
|
|
||||||
observes="cmd_label2"/>
|
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem3"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd3.accesskey;"
|
|
||||||
observes="cmd_label3"/>
|
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem4"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd4.accesskey;"
|
|
||||||
observes="cmd_label4"/>
|
|
||||||
<menuitem
|
|
||||||
id="messagePaneContext-labelMenuItem5"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd5.accesskey;"
|
|
||||||
observes="cmd_label5"/>
|
|
||||||
</menupopup>
|
</menupopup>
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="messagePaneContext-mark" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
<menu id="messagePaneContext-mark" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
||||||
|
@ -1613,85 +1539,48 @@
|
||||||
</template>
|
</template>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
||||||
<menu id="labelMenu" label="&labelMenu.label;" accesskey="&labelMenu.accesskey;">
|
<menu id="messagePaneContext-tags" label="&tagMenu.label;" accesskey="&tagMenu.accesskey;">
|
||||||
<menupopup id="menuPopup-labels" onpopupshowing="InitMessageLabel('menuPopup')">
|
<menupopup id="messagePaneContext-tagpopup" onpopupshowing="InitMessageTags('messagePaneContext')">
|
||||||
<menuitem
|
</menupopup>
|
||||||
id="menuPopup-labelMenuItem0"
|
</menu>
|
||||||
type="radio"
|
<menu id="markMenu" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
||||||
checked="false"
|
<menupopup onpopupshowing="InitMessageMark()">
|
||||||
accesskey="&labelCmd0.accesskey;"
|
<menuitem type="checkbox" id="markReadMenuItem" label="&markAsReadCmd.label;" accesskey="&markAsReadCmd.accesskey;" observes="cmd_markAsRead"
|
||||||
observes="cmd_label0"/>
|
ifndef="" XP_MACOSX=""
|
||||||
<menuseparator/>
|
|
||||||
<menuitem
|
|
||||||
id="menuPopup-labelMenuItem1"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd1.accesskey;"
|
|
||||||
observes="cmd_label1"/>
|
|
||||||
<menuitem
|
|
||||||
id="menuPopup-labelMenuItem2"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd2.accesskey;"
|
|
||||||
observes="cmd_label2"/>
|
|
||||||
<menuitem
|
|
||||||
id="menuPopup-labelMenuItem3"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd3.accesskey;"
|
|
||||||
observes="cmd_label3"/>
|
|
||||||
<menuitem
|
|
||||||
id="menuPopup-labelMenuItem4"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd4.accesskey;"
|
|
||||||
observes="cmd_label4"/>
|
|
||||||
<menuitem
|
|
||||||
id="menuPopup-labelMenuItem5"
|
|
||||||
type="radio"
|
|
||||||
checked="false"
|
|
||||||
accesskey="&labelCmd5.accesskey;"
|
|
||||||
observes="cmd_label5"/>
|
|
||||||
</menupopup>
|
|
||||||
</menu>
|
|
||||||
<menu id="markMenu" label="&markMenu.label;" accesskey="&markMenu.accesskey;">
|
|
||||||
<menupopup onpopupshowing="InitMessageMark()">
|
|
||||||
<menuitem type="checkbox" id="markReadMenuItem" label="&markAsReadCmd.label;" accesskey="&markAsReadCmd.accesskey;" observes="cmd_markAsRead"
|
|
||||||
#ifndef XP_MACOSX
|
|
||||||
key="key_toggleRead"
|
key="key_toggleRead"
|
||||||
#endif
|
endif=""
|
||||||
/>
|
/>
|
||||||
<menuitem label="&markThreadAsReadCmd.label;" accesskey="&markThreadAsReadCmd.accesskey;" observes="cmd_markThreadAsRead"
|
<menuitem label="&markThreadAsReadCmd.label;" accesskey="&markThreadAsReadCmd.accesskey;" observes="cmd_markThreadAsRead"
|
||||||
#ifndef XP_MACOSX
|
ifndef="" XP_MACOSX=""
|
||||||
key="key_markThreadAsRead"
|
key="key_markThreadAsRead"
|
||||||
#endif
|
endif=""
|
||||||
/>
|
/>
|
||||||
<menuitem label="&markReadByDateCmd.label;" accesskey="&markReadByDateCmd.accesskey;" command="cmd_markReadByDate"
|
<menuitem label="&markReadByDateCmd.label;" accesskey="&markReadByDateCmd.accesskey;" command="cmd_markReadByDate"
|
||||||
#ifndef XP_MACOSX
|
ifndef="" XP_MACOSX=""
|
||||||
key="key_markReadByDate"
|
key="key_markReadByDate"
|
||||||
#endif
|
endif=""
|
||||||
/>
|
/>
|
||||||
<menuitem label="&markAllReadCmd.label;" key="key_markAllRead" accesskey="&markAllReadCmd.accesskey;" observes="cmd_markAllRead"/>
|
<menuitem label="&markAllReadCmd.label;" key="key_markAllRead" accesskey="&markAllReadCmd.accesskey;" observes="cmd_markAllRead"/>
|
||||||
<menuseparator/>
|
<menuseparator/>
|
||||||
<menuitem id="markFlaggedMenuItem"
|
<menuitem id="markFlaggedMenuItem"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
label="&markFlaggedCmd.label;"
|
label="&markFlaggedCmd.label;"
|
||||||
accesskey="&markFlaggedCmd.accesskey;"
|
accesskey="&markFlaggedCmd.accesskey;"
|
||||||
observes="cmd_markAsFlagged"
|
observes="cmd_markAsFlagged"
|
||||||
#ifndef XP_MACOSX
|
ifndef="" XP_MACOSX=""
|
||||||
key="key_toggleFlagged"
|
key="key_toggleFlagged"
|
||||||
#endif
|
endif=""
|
||||||
/>
|
/>
|
||||||
<menuseparator/>
|
<menuseparator/>
|
||||||
<menuitem label="&markAsJunkCmd.label;"
|
<menuitem label="&markAsJunkCmd.label;"
|
||||||
accesskey="&markAsJunkCmd.accesskey;"
|
accesskey="&markAsJunkCmd.accesskey;"
|
||||||
observes="cmd_markAsJunk"
|
observes="cmd_markAsJunk"
|
||||||
#ifndef XP_MACOSX
|
ifndef="" XP_MACOSX=""
|
||||||
key="key_markJunk"
|
key="key_markJunk"
|
||||||
#endif
|
endif=""
|
||||||
/>
|
/>
|
||||||
<menuitem label="&markAsNotJunkCmd.label;"
|
<menuitem label="&markAsNotJunkCmd.label;"
|
||||||
key="key_markNotJunk"
|
key="key_markNotJunk"
|
||||||
accesskey="&markAsNotJunkCmd.accesskey;"
|
accesskey="&markAsNotJunkCmd.accesskey;"
|
||||||
observes="cmd_markAsNotJunk"/>
|
observes="cmd_markAsNotJunk"/>
|
||||||
<menuitem label="&recalculateJunkScoreCmd.label;"
|
<menuitem label="&recalculateJunkScoreCmd.label;"
|
||||||
|
|
|
@ -1053,24 +1053,6 @@ var MessageWindowController =
|
||||||
case "cmd_recalculateJunkScore":
|
case "cmd_recalculateJunkScore":
|
||||||
analyzeMessagesForJunk();
|
analyzeMessagesForJunk();
|
||||||
return;
|
return;
|
||||||
case "cmd_label0":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label0);
|
|
||||||
return;
|
|
||||||
case "cmd_label1":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label1);
|
|
||||||
return;
|
|
||||||
case "cmd_label2":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label2);
|
|
||||||
return;
|
|
||||||
case "cmd_label3":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label3);
|
|
||||||
return;
|
|
||||||
case "cmd_label4":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label4);
|
|
||||||
return;
|
|
||||||
case "cmd_label5":
|
|
||||||
gDBView.doCommand(nsMsgViewCommandType.label5);
|
|
||||||
return;
|
|
||||||
case "cmd_downloadFlagged":
|
case "cmd_downloadFlagged":
|
||||||
MsgDownloadFlagged();
|
MsgDownloadFlagged();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -112,8 +112,8 @@ searchterm {
|
||||||
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-folder");
|
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
.ruleactiontarget[type="labelmessageas"] {
|
.ruleactiontarget[type="addtagtomessage"] {
|
||||||
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-label");
|
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
.ruleactiontarget[type="setpriorityto"] {
|
.ruleactiontarget[type="setpriorityto"] {
|
||||||
|
|
|
@ -68,6 +68,8 @@ messenger.jar:
|
||||||
content/messenger/shareglue.js (/mailnews/base/resources/content/shareglue.js)
|
content/messenger/shareglue.js (/mailnews/base/resources/content/shareglue.js)
|
||||||
content/messenger/newFolderDialog.xul (/mailnews/base/resources/content/newFolderDialog.xul)
|
content/messenger/newFolderDialog.xul (/mailnews/base/resources/content/newFolderDialog.xul)
|
||||||
content/messenger/newFolderDialog.js (/mailnews/base/resources/content/newFolderDialog.js)
|
content/messenger/newFolderDialog.js (/mailnews/base/resources/content/newFolderDialog.js)
|
||||||
|
content/messenger/newTagDialog.xul (/mailnews/base/resources/content/newTagDialog.xul)
|
||||||
|
content/messenger/newTagDialog.js (/mailnews/base/resources/content/newTagDialog.js)
|
||||||
content/messenger/msgViewNavigation.js (/mailnews/base/resources/content/msgViewNavigation.js)
|
content/messenger/msgViewNavigation.js (/mailnews/base/resources/content/msgViewNavigation.js)
|
||||||
content/messenger/msgAccountCentral.xul (/mailnews/base/resources/content/msgAccountCentral.xul)
|
content/messenger/msgAccountCentral.xul (/mailnews/base/resources/content/msgAccountCentral.xul)
|
||||||
content/messenger/msgAccountCentral.js (/mailnews/base/resources/content/msgAccountCentral.js)
|
content/messenger/msgAccountCentral.js (/mailnews/base/resources/content/msgAccountCentral.js)
|
||||||
|
|
|
@ -389,6 +389,7 @@ FeedItem.prototype =
|
||||||
openingLine +
|
openingLine +
|
||||||
'X-Mozilla-Status: 0000\n' +
|
'X-Mozilla-Status: 0000\n' +
|
||||||
'X-Mozilla-Status2: 00000000\n' +
|
'X-Mozilla-Status2: 00000000\n' +
|
||||||
|
'X-Mozilla-Keys: \n' +
|
||||||
'Date: ' + this.mDate + '\n' +
|
'Date: ' + this.mDate + '\n' +
|
||||||
'Message-Id: <' + this.messageID + '>\n' +
|
'Message-Id: <' + this.messageID + '>\n' +
|
||||||
'From: ' + this.author + '\n' +
|
'From: ' + this.author + '\n' +
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
<!ENTITY markMessageFlagged.label "Mark As Flagged">
|
<!ENTITY markMessageFlagged.label "Mark As Flagged">
|
||||||
<!ENTITY labelMessage.label "Label Message As">
|
<!ENTITY labelMessage.label "Label Message As">
|
||||||
<!ENTITY setPriority.label "Set Priority to">
|
<!ENTITY setPriority.label "Set Priority to">
|
||||||
|
<!ENTITY addTag.label "Tag Message">
|
||||||
<!ENTITY setJunkScore.label "Set Junk Status to">
|
<!ENTITY setJunkScore.label "Set Junk Status to">
|
||||||
<!ENTITY deleteMessage.label "Delete Message">
|
<!ENTITY deleteMessage.label "Delete Message">
|
||||||
<!ENTITY deleteFromPOP.label "Delete From POP Server">
|
<!ENTITY deleteFromPOP.label "Delete From POP Server">
|
||||||
|
|
|
@ -330,6 +330,8 @@
|
||||||
<!ENTITY fileHereMenu.accesskey "F">
|
<!ENTITY fileHereMenu.accesskey "F">
|
||||||
<!ENTITY copyHereMenu.label "Copy Here">
|
<!ENTITY copyHereMenu.label "Copy Here">
|
||||||
<!ENTITY copyHereMenu.accesskey "C">
|
<!ENTITY copyHereMenu.accesskey "C">
|
||||||
|
<!ENTITY tagMenu.label "Tag">
|
||||||
|
<!ENTITY tagMenu.accesskey "g">
|
||||||
<!ENTITY labelMenu.label "Label">
|
<!ENTITY labelMenu.label "Label">
|
||||||
<!ENTITY labelMenu.accesskey "L">
|
<!ENTITY labelMenu.accesskey "L">
|
||||||
<!ENTITY labelCmd0.accesskey "0">
|
<!ENTITY labelCmd0.accesskey "0">
|
||||||
|
|
|
@ -48,6 +48,7 @@ newSubfolderMenuItem=Subfolder...
|
||||||
newFolder=New Folder...
|
newFolder=New Folder...
|
||||||
newSubfolder=New Subfolder...
|
newSubfolder=New Subfolder...
|
||||||
folderProperties=Folder Properties
|
folderProperties=Folder Properties
|
||||||
|
newTag=New Tag...
|
||||||
getNextNMessages=Get Next %S News Messages
|
getNextNMessages=Get Next %S News Messages
|
||||||
advanceNextPrompt=Advance to next unread message in %S?
|
advanceNextPrompt=Advance to next unread message in %S?
|
||||||
titleNewsPreHost=on
|
titleNewsPreHost=on
|
||||||
|
@ -234,6 +235,9 @@ junk=Junk
|
||||||
# for the has attachment picker in search and mail views
|
# for the has attachment picker in search and mail views
|
||||||
hasAttachments=Has Attachments
|
hasAttachments=Has Attachments
|
||||||
|
|
||||||
|
# for the Tag picker in search and mail views.
|
||||||
|
tag=Tags
|
||||||
|
|
||||||
# mailnews.js
|
# mailnews.js
|
||||||
mailnews.send_default_charset=ISO-8859-1
|
mailnews.send_default_charset=ISO-8859-1
|
||||||
mailnews.view_default_charset=ISO-8859-1
|
mailnews.view_default_charset=ISO-8859-1
|
||||||
|
@ -361,6 +365,9 @@ passwordTitle=Mail Server Password Required
|
||||||
openWindowWarningTitle=Confirm
|
openWindowWarningTitle=Confirm
|
||||||
openWindowWarningText=Opening %S messages may be slow. Continue?
|
openWindowWarningText=Opening %S messages may be slow. Continue?
|
||||||
|
|
||||||
|
# for warning the user that a tag they're trying to create already exists
|
||||||
|
tagExists=A tag with that name already exists.
|
||||||
|
|
||||||
# for the virtual folder list dialog title
|
# for the virtual folder list dialog title
|
||||||
# %S is the name of the saved search folder
|
# %S is the name of the saved search folder
|
||||||
editVirtualFolderPropertiesTitle=Edit Saved Search Properties for %S
|
editVirtualFolderPropertiesTitle=Edit Saved Search Properties for %S
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||||
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
-
|
||||||
|
- The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
- the License. You may obtain a copy of the License at
|
||||||
|
- http://www.mozilla.org/MPL/
|
||||||
|
-
|
||||||
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
- for the specific language governing rights and limitations under the
|
||||||
|
- License.
|
||||||
|
-
|
||||||
|
- The Original Code is new tag dialog
|
||||||
|
-
|
||||||
|
- The Initial Developer of the Original Code is
|
||||||
|
- The Mozilla Corporation.
|
||||||
|
- Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
- the Initial Developer. All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
- of those above. If you wish to allow use of your version of this file only
|
||||||
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
- use your version of this file under the terms of the MPL, indicate your
|
||||||
|
- decision by deleting the provisions above and replace them with the notice
|
||||||
|
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
- the provisions above, a recipient may use your version of this file under
|
||||||
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
-
|
||||||
|
- ***** END LICENSE BLOCK ***** -->
|
||||||
|
|
||||||
|
<!-- Labels -->
|
||||||
|
<!ENTITY newTagDialog.title "New Tag">
|
||||||
|
<!ENTITY name.label "Tag:">
|
||||||
|
<!ENTITY name.accesskey "T">
|
|
@ -15,7 +15,7 @@
|
||||||
12=Folder Info
|
12=Folder Info
|
||||||
13=Size
|
13=Size
|
||||||
14=AnyText
|
14=AnyText
|
||||||
15=Keywords
|
15=Tags
|
||||||
# for AB and LDAP
|
# for AB and LDAP
|
||||||
16=Any Name
|
16=Any Name
|
||||||
17=Display Name
|
17=Display Name
|
||||||
|
@ -50,5 +50,5 @@
|
||||||
46=Attachment Status
|
46=Attachment Status
|
||||||
47=Junk Status
|
47=Junk Status
|
||||||
48=Label
|
48=Label
|
||||||
|
49=Customize
|
||||||
# don't use above 49
|
# don't use above 49
|
||||||
49=Customize...
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
locale/@AB_CD@/messenger/threadpane.dtd (%chrome/messenger/threadpane.dtd)
|
locale/@AB_CD@/messenger/threadpane.dtd (%chrome/messenger/threadpane.dtd)
|
||||||
locale/@AB_CD@/messenger/folderpane.dtd (%chrome/messenger/folderpane.dtd)
|
locale/@AB_CD@/messenger/folderpane.dtd (%chrome/messenger/folderpane.dtd)
|
||||||
locale/@AB_CD@/messenger/newFolderDialog.dtd (%chrome/messenger/newFolderDialog.dtd)
|
locale/@AB_CD@/messenger/newFolderDialog.dtd (%chrome/messenger/newFolderDialog.dtd)
|
||||||
|
locale/@AB_CD@/messenger/newTagDialog.dtd (%chrome/messenger/newTagDialog.dtd)
|
||||||
locale/@AB_CD@/messenger/renameFolderDialog.dtd (%chrome/messenger/renameFolderDialog.dtd)
|
locale/@AB_CD@/messenger/renameFolderDialog.dtd (%chrome/messenger/renameFolderDialog.dtd)
|
||||||
locale/@AB_CD@/messenger/folderProps.dtd (%chrome/messenger/folderProps.dtd)
|
locale/@AB_CD@/messenger/folderProps.dtd (%chrome/messenger/folderProps.dtd)
|
||||||
locale/@AB_CD@/messenger/subscribe.dtd (%chrome/messenger/subscribe.dtd)
|
locale/@AB_CD@/messenger/subscribe.dtd (%chrome/messenger/subscribe.dtd)
|
||||||
|
|
|
@ -70,6 +70,7 @@ XPIDLSRCS = \
|
||||||
nsIMsgMailSession.idl \
|
nsIMsgMailSession.idl \
|
||||||
nsIMsgMessageService.idl \
|
nsIMsgMessageService.idl \
|
||||||
nsIMsgSignature.idl \
|
nsIMsgSignature.idl \
|
||||||
|
nsIMsgTagService.idl \
|
||||||
nsIMsgThread.idl \
|
nsIMsgThread.idl \
|
||||||
nsIUrlListener.idl \
|
nsIUrlListener.idl \
|
||||||
nsIUrlListenerManager.idl \
|
nsIUrlListenerManager.idl \
|
||||||
|
|
|
@ -70,7 +70,7 @@ typedef long nsMsgBiffState;
|
||||||
// enumerated type for determining if a message has been replied to, forwarded, etc.
|
// enumerated type for determining if a message has been replied to, forwarded, etc.
|
||||||
typedef long nsMsgDispositionState;
|
typedef long nsMsgDispositionState;
|
||||||
|
|
||||||
[scriptable, uuid(28424d1c-db6f-4ac5-bc5d-418dd336120b)]
|
[scriptable, uuid(5711cb97-42ad-466d-9e8f-48b84a8b76a2)]
|
||||||
interface nsIMsgFolder : nsICollection {
|
interface nsIMsgFolder : nsICollection {
|
||||||
|
|
||||||
const nsMsgBiffState nsMsgBiffState_NewMail = 0; // User has new mail waiting.
|
const nsMsgBiffState nsMsgBiffState_NewMail = 0; // User has new mail waiting.
|
||||||
|
@ -497,4 +497,9 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne
|
||||||
in unsigned long aNumKeys, in boolean aLocalOnly,
|
in unsigned long aNumKeys, in boolean aLocalOnly,
|
||||||
in nsIUrlListener aUrlListener, out boolean aAsyncResults);
|
in nsIUrlListener aUrlListener, out boolean aAsyncResults);
|
||||||
|
|
||||||
|
// used to set/clear tags - we could have a single method to setKeywords which
|
||||||
|
// would figure out the diffs, but these methods might be more convenient.
|
||||||
|
void addKeywordToMessages(in nsISupportsArray aMessages, in string aKeyword);
|
||||||
|
void removeKeywordFromMessages(in nsISupportsArray aMessages, in string aKeyword);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* The Mozilla Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Bienvenu <bienvenu@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "nsISupports.idl"
|
||||||
|
#include "nsIStringEnumerator.idl"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keys are the internal representation of tags, and use a limited range of
|
||||||
|
* characters, basically the characters allowed in imap keywords, which are
|
||||||
|
* alphanumeric characters, but don't include spaces. Keys are stored on
|
||||||
|
* the imap server, in local mail messages, and in summary files.
|
||||||
|
*
|
||||||
|
* Tags are the user visible representation of keys, and are full unicode
|
||||||
|
* strings. Tags should allow any unicode character.
|
||||||
|
*
|
||||||
|
* This service will do the mapping between keys and tags. When a tag
|
||||||
|
* is added, we'll need to "compute" the corresponding key to use. This
|
||||||
|
* will probably entail replacing illegal ascii characters (' ', '/', etc)
|
||||||
|
* with '_' and then converting to imap mod utf7. We'll then need to make
|
||||||
|
* sure that no other keyword has the same value since that algorithm
|
||||||
|
* doesn't guarantee a unique mapping.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
[scriptable, uuid(ad04db53-cfcc-47eb-b409-b24b3a0b6130)]
|
||||||
|
interface nsIMsgTagService : nsISupports {
|
||||||
|
AString getTagForKey(in ACString key); // look up the tag for a key.
|
||||||
|
void setTagForKey(in ACString key, in AString tag); // this can be used to "rename" a tag
|
||||||
|
ACString getKeyForTag(in AString tag); // get the key representation of a given tag
|
||||||
|
void addTagForKey(in ACString key, in AString tag, in ACString color);
|
||||||
|
void addTag(in AString tag, in ACString color);
|
||||||
|
ACString getColorForKey(in ACString key);
|
||||||
|
void deleteTag(in AString tag);
|
||||||
|
// we need some way to enumerate all tags. Or return a list of all tags.
|
||||||
|
readonly attribute nsIStringEnumerator tagEnumerator;
|
||||||
|
readonly attribute nsIUTF8StringEnumerator keyEnumerator;
|
||||||
|
};
|
||||||
|
|
|
@ -516,6 +516,16 @@
|
||||||
{0x9c, 0xff, 0x2a, 0x66, 0x33, 0x33, 0x3b, 0x2b }}
|
{0x9c, 0xff, 0x2a, 0x66, 0x33, 0x33, 0x3b, 0x2b }}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// nsMsgTagService
|
||||||
|
//
|
||||||
|
#define NS_MSGTAGSERVICE_CONTRACTID \
|
||||||
|
"@mozilla.org/messenger/tagservice;1"
|
||||||
|
|
||||||
|
#define NS_MSGTAGSERVICE_CID \
|
||||||
|
{ /* ad04db53-cfcc-47eb-b409-b24b3a0b6130 */ \
|
||||||
|
0xad04db53, 0xcfcc, 0x47eb, \
|
||||||
|
{ 0xb4, 0x09, 0xb2, 0x4b, 0x3a, 0x0b, 0x61, 0x30}}
|
||||||
|
//
|
||||||
// nsMessengerOSIntegration
|
// nsMessengerOSIntegration
|
||||||
//
|
//
|
||||||
#define NS_MESSENGEROSINTEGRATION_CONTRACTID \
|
#define NS_MESSENGEROSINTEGRATION_CONTRACTID \
|
||||||
|
|
|
@ -64,4 +64,7 @@
|
||||||
/* Provide a common means of detecting empty lines in a message. i.e. to detect the end of headers among other things...*/
|
/* Provide a common means of detecting empty lines in a message. i.e. to detect the end of headers among other things...*/
|
||||||
#define EMPTY_MESSAGE_LINE(buf) (buf[0] == nsCRT::CR || buf[0] == nsCRT::LF || buf[0] == '\0')
|
#define EMPTY_MESSAGE_LINE(buf) (buf[0] == nsCRT::CR || buf[0] == nsCRT::LF || buf[0] == '\0')
|
||||||
|
|
||||||
|
/* blank filled header to store keyword/tags in the mailbox */
|
||||||
|
#define X_MOZILLA_KEYWORDS HEADER_X_MOZILLA_KEYWORDS ": " MSG_LINEBREAK
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1235,7 +1235,8 @@
|
||||||
<!-- searchvalue - a widget which dynamically changes its user interface
|
<!-- searchvalue - a widget which dynamically changes its user interface
|
||||||
depending on what type of data it's supposed to be showing
|
depending on what type of data it's supposed to be showing
|
||||||
currently handles arbitrary text entry, and menulists for
|
currently handles arbitrary text entry, and menulists for
|
||||||
priority, status, junk status, hasAttachment status, and addressbook
|
priority, status, junk status, tags, hasAttachment status,
|
||||||
|
and addressbook
|
||||||
-->
|
-->
|
||||||
<binding id="searchvalue" name="searchValue">
|
<binding id="searchvalue" name="searchValue">
|
||||||
<content>
|
<content>
|
||||||
|
@ -1277,12 +1278,6 @@
|
||||||
</xul:menulist>
|
</xul:menulist>
|
||||||
<xul:menulist flex="1" class="search-value-menulist">
|
<xul:menulist flex="1" class="search-value-menulist">
|
||||||
<xul:menupopup class="search-value-popup">
|
<xul:menupopup class="search-value-popup">
|
||||||
<xul:menuitem value="0" class="search-value-menuitem"/>
|
|
||||||
<xul:menuitem value="1" class="search-value-menuitem"/>
|
|
||||||
<xul:menuitem value="2" class="search-value-menuitem"/>
|
|
||||||
<xul:menuitem value="3" class="search-value-menuitem"/>
|
|
||||||
<xul:menuitem value="4" class="search-value-menuitem"/>
|
|
||||||
<xul:menuitem value="5" class="search-value-menuitem"/>
|
|
||||||
</xul:menupopup>
|
</xul:menupopup>
|
||||||
</xul:menulist>
|
</xul:menulist>
|
||||||
<xul:menulist flex="1" class="search-value-menulist">
|
<xul:menulist flex="1" class="search-value-menulist">
|
||||||
|
@ -1375,12 +1370,7 @@
|
||||||
// it's a text search, so show the textbox
|
// it's a text search, so show the textbox
|
||||||
this.setAttribute("selectedIndex", "0");
|
this.setAttribute("selectedIndex", "0");
|
||||||
}
|
}
|
||||||
else if (val == Components.interfaces.nsMsgSearchAttrib.Label)
|
else if (val == Components.interfaces.nsMsgSearchAttrib.Keywords) {
|
||||||
{
|
|
||||||
var children = document.getAnonymousNodes(this);
|
|
||||||
var abs = children[5].getElementsByAttribute("value", "1");
|
|
||||||
if (abs.item(0))
|
|
||||||
children[5].selectedItem = abs[0];
|
|
||||||
this.setAttribute("selectedIndex", "5");
|
this.setAttribute("selectedIndex", "5");
|
||||||
}
|
}
|
||||||
else if (val == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
|
else if (val == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
|
||||||
|
@ -1433,11 +1423,14 @@
|
||||||
else
|
else
|
||||||
children[0].value = val.str;
|
children[0].value = val.str;
|
||||||
}
|
}
|
||||||
else if (attrib == nsMsgSearchAttrib.Label)
|
else if (attrib == nsMsgSearchAttrib.Keywords)
|
||||||
{
|
{
|
||||||
var labelVal = children[5].getElementsByAttribute("value", val.label);
|
var keywordVal = children[5].getElementsByAttribute("value", val.str);
|
||||||
if (labelVal.item(0))
|
if (keywordVal.item(0))
|
||||||
children[5].selectedItem = labelVal[0];
|
{
|
||||||
|
children[5].value = val.str;
|
||||||
|
children[5].selectedItem = keywordVal[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (attrib == nsMsgSearchAttrib.JunkStatus) {
|
else if (attrib == nsMsgSearchAttrib.JunkStatus) {
|
||||||
var junkStatus =
|
var junkStatus =
|
||||||
|
@ -1485,8 +1478,10 @@
|
||||||
else
|
else
|
||||||
searchValue.str = children[0].value;
|
searchValue.str = children[0].value;
|
||||||
}
|
}
|
||||||
else if (searchAttribute == nsMsgSearchAttrib.Label)
|
else if (searchAttribute == nsMsgSearchAttrib.Keywords)
|
||||||
searchValue.label = children[5].selectedItem.value;
|
{
|
||||||
|
searchValue.str = children[5].value;
|
||||||
|
}
|
||||||
else if (searchAttribute == nsMsgSearchAttrib.JunkStatus)
|
else if (searchAttribute == nsMsgSearchAttrib.JunkStatus)
|
||||||
searchValue.junkStatus = children[6].value;
|
searchValue.junkStatus = children[6].value;
|
||||||
else if (searchAttribute == nsMsgSearchAttrib.Size)
|
else if (searchAttribute == nsMsgSearchAttrib.Size)
|
||||||
|
@ -1507,6 +1502,33 @@
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="fillInTags">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
var children = document.getAnonymousNodes(this);
|
||||||
|
var popupMenu = children[5].firstChild;
|
||||||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
|
||||||
|
var allTags = tagService.tagEnumerator;
|
||||||
|
var allKeys = tagService.keyEnumerator;
|
||||||
|
var tagNum = 0;
|
||||||
|
while (allTags.hasMore())
|
||||||
|
{
|
||||||
|
var tag = allTags.getNext();
|
||||||
|
var key = allKeys.getNext();
|
||||||
|
var newMenuItem = document.createElement('menuitem');
|
||||||
|
newMenuItem.setAttribute('label', tag);
|
||||||
|
newMenuItem.setAttribute('value', key);
|
||||||
|
popupMenu.appendChild(newMenuItem);
|
||||||
|
if (tagNum == 0)
|
||||||
|
{
|
||||||
|
children[5].selectedItem = newMenuItem;
|
||||||
|
children[5].value = key;
|
||||||
|
tagNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
<method name="fillStringsForChildren">
|
<method name="fillStringsForChildren">
|
||||||
<parameter name="parentNode"/>
|
<parameter name="parentNode"/>
|
||||||
<parameter name="bundle"/>
|
<parameter name="bundle"/>
|
||||||
|
@ -1565,18 +1587,14 @@
|
||||||
// initialize the address book picker
|
// initialize the address book picker
|
||||||
this.initialize(document.getAnonymousNodes(this)[4], bundle);
|
this.initialize(document.getAnonymousNodes(this)[4], bundle);
|
||||||
|
|
||||||
// initialize the label picker....
|
|
||||||
var labelStrings = GetLabelStrings();
|
|
||||||
var children = document.getAnonymousNodes(this)[5].firstChild.childNodes;
|
|
||||||
// set the label string on each label element...
|
|
||||||
for (var index = 0; index < 6; index++)
|
|
||||||
children[index].setAttribute('label', labelStrings[index]);
|
|
||||||
|
|
||||||
// initialize the junk status picker
|
// initialize the junk status picker
|
||||||
this.initialize(document.getAnonymousNodes(this)[6], bundle);
|
this.initialize(document.getAnonymousNodes(this)[6], bundle);
|
||||||
|
|
||||||
// initialize the has attachment status picker
|
// initialize the has attachment status picker
|
||||||
this.initialize(document.getAnonymousNodes(this)[7], bundle);
|
this.initialize(document.getAnonymousNodes(this)[7], bundle);
|
||||||
|
|
||||||
|
// initialize the tag list
|
||||||
|
fillInTags();
|
||||||
]]>
|
]]>
|
||||||
</constructor>
|
</constructor>
|
||||||
</implementation>
|
</implementation>
|
||||||
|
|
|
@ -526,61 +526,6 @@ function SetMenuItemLabel(menuItemId, customLabel)
|
||||||
menuItem.setAttribute('label', customLabel);
|
menuItem.setAttribute('label', customLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function InitMessageLabel(menuType)
|
|
||||||
{
|
|
||||||
/* this code gets the label strings and changes the menu labels */
|
|
||||||
var color;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var isChecked = true;
|
|
||||||
var checkedLabel = gDBView.hdrForFirstSelectedMessage.label;
|
|
||||||
}
|
|
||||||
catch(ex)
|
|
||||||
{
|
|
||||||
isChecked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var label = 0; label <= 5; label++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var prefString = gPrefBranch.getComplexValue("mailnews.labels.description." + label,
|
|
||||||
Components.interfaces.nsIPrefLocalizedString);
|
|
||||||
var formattedPrefString = gMessengerBundle.getFormattedString("labelMenuItemFormat" + label,
|
|
||||||
[prefString], 1);
|
|
||||||
var menuItemId = menuType + "-labelMenuItem" + label;
|
|
||||||
var menuItem = document.getElementById(menuItemId);
|
|
||||||
|
|
||||||
SetMenuItemLabel(menuItemId, formattedPrefString);
|
|
||||||
if (isChecked && label == checkedLabel)
|
|
||||||
menuItem.setAttribute("checked", "true");
|
|
||||||
else
|
|
||||||
menuItem.setAttribute("checked", "false");
|
|
||||||
|
|
||||||
// commented out for now until UE decides on how to show the Labels menu items.
|
|
||||||
// This code will color either the text or background for the Labels menu items.
|
|
||||||
/*****
|
|
||||||
if (label != 0)
|
|
||||||
{
|
|
||||||
color = gPrefBranch.getCharPref("mailnews.labels.color." + label);
|
|
||||||
// this colors the text of the menuitem only.
|
|
||||||
//menuItem.setAttribute("style", ("color: " + color));
|
|
||||||
|
|
||||||
// this colors the background of the menuitem and
|
|
||||||
// when selected, text becomes white.
|
|
||||||
//menuItem.setAttribute("style", ("color: #FFFFFF"));
|
|
||||||
//menuItem.setAttribute("style", ("background-color: " + color));
|
|
||||||
}
|
|
||||||
****/
|
|
||||||
}
|
|
||||||
catch(ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.commandDispatcher.updateCommands('create-menu-label');
|
|
||||||
}
|
|
||||||
|
|
||||||
function InitMessageMark()
|
function InitMessageMark()
|
||||||
{
|
{
|
||||||
var areMessagesRead = SelectedMessagesAreRead();
|
var areMessagesRead = SelectedMessagesAreRead();
|
||||||
|
|
|
@ -108,8 +108,8 @@ searchterm {
|
||||||
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-folder");
|
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
.ruleactiontarget[type="labelmessageas"] {
|
.ruleactiontarget[type="addtagtomessage"] {
|
||||||
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-label");
|
-moz-binding: url("chrome://messenger/content/searchWidgets.xml#ruleactiontarget-tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
.ruleactiontarget[type="setpriorityto"] {
|
.ruleactiontarget[type="setpriorityto"] {
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
*
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the new tag dialog
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* David Bienvenu.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Bienvenu <bienvenu@nventure.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
var dialog;
|
||||||
|
|
||||||
|
function onLoad()
|
||||||
|
{
|
||||||
|
var arguments = window.arguments[0];
|
||||||
|
|
||||||
|
dialog = {};
|
||||||
|
|
||||||
|
dialog.OKButton = document.documentElement.getButton("accept");
|
||||||
|
|
||||||
|
dialog.nameField = document.getElementById("name");
|
||||||
|
dialog.nameField.focus();
|
||||||
|
|
||||||
|
// call this when OK is pressed
|
||||||
|
dialog.okCallback = arguments.okCallback;
|
||||||
|
|
||||||
|
moveToAlertPosition();
|
||||||
|
doEnabling();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onOK()
|
||||||
|
{
|
||||||
|
var name = dialog.nameField.value;
|
||||||
|
|
||||||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
|
||||||
|
// do name validity check? Has to be non-empty, and not existing already
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var key = tagService.getKeyForTag(name);
|
||||||
|
// above will throw an error if tag doesn't exist. So if it doesn't throw an error,
|
||||||
|
// the tag exists, so alert the user and return false.
|
||||||
|
}
|
||||||
|
catch (ex) {return dialog.okCallback(name, "")}
|
||||||
|
|
||||||
|
var messengerBundle = document.getElementById("bundle_messenger");
|
||||||
|
var alertText = messengerBundle.getString("tagExists");
|
||||||
|
window.alert(alertText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doEnabling()
|
||||||
|
{
|
||||||
|
if (dialog.nameField.value) {
|
||||||
|
if (dialog.OKButton.disabled)
|
||||||
|
dialog.OKButton.disabled = false;
|
||||||
|
} else {
|
||||||
|
if (!dialog.OKButton.disabled)
|
||||||
|
dialog.OKButton.disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||||
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
-
|
||||||
|
- The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
- the License. You may obtain a copy of the License at
|
||||||
|
- http://www.mozilla.org/MPL/
|
||||||
|
-
|
||||||
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
- for the specific language governing rights and limitations under the
|
||||||
|
- License.
|
||||||
|
-
|
||||||
|
- The Original Code is Mozilla Mail Tag Support
|
||||||
|
-
|
||||||
|
- The Initial Developer of the Original Code is
|
||||||
|
- The Mozilla Corporation.
|
||||||
|
- Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
- the Initial Developer. All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
- of those above. If you wish to allow use of your version of this file only
|
||||||
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
- use your version of this file under the terms of the MPL, indicate your
|
||||||
|
- decision by deleting the provisions above and replace them with the notice
|
||||||
|
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
- the provisions above, a recipient may use your version of this file under
|
||||||
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
-
|
||||||
|
- ***** END LICENSE BLOCK ***** -->
|
||||||
|
|
||||||
|
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
|
||||||
|
|
||||||
|
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/newTagDialog.dtd">
|
||||||
|
|
||||||
|
<dialog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
title="&newTagDialog.title;"
|
||||||
|
onload="onLoad();"
|
||||||
|
ondialogaccept="return onOK();">
|
||||||
|
|
||||||
|
<stringbundleset id="stringbundleset">
|
||||||
|
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
|
||||||
|
</stringbundleset>
|
||||||
|
|
||||||
|
<script type="application/x-javascript" src="chrome://messenger/content/newTagDialog.js"/>
|
||||||
|
|
||||||
|
<label value="&name.label;" accesskey="&name.accesskey;" control="name"/>
|
||||||
|
<textbox id="name" oninput="doEnabling();"/>
|
||||||
|
|
||||||
|
<separator/>
|
||||||
|
|
||||||
|
</dialog>
|
|
@ -236,6 +236,9 @@ junk=Junk
|
||||||
# for the has attachment picker in search and mail views
|
# for the has attachment picker in search and mail views
|
||||||
hasAttachments=Has Attachments
|
hasAttachments=Has Attachments
|
||||||
|
|
||||||
|
# for the Tag picker in search and mail views.
|
||||||
|
tag=Tag
|
||||||
|
|
||||||
# mailnews.js
|
# mailnews.js
|
||||||
mailnews.send_default_charset=ISO-8859-1
|
mailnews.send_default_charset=ISO-8859-1
|
||||||
mailnews.view_default_charset=ISO-8859-1
|
mailnews.view_default_charset=ISO-8859-1
|
||||||
|
|
|
@ -46,7 +46,7 @@ interface nsIMsgSearchScopeTerm;
|
||||||
|
|
||||||
native nsCStringRef(nsCString&);
|
native nsCStringRef(nsCString&);
|
||||||
|
|
||||||
[scriptable, uuid(cc7795ce-1dd1-11b2-9ad2-dfa3c0b6ee09)]
|
[scriptable, uuid(cde583fe-9add-4adb-9e1a-9cfe050d8a26)]
|
||||||
interface nsIMsgSearchTerm : nsISupports {
|
interface nsIMsgSearchTerm : nsISupports {
|
||||||
attribute nsMsgSearchAttribValue attrib;
|
attribute nsMsgSearchAttribValue attrib;
|
||||||
attribute nsMsgSearchOpValue op;
|
attribute nsMsgSearchOpValue op;
|
||||||
|
@ -93,6 +93,7 @@ interface nsIMsgSearchTerm : nsISupports {
|
||||||
readonly attribute boolean matchAllBeforeDeciding;
|
readonly attribute boolean matchAllBeforeDeciding;
|
||||||
|
|
||||||
readonly attribute ACString termAsString;
|
readonly attribute ACString termAsString;
|
||||||
|
boolean matchKeyword(in string keyword); // used for tag searches
|
||||||
attribute boolean matchAll;
|
attribute boolean matchAll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ typedef long nsMsgFilterIndex;
|
||||||
|
|
||||||
typedef long nsMsgRuleActionType;
|
typedef long nsMsgRuleActionType;
|
||||||
|
|
||||||
[scriptable, uuid(3099cee1-eb76-4cd3-a40e-cfc8d2ef4437)]
|
[scriptable, uuid(59af7696-1e28-4642-a400-fa327ae0b8d8)]
|
||||||
interface nsMsgFilterAction {
|
interface nsMsgFilterAction {
|
||||||
|
|
||||||
/* these longs are all actually of type nsMsgFilterActionType */
|
/* these longs are all actually of type nsMsgFilterActionType */
|
||||||
|
@ -80,5 +80,6 @@ interface nsMsgFilterAction {
|
||||||
const long JunkScore=14;
|
const long JunkScore=14;
|
||||||
const long FetchBodyFromPop3Server=15;
|
const long FetchBodyFromPop3Server=15;
|
||||||
const long CopyToFolder=16;
|
const long CopyToFolder=16;
|
||||||
|
const long AddTag=17;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -80,13 +80,13 @@ interface nsMsgSearchAttrib {
|
||||||
const nsMsgSearchAttribValue CC = 7;
|
const nsMsgSearchAttribValue CC = 7;
|
||||||
const nsMsgSearchAttribValue ToOrCC = 8;
|
const nsMsgSearchAttribValue ToOrCC = 8;
|
||||||
|
|
||||||
const nsMsgSearchAttribValue Location = 9; /* result list only */
|
const nsMsgSearchAttribValue Location = 9; /* result list only */
|
||||||
const nsMsgSearchAttribValue MessageKey = 10; /* message result elems */
|
const nsMsgSearchAttribValue MessageKey = 10; /* message result elems */
|
||||||
const nsMsgSearchAttribValue AgeInDays = 11;
|
const nsMsgSearchAttribValue AgeInDays = 11;
|
||||||
const nsMsgSearchAttribValue FolderInfo = 12; /* for "view thread context" from result */
|
const nsMsgSearchAttribValue FolderInfo = 12; /* for "view thread context" from result */
|
||||||
const nsMsgSearchAttribValue Size = 13;
|
const nsMsgSearchAttribValue Size = 13;
|
||||||
const nsMsgSearchAttribValue AnyText = 14;
|
const nsMsgSearchAttribValue AnyText = 14;
|
||||||
const nsMsgSearchAttribValue Keywords = 15;
|
const nsMsgSearchAttribValue Keywords = 15; // keywords are the internal representation of tags.
|
||||||
|
|
||||||
const nsMsgSearchAttribValue Name = 16;
|
const nsMsgSearchAttribValue Name = 16;
|
||||||
const nsMsgSearchAttribValue DisplayName = 17;
|
const nsMsgSearchAttribValue DisplayName = 17;
|
||||||
|
@ -106,12 +106,12 @@ interface nsMsgSearchAttrib {
|
||||||
const nsMsgSearchAttribValue Organization = 31;
|
const nsMsgSearchAttribValue Organization = 31;
|
||||||
const nsMsgSearchAttribValue Department = 32;
|
const nsMsgSearchAttribValue Department = 32;
|
||||||
|
|
||||||
// 33 - 45, reserved for ab / LDAP;
|
// 33 - 45, reserved for ab / LDAP;
|
||||||
const nsMsgSearchAttribValue HasAttachmentStatus = 46;
|
const nsMsgSearchAttribValue HasAttachmentStatus = 46;
|
||||||
const nsMsgSearchAttribValue JunkStatus = 47;
|
const nsMsgSearchAttribValue JunkStatus = 47;
|
||||||
const nsMsgSearchAttribValue Label = 48; /* mail only...can search by label */
|
const nsMsgSearchAttribValue Label = 48; /* mail only...can search by label */
|
||||||
//49 is for showing customize... in ui headers start from 50 onwards up until 99.
|
//49 is for showing customize... in ui headers start from 50 onwards up until 99.
|
||||||
const nsMsgSearchAttribValue OtherHeader = 49; /* for mail and news. MUST ALWAYS BE LAST attribute since we can have an arbitrary # of these... */
|
const nsMsgSearchAttribValue OtherHeader = 49; /* for mail and news. MUST ALWAYS BE LAST attribute since we can have an arbitrary # of these... */
|
||||||
const nsMsgSearchAttribValue kNumMsgSearchAttributes = 100; /* must be last attribute */
|
const nsMsgSearchAttribValue kNumMsgSearchAttributes = 100; /* must be last attribute */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,9 +57,9 @@ var gFilterActionList;
|
||||||
|
|
||||||
var gFilterActionStrings = ["none", "movemessage", "setpriorityto", "deletemessage",
|
var gFilterActionStrings = ["none", "movemessage", "setpriorityto", "deletemessage",
|
||||||
"markasread", "ignorethread", "watchthread", "markasflagged",
|
"markasread", "ignorethread", "watchthread", "markasflagged",
|
||||||
"labelmessageas", "replytomessage", "forwardmessage", "stopexecution",
|
"label", "replytomessage", "forwardmessage", "stopexecution",
|
||||||
"deletefrompopserver", "leaveonpopserver", "setjunkscore",
|
"deletefrompopserver", "leaveonpopserver", "setjunkscore",
|
||||||
"fetchfrompopserver", "copymessage"];
|
"fetchfrompopserver", "copymessage", "addtagtomessage"];
|
||||||
|
|
||||||
var nsMsgFilterAction = Components.interfaces.nsMsgFilterAction;
|
var nsMsgFilterAction = Components.interfaces.nsMsgFilterAction;
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ function filterEditorOnLoad()
|
||||||
|
|
||||||
gPrefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch(null);
|
gPrefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch(null);
|
||||||
gFilterBundle = document.getElementById("bundle_filter");
|
gFilterBundle = document.getElementById("bundle_filter");
|
||||||
InitMessageLabel();
|
InitMessageMark();
|
||||||
if ("arguments" in window && window.arguments[0])
|
if ("arguments" in window && window.arguments[0])
|
||||||
{
|
{
|
||||||
var args = window.arguments[0];
|
var args = window.arguments[0];
|
||||||
|
|
|
@ -70,8 +70,8 @@
|
||||||
<xul:menuseparator/>
|
<xul:menuseparator/>
|
||||||
<xul:menuitem label="&markMessageRead.label;" value="markasread"/>
|
<xul:menuitem label="&markMessageRead.label;" value="markasread"/>
|
||||||
<xul:menuitem label="&markMessageFlagged.label;" value="markasflagged"/>
|
<xul:menuitem label="&markMessageFlagged.label;" value="markasflagged"/>
|
||||||
<xul:menuitem label="&labelMessage.label;" value="labelmessageas"/>
|
|
||||||
<xul:menuitem label="&setPriority.label;" value="setpriorityto"/>
|
<xul:menuitem label="&setPriority.label;" value="setpriorityto"/>
|
||||||
|
<xul:menuitem label="&addTag.label;" value="addtagtomessage"/>
|
||||||
<xul:menuitem label="&setJunkScore.label;" value="setjunkscore" enablefornews="false"/>
|
<xul:menuitem label="&setJunkScore.label;" value="setjunkscore" enablefornews="false"/>
|
||||||
<xul:menuseparator enableforpop3="true"/>
|
<xul:menuseparator enableforpop3="true"/>
|
||||||
<xul:menuitem label="&deleteMessage.label;" value="deletemessage"/>
|
<xul:menuitem label="&deleteMessage.label;" value="deletemessage"/>
|
||||||
|
@ -255,6 +255,9 @@
|
||||||
case "setjunkscore":
|
case "setjunkscore":
|
||||||
document.getAnonymousNodes(actionTarget)[0].value = aFilterAction.junkScore;
|
document.getAnonymousNodes(actionTarget)[0].value = aFilterAction.junkScore;
|
||||||
break;
|
break;
|
||||||
|
case "addtagtomessage":
|
||||||
|
document.getAnonymousNodes(actionTarget)[0].value = aFilterAction.strValue;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -328,6 +331,7 @@
|
||||||
case "setjunkscore":
|
case "setjunkscore":
|
||||||
filterAction.junkScore = document.getAnonymousNodes(actionTarget)[0].value;
|
filterAction.junkScore = document.getAnonymousNodes(actionTarget)[0].value;
|
||||||
break;
|
break;
|
||||||
|
case "addtagtomessage":
|
||||||
case "replytomessage":
|
case "replytomessage":
|
||||||
case "forwardmessage":
|
case "forwardmessage":
|
||||||
filterAction.strValue = document.getAnonymousNodes(actionTarget)[0].value;
|
filterAction.strValue = document.getAnonymousNodes(actionTarget)[0].value;
|
||||||
|
@ -385,16 +389,10 @@
|
||||||
</implementation>
|
</implementation>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
<binding id="ruleactiontarget-label" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base">
|
<binding id="ruleactiontarget-tag" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base">
|
||||||
<content>
|
<content>
|
||||||
<xul:menulist class="ruleactionitem">
|
<xul:menulist class="ruleactionitem">
|
||||||
<xul:menupopup>
|
<xul:menupopup>
|
||||||
<xul:menuitem value="0"/>
|
|
||||||
<xul:menuitem value="1"/>
|
|
||||||
<xul:menuitem value="2"/>
|
|
||||||
<xul:menuitem value="3"/>
|
|
||||||
<xul:menuitem value="4"/>
|
|
||||||
<xul:menuitem value="5"/>
|
|
||||||
</xul:menupopup>
|
</xul:menupopup>
|
||||||
</xul:menulist>
|
</xul:menulist>
|
||||||
</content>
|
</content>
|
||||||
|
@ -402,19 +400,21 @@
|
||||||
<implementation>
|
<implementation>
|
||||||
<constructor>
|
<constructor>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
var menuItems = document.getAnonymousNodes(this)[0].menupopup.childNodes;
|
var menuPopup = document.getAnonymousNodes(this)[0].menupopup;
|
||||||
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch(null);
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
|
||||||
|
var allTags = tagService.tagEnumerator;
|
||||||
for (var index = 0; index < menuItems.length; index++)
|
var allKeys = tagService.keyEnumerator;
|
||||||
{
|
while (allTags.hasMore())
|
||||||
var menuEl = menuItems[index];
|
{
|
||||||
var prefString = prefBranch.getComplexValue("mailnews.labels.description." + menuEl.value,
|
var tag = allTags.getNext();
|
||||||
Components.interfaces.nsIPrefLocalizedString);
|
var key = allKeys.getNext();
|
||||||
menuEl.setAttribute("label", prefString);
|
var newMenuItem = document.createElement('menuitem');
|
||||||
}
|
newMenuItem.setAttribute('label', tag);
|
||||||
|
newMenuItem.setAttribute('value', key);
|
||||||
// propagating a pre-existing hack to make the label get displayed correctly in the menulist
|
menuPopup.appendChild(newMenuItem);
|
||||||
// now that we've changed the labels for each menu list. We need to use the current selectedIndex
|
}
|
||||||
|
// propagating a pre-existing hack to make the tag get displayed correctly in the menulist
|
||||||
|
// now that we've changed the tags for each menu list. We need to use the current selectedIndex
|
||||||
// (if its defined) to handle the case where we were initialized with a filter action already.
|
// (if its defined) to handle the case where we were initialized with a filter action already.
|
||||||
var currentItem = document.getAnonymousNodes(this)[0].selectedItem;
|
var currentItem = document.getAnonymousNodes(this)[0].selectedItem;
|
||||||
document.getAnonymousNodes(this)[0].selectedItem = null;
|
document.getAnonymousNodes(this)[0].selectedItem = null;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
12=Folder Info
|
12=Folder Info
|
||||||
13=Size (KB)
|
13=Size (KB)
|
||||||
14=AnyText
|
14=AnyText
|
||||||
15=Keywords
|
15=Tags
|
||||||
# for AB and LDAP
|
# for AB and LDAP
|
||||||
16=Any Name
|
16=Any Name
|
||||||
17=Display Name
|
17=Display Name
|
||||||
|
@ -50,5 +50,5 @@
|
||||||
46=Attachment Status
|
46=Attachment Status
|
||||||
47=Junk Status
|
47=Junk Status
|
||||||
48=Label
|
48=Label
|
||||||
|
49=Customize
|
||||||
# don't use above 49
|
# don't use above 49
|
||||||
49=Customize...
|
|
||||||
|
|
|
@ -730,6 +730,7 @@ nsresult nsMsgFilter::SaveRule(nsIOFileStream *aStream)
|
||||||
err = filterList->WriteIntAttr(nsIMsgFilterList::attribActionValue, junkScore, aStream);
|
err = filterList->WriteIntAttr(nsIMsgFilterList::attribActionValue, junkScore, aStream);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nsMsgFilterAction::AddTag:
|
||||||
case nsMsgFilterAction::Reply:
|
case nsMsgFilterAction::Reply:
|
||||||
case nsMsgFilterAction::Forward:
|
case nsMsgFilterAction::Forward:
|
||||||
{
|
{
|
||||||
|
@ -818,6 +819,7 @@ static struct RuleActionsTableEntry ruleActionsTable[] =
|
||||||
{ nsMsgFilterAction::LeaveOnPop3Server, nsMsgFilterType::Inbox, 0, "Leave on Pop3 server"},
|
{ nsMsgFilterAction::LeaveOnPop3Server, nsMsgFilterType::Inbox, 0, "Leave on Pop3 server"},
|
||||||
{ nsMsgFilterAction::JunkScore, nsMsgFilterType::All, 0, "JunkScore"},
|
{ nsMsgFilterAction::JunkScore, nsMsgFilterType::All, 0, "JunkScore"},
|
||||||
{ nsMsgFilterAction::FetchBodyFromPop3Server, nsMsgFilterType::Inbox, 0, "Fetch body from Pop3Server"},
|
{ nsMsgFilterAction::FetchBodyFromPop3Server, nsMsgFilterType::Inbox, 0, "Fetch body from Pop3Server"},
|
||||||
|
{ nsMsgFilterAction::AddTag, nsMsgFilterType::All, 0, "AddTag"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *nsMsgFilter::GetActionStr(nsMsgRuleActionType action)
|
const char *nsMsgFilter::GetActionStr(nsMsgRuleActionType action)
|
||||||
|
|
|
@ -662,10 +662,16 @@ nsresult nsMsgFilterList::LoadTextFilters(nsIOFileStream *aStream)
|
||||||
}
|
}
|
||||||
else if (type == nsMsgFilterAction::Label)
|
else if (type == nsMsgFilterAction::Label)
|
||||||
{
|
{
|
||||||
|
// upgrade label to corresponding tag/keyword
|
||||||
PRInt32 res;
|
PRInt32 res;
|
||||||
PRInt32 labelInt = value.ToInteger(&res, 10);
|
PRInt32 labelInt = value.ToInteger(&res, 10);
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
currentFilterAction->SetLabel((nsMsgLabelValue) labelInt);
|
{
|
||||||
|
nsCAutoString keyword("$label");
|
||||||
|
keyword.Append('0' + labelInt);
|
||||||
|
currentFilterAction->SetType(nsMsgFilterAction::AddTag);
|
||||||
|
currentFilterAction->SetStrValue(keyword.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (type == nsMsgFilterAction::JunkScore)
|
else if (type == nsMsgFilterAction::JunkScore)
|
||||||
{
|
{
|
||||||
|
@ -674,7 +680,8 @@ nsresult nsMsgFilterList::LoadTextFilters(nsIOFileStream *aStream)
|
||||||
if (!res)
|
if (!res)
|
||||||
currentFilterAction->SetJunkScore(junkScore);
|
currentFilterAction->SetJunkScore(junkScore);
|
||||||
}
|
}
|
||||||
else if (type == nsMsgFilterAction::Forward || type == nsMsgFilterAction::Reply)
|
else if (type == nsMsgFilterAction::Forward || type == nsMsgFilterAction::Reply
|
||||||
|
|| type == nsMsgFilterAction::AddTag)
|
||||||
{
|
{
|
||||||
currentFilterAction->SetStrValue(value.get());
|
currentFilterAction->SetStrValue(value.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -647,6 +647,13 @@ nsresult nsMsgFilterAfterTheFact::ApplyFilter()
|
||||||
m_curFolder->SetLabelForMessages(m_searchHitHdrs, filterLabel);
|
m_curFolder->SetLabelForMessages(m_searchHitHdrs, filterLabel);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nsMsgFilterAction::AddTag:
|
||||||
|
{
|
||||||
|
nsXPIDLCString keyword;
|
||||||
|
filterAction->GetStrValue(getter_Copies(keyword));
|
||||||
|
m_curFolder->AddKeywordToMessages(m_searchHitHdrs, keyword.get());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case nsMsgFilterAction::JunkScore:
|
case nsMsgFilterAction::JunkScore:
|
||||||
{
|
{
|
||||||
nsCAutoString junkScoreStr;
|
nsCAutoString junkScoreStr;
|
||||||
|
|
|
@ -197,11 +197,6 @@ nsMsgSearchValidityManager::InitOfflineMailTable()
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
|
||||||
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
|
||||||
|
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Label, nsMsgSearchOp::Is, 1);
|
|
||||||
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Label, nsMsgSearchOp::Is, 1);
|
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Label, nsMsgSearchOp::Isnt, 1);
|
|
||||||
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Label, nsMsgSearchOp::Isnt, 1);
|
|
||||||
|
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::To, nsMsgSearchOp::Contains, 1);
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::To, nsMsgSearchOp::Contains, 1);
|
||||||
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::To, nsMsgSearchOp::Contains, 1);
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::To, nsMsgSearchOp::Contains, 1);
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::To, nsMsgSearchOp::DoesntContain, 1);
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::To, nsMsgSearchOp::DoesntContain, 1);
|
||||||
|
@ -315,6 +310,14 @@ nsMsgSearchValidityManager::InitOfflineMailTable()
|
||||||
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
|
||||||
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
|
||||||
|
|
||||||
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
|
||||||
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
|
||||||
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
|
||||||
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
|
||||||
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
|
||||||
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
|
||||||
|
m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
|
||||||
|
m_offlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +385,15 @@ nsMsgSearchValidityManager::InitOnlineMailTable()
|
||||||
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
|
||||||
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
|
||||||
|
|
||||||
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
|
||||||
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
|
||||||
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
|
||||||
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
|
||||||
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
|
||||||
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
|
||||||
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
|
||||||
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
|
||||||
|
|
||||||
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
|
||||||
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
|
m_onlineMailTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
|
||||||
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
|
m_onlineMailTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
|
||||||
|
|
|
@ -552,6 +552,13 @@ nsresult nsMsgSearchOfflineMail::ProcessSearchTerm(nsIMsgDBHdr *msgToMatch,
|
||||||
err = aTerm->MatchLabel(label, &result);
|
err = aTerm->MatchLabel(label, &result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case nsMsgSearchAttrib::Keywords:
|
||||||
|
{
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
msgToMatch->GetStringProperty("keywords", getter_Copies(keywords));
|
||||||
|
err = aTerm->MatchKeyword(keywords.get(), &result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case nsMsgSearchAttrib::JunkStatus:
|
case nsMsgSearchAttrib::JunkStatus:
|
||||||
{
|
{
|
||||||
nsXPIDLCString junkScoreStr;
|
nsXPIDLCString junkScoreStr;
|
||||||
|
|
|
@ -500,7 +500,7 @@ nsresult nsMsgSearchAdapter::EncodeImapTerm (nsIMsgSearchTerm *term, PRBool real
|
||||||
whichMnemonic = m_kImapAnyText;
|
whichMnemonic = m_kImapAnyText;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchAttrib::Keywords:
|
case nsMsgSearchAttrib::Keywords:
|
||||||
whichMnemonic = m_kNntpKeywords;
|
whichMnemonic = m_kImapKeyword;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchAttrib::MsgStatus:
|
case nsMsgSearchAttrib::MsgStatus:
|
||||||
useNot = PR_FALSE; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
|
useNot = PR_FALSE; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
|
||||||
|
|
|
@ -97,6 +97,7 @@ nsMsgSearchAttribEntry SearchAttribEntryTable[] =
|
||||||
{nsMsgSearchAttrib::ToOrCC, "to or cc"},
|
{nsMsgSearchAttrib::ToOrCC, "to or cc"},
|
||||||
{nsMsgSearchAttrib::AgeInDays, "age in days"},
|
{nsMsgSearchAttrib::AgeInDays, "age in days"},
|
||||||
{nsMsgSearchAttrib::Label, "label"},
|
{nsMsgSearchAttrib::Label, "label"},
|
||||||
|
{nsMsgSearchAttrib::Keywords, "tag"},
|
||||||
{nsMsgSearchAttrib::Size, "size"},
|
{nsMsgSearchAttrib::Size, "size"},
|
||||||
// this used to be nsMsgSearchAttrib::SenderInAddressBook
|
// this used to be nsMsgSearchAttrib::SenderInAddressBook
|
||||||
// we used to have two Sender menuitems
|
// we used to have two Sender menuitems
|
||||||
|
@ -663,8 +664,16 @@ nsresult nsMsgSearchTerm::DeStreamNew (char *inStream, PRInt16 /*length*/)
|
||||||
if (commaSep)
|
if (commaSep)
|
||||||
rv = ParseOperator(commaSep + 1, &m_operator);
|
rv = ParseOperator(commaSep + 1, &m_operator);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
// convert label filters and saved searches to keyword equivalents
|
||||||
if (secondCommaSep)
|
if (secondCommaSep)
|
||||||
ParseValue(secondCommaSep + 1);
|
ParseValue(secondCommaSep + 1);
|
||||||
|
if (m_attribute == nsMsgSearchAttrib::Label)
|
||||||
|
{
|
||||||
|
nsCAutoString keyword("$label");
|
||||||
|
m_value.attribute = m_attribute = nsMsgSearchAttrib::Keywords;
|
||||||
|
keyword.Append('0' + m_value.u.label);
|
||||||
|
m_value.string = PL_strdup(keyword.get());
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,38 +1221,38 @@ nsresult nsMsgSearchTerm::MatchAge (PRTime msgDate, PRBool *pResult)
|
||||||
|
|
||||||
nsresult nsMsgSearchTerm::MatchSize (PRUint32 sizeToMatch, PRBool *pResult)
|
nsresult nsMsgSearchTerm::MatchSize (PRUint32 sizeToMatch, PRBool *pResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(pResult);
|
NS_ENSURE_ARG_POINTER(pResult);
|
||||||
|
|
||||||
PRBool result = PR_FALSE;
|
PRBool result = PR_FALSE;
|
||||||
// We reduce the sizeToMatch rather than supplied size
|
// We reduce the sizeToMatch rather than supplied size
|
||||||
// as then we can do an exact match on the displayed value
|
// as then we can do an exact match on the displayed value
|
||||||
// which will be less confusing to the user.
|
// which will be less confusing to the user.
|
||||||
PRUint32 sizeToMatchKB = sizeToMatch;
|
PRUint32 sizeToMatchKB = sizeToMatch;
|
||||||
|
|
||||||
if (sizeToMatchKB < 1024)
|
if (sizeToMatchKB < 1024)
|
||||||
sizeToMatchKB = 1024;
|
sizeToMatchKB = 1024;
|
||||||
|
|
||||||
sizeToMatchKB /= 1024;
|
sizeToMatchKB /= 1024;
|
||||||
|
|
||||||
switch (m_operator)
|
switch (m_operator)
|
||||||
{
|
{
|
||||||
case nsMsgSearchOp::IsGreaterThan:
|
case nsMsgSearchOp::IsGreaterThan:
|
||||||
if (sizeToMatchKB > m_value.u.size)
|
if (sizeToMatchKB > m_value.u.size)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::IsLessThan:
|
case nsMsgSearchOp::IsLessThan:
|
||||||
if (sizeToMatchKB < m_value.u.size)
|
if (sizeToMatchKB < m_value.u.size)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::Is:
|
case nsMsgSearchOp::Is:
|
||||||
if (sizeToMatchKB == m_value.u.size)
|
if (sizeToMatchKB == m_value.u.size)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*pResult = result;
|
*pResult = result;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMsgSearchTerm::MatchJunkStatus(const char *aJunkScore, PRBool *pResult)
|
nsresult nsMsgSearchTerm::MatchJunkStatus(const char *aJunkScore, PRBool *pResult)
|
||||||
|
@ -1269,22 +1278,22 @@ nsresult nsMsgSearchTerm::MatchJunkStatus(const char *aJunkScore, PRBool *pResul
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool matches = (junkStatus == m_value.u.junkStatus);
|
PRBool matches = (junkStatus == m_value.u.junkStatus);
|
||||||
|
|
||||||
switch (m_operator)
|
switch (m_operator)
|
||||||
{
|
{
|
||||||
case nsMsgSearchOp::Is:
|
case nsMsgSearchOp::Is:
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::Isnt:
|
case nsMsgSearchOp::Isnt:
|
||||||
matches = !matches;
|
matches = !matches;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
NS_ASSERTION(PR_FALSE, "invalid compare op for junk status");
|
NS_ASSERTION(PR_FALSE, "invalid compare op for junk status");
|
||||||
}
|
}
|
||||||
|
|
||||||
*pResult = matches;
|
*pResult = matches;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMsgSearchTerm::MatchLabel(nsMsgLabelValue aLabelValue, PRBool *pResult)
|
nsresult nsMsgSearchTerm::MatchLabel(nsMsgLabelValue aLabelValue, PRBool *pResult)
|
||||||
|
@ -1309,62 +1318,109 @@ nsresult nsMsgSearchTerm::MatchLabel(nsMsgLabelValue aLabelValue, PRBool *pResul
|
||||||
|
|
||||||
nsresult nsMsgSearchTerm::MatchStatus(PRUint32 statusToMatch, PRBool *pResult)
|
nsresult nsMsgSearchTerm::MatchStatus(PRUint32 statusToMatch, PRBool *pResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(pResult);
|
NS_ENSURE_ARG_POINTER(pResult);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool matches = (statusToMatch & m_value.u.msgStatus);
|
PRBool matches = (statusToMatch & m_value.u.msgStatus);
|
||||||
|
|
||||||
switch (m_operator)
|
switch (m_operator)
|
||||||
{
|
{
|
||||||
case nsMsgSearchOp::Is:
|
case nsMsgSearchOp::Is:
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::Isnt:
|
case nsMsgSearchOp::Isnt:
|
||||||
matches = !matches;
|
matches = !matches;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
NS_ERROR("invalid compare op for msg status");
|
NS_ERROR("invalid compare op for msg status");
|
||||||
}
|
}
|
||||||
|
|
||||||
*pResult = matches;
|
*pResult = matches;
|
||||||
return rv;
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsMsgSearchTerm::MatchKeyword(const char *keyword, PRBool *pResult)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(pResult);
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
nsCAutoString keys;
|
||||||
|
|
||||||
|
PRBool matches = PR_FALSE;
|
||||||
|
|
||||||
|
switch (m_operator)
|
||||||
|
{
|
||||||
|
case nsMsgSearchOp::Is:
|
||||||
|
matches = !strcmp(keyword, m_value.string);
|
||||||
|
break;
|
||||||
|
case nsMsgSearchOp::Isnt:
|
||||||
|
matches = strcmp(keyword, m_value.string);
|
||||||
|
break;
|
||||||
|
case nsMsgSearchOp::DoesntContain:
|
||||||
|
case nsMsgSearchOp::Contains:
|
||||||
|
{
|
||||||
|
const char *keywordLoc = PL_strstr(keyword, m_value.string);
|
||||||
|
const char *startOfKeyword = keyword;
|
||||||
|
PRUint32 keywordLen = strlen(keyword);
|
||||||
|
while (keywordLoc)
|
||||||
|
{
|
||||||
|
// if the keyword is at the beginning of the string, then it's a match if
|
||||||
|
// it is either the whole string, or is followed by a space, it's a match.
|
||||||
|
if (keywordLoc == startOfKeyword || (keywordLoc[-1] == ' '))
|
||||||
|
{
|
||||||
|
matches = keywordLen == strlen(keywordLoc) || (keywordLoc[keywordLen] == ' ');
|
||||||
|
if (matches)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
startOfKeyword = keywordLoc + keywordLen;
|
||||||
|
keywordLoc = PL_strstr(keyword, keywordLoc + keywordLen + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv = NS_ERROR_FAILURE;
|
||||||
|
NS_ERROR("invalid compare op for msg status");
|
||||||
|
}
|
||||||
|
|
||||||
|
*pResult = (m_operator == nsMsgSearchOp::DoesntContain) ? !matches : matches;
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsMsgSearchTerm::MatchPriority (nsMsgPriorityValue priorityToMatch,
|
nsMsgSearchTerm::MatchPriority (nsMsgPriorityValue priorityToMatch,
|
||||||
PRBool *pResult)
|
PRBool *pResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(pResult);
|
NS_ENSURE_ARG_POINTER(pResult);
|
||||||
|
|
||||||
nsresult err = NS_OK;
|
nsresult err = NS_OK;
|
||||||
PRBool result=NS_OK;
|
PRBool result=NS_OK;
|
||||||
|
|
||||||
// Use this ugly little hack to get around the fact that enums don't have
|
// Use this ugly little hack to get around the fact that enums don't have
|
||||||
// integer compare operators
|
// integer compare operators
|
||||||
int p1 = (priorityToMatch == nsMsgPriority::none) ? (int) nsMsgPriority::normal : (int) priorityToMatch;
|
int p1 = (priorityToMatch == nsMsgPriority::none) ? (int) nsMsgPriority::normal : (int) priorityToMatch;
|
||||||
int p2 = (int) m_value.u.priority;
|
int p2 = (int) m_value.u.priority;
|
||||||
|
|
||||||
switch (m_operator)
|
switch (m_operator)
|
||||||
{
|
{
|
||||||
case nsMsgSearchOp::IsHigherThan:
|
case nsMsgSearchOp::IsHigherThan:
|
||||||
if (p1 > p2)
|
if (p1 > p2)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::IsLowerThan:
|
case nsMsgSearchOp::IsLowerThan:
|
||||||
if (p1 < p2)
|
if (p1 < p2)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
case nsMsgSearchOp::Is:
|
case nsMsgSearchOp::Is:
|
||||||
if (p1 == p2)
|
if (p1 == p2)
|
||||||
result = PR_TRUE;
|
result = PR_TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = PR_FALSE;
|
result = PR_FALSE;
|
||||||
err = NS_ERROR_FAILURE;
|
err = NS_ERROR_FAILURE;
|
||||||
NS_ASSERTION(PR_FALSE, "invalid match operator");
|
NS_ASSERTION(PR_FALSE, "invalid match operator");
|
||||||
}
|
}
|
||||||
*pResult = result;
|
*pResult = result;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lazily initialize the rfc822 header parser we're going to use to do
|
// Lazily initialize the rfc822 header parser we're going to use to do
|
||||||
|
|
|
@ -99,6 +99,8 @@ nsMsgSearchValueImpl::GetStr(PRUnichar** aResult)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMsgSearchValueImpl::SetStr(const PRUnichar* aValue)
|
nsMsgSearchValueImpl::SetStr(const PRUnichar* aValue)
|
||||||
{
|
{
|
||||||
|
if (!aValue)
|
||||||
|
return NS_ERROR_NULL_POINTER;
|
||||||
NS_ENSURE_TRUE(IS_STRING_ATTRIBUTE(mValue.attribute), NS_ERROR_ILLEGAL_VALUE);
|
NS_ENSURE_TRUE(IS_STRING_ATTRIBUTE(mValue.attribute), NS_ERROR_ILLEGAL_VALUE);
|
||||||
if (mValue.string)
|
if (mValue.string)
|
||||||
nsCRT::free(mValue.string);
|
nsCRT::free(mValue.string);
|
||||||
|
|
|
@ -127,6 +127,7 @@ CPPSRCS = \
|
||||||
nsSpamSettings.cpp \
|
nsSpamSettings.cpp \
|
||||||
nsCidProtocolHandler.cpp \
|
nsCidProtocolHandler.cpp \
|
||||||
nsMsgContentPolicy.cpp \
|
nsMsgContentPolicy.cpp \
|
||||||
|
nsMsgTagService.cpp\
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
# MacOSX requires the MoreFiles module
|
# MacOSX requires the MoreFiles module
|
||||||
|
|
|
@ -769,14 +769,40 @@ nsresult nsMsgDBView::FetchPriority(nsIMsgDBHdr *aHdr, PRUnichar ** aPriorityStr
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priorityString)
|
*aPriorityString = (priorityString) ? nsCRT::strdup(priorityString) : nsnull;
|
||||||
*aPriorityString = nsCRT::strdup(priorityString);
|
|
||||||
else
|
|
||||||
*aPriorityString = nsnull;
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult nsMsgDBView::FetchTags(nsIMsgDBHdr *aHdr, PRUnichar ** aTagString)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
if (!mTagService)
|
||||||
|
{
|
||||||
|
mTagService = do_GetService(NS_MSGTAGSERVICE_CONTRACTID, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
nsXPIDLString label, tags;
|
||||||
|
FetchLabel(aHdr, getter_Copies(label));
|
||||||
|
aHdr->GetStringProperty("keywords", getter_Copies(keywords));
|
||||||
|
nsCStringArray keywordsArray;
|
||||||
|
keywordsArray.ParseString(keywords.get(), " ");
|
||||||
|
nsAutoString tag;
|
||||||
|
for (PRInt32 i = 0; i < keywordsArray.Count(); i++)
|
||||||
|
{
|
||||||
|
rv = mTagService->GetTagForKey(*(keywordsArray[i]), tag);
|
||||||
|
if (NS_SUCCEEDED(rv) && !tag.IsEmpty() && !tag.Equals(label))
|
||||||
|
{
|
||||||
|
if (!tags.IsEmpty())
|
||||||
|
tags.Append((PRUnichar) ' ');
|
||||||
|
tags.Append(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags.Append(label);
|
||||||
|
*aTagString = ToNewUnicode(tags);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
nsresult nsMsgDBView::FetchLabel(nsIMsgDBHdr *aHdr, PRUnichar ** aLabelString)
|
nsresult nsMsgDBView::FetchLabel(nsIMsgDBHdr *aHdr, PRUnichar ** aLabelString)
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
@ -1601,8 +1627,8 @@ NS_IMETHODIMP nsMsgDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAStr
|
||||||
rv = FetchPriority(msgHdr, getter_Copies(valueText));
|
rv = FetchPriority(msgHdr, getter_Copies(valueText));
|
||||||
aValue.Assign(valueText);
|
aValue.Assign(valueText);
|
||||||
break;
|
break;
|
||||||
case 'l': // label
|
case 'l': // label - labels are now tags...
|
||||||
rv = FetchLabel(msgHdr, getter_Copies(valueText));
|
rv = FetchTags(msgHdr, getter_Copies(valueText));
|
||||||
aValue.Assign(valueText);
|
aValue.Assign(valueText);
|
||||||
break;
|
break;
|
||||||
case 'a': // account
|
case 'a': // account
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "nsIMsgFilterPlugin.h"
|
#include "nsIMsgFilterPlugin.h"
|
||||||
#include "nsIStringBundle.h"
|
#include "nsIStringBundle.h"
|
||||||
|
#include "nsMsgTagService.h"
|
||||||
|
|
||||||
#define MESSENGER_STRING_URL "chrome://messenger/locale/messenger.properties"
|
#define MESSENGER_STRING_URL "chrome://messenger/locale/messenger.properties"
|
||||||
|
|
||||||
|
@ -171,6 +172,7 @@ protected:
|
||||||
nsresult FetchSize(nsIMsgDBHdr * aHdr, PRUnichar ** aSizeString);
|
nsresult FetchSize(nsIMsgDBHdr * aHdr, PRUnichar ** aSizeString);
|
||||||
nsresult FetchPriority(nsIMsgDBHdr *aHdr, PRUnichar ** aPriorityString);
|
nsresult FetchPriority(nsIMsgDBHdr *aHdr, PRUnichar ** aPriorityString);
|
||||||
nsresult FetchLabel(nsIMsgDBHdr *aHdr, PRUnichar ** aLabelString);
|
nsresult FetchLabel(nsIMsgDBHdr *aHdr, PRUnichar ** aLabelString);
|
||||||
|
nsresult FetchTags(nsIMsgDBHdr *aHdr, PRUnichar ** aTagString);
|
||||||
nsresult FetchAccount(nsIMsgDBHdr * aHdr, PRUnichar ** aAccount);
|
nsresult FetchAccount(nsIMsgDBHdr * aHdr, PRUnichar ** aAccount);
|
||||||
nsresult CycleThreadedColumn(nsIDOMElement * aElement);
|
nsresult CycleThreadedColumn(nsIDOMElement * aElement);
|
||||||
|
|
||||||
|
@ -358,6 +360,7 @@ protected:
|
||||||
// I18N date formater service which we'll want to cache locally.
|
// I18N date formater service which we'll want to cache locally.
|
||||||
nsCOMPtr<nsIDateTimeFormat> mDateFormater;
|
nsCOMPtr<nsIDateTimeFormat> mDateFormater;
|
||||||
nsCOMPtr<nsIMsgHeaderParser> mHeaderParser;
|
nsCOMPtr<nsIMsgHeaderParser> mHeaderParser;
|
||||||
|
nsCOMPtr<nsIMsgTagService> mTagService;
|
||||||
// i'm not sure if we are going to permamently need a nsIMessenger instance or if we'll be able
|
// i'm not sure if we are going to permamently need a nsIMessenger instance or if we'll be able
|
||||||
// to phase it out eventually....for now we need it though.
|
// to phase it out eventually....for now we need it though.
|
||||||
nsCOMPtr<nsIMessenger> mMessengerInstance;
|
nsCOMPtr<nsIMessenger> mMessengerInstance;
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsIMsgLocalMailFolder.h"
|
#include "nsIMsgLocalMailFolder.h"
|
||||||
#include "nsIMsgImapMailFolder.h"
|
#include "nsIMsgImapMailFolder.h"
|
||||||
|
#include "nsMailHeaders.h"
|
||||||
#include "nsMsgI18N.h"
|
#include "nsMsgI18N.h"
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "nsMsgLocalFolderHdrs.h"
|
#include "nsMsgLocalFolderHdrs.h"
|
||||||
|
@ -584,6 +584,20 @@ done:
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsFolderCompactState::AdvanceToNextLine(const char *buffer, PRUint32 &bufferOffset, PRUint32 maxBufferOffset)
|
||||||
|
{
|
||||||
|
for (; bufferOffset < maxBufferOffset; bufferOffset++)
|
||||||
|
{
|
||||||
|
if (buffer[bufferOffset] == nsCRT::CR || buffer[bufferOffset] == nsCRT::LF)
|
||||||
|
{
|
||||||
|
bufferOffset++;
|
||||||
|
if (buffer[bufferOffset- 1] == nsCRT::CR && buffer[bufferOffset] == nsCRT::LF)
|
||||||
|
bufferOffset++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
nsIInputStream *inStr,
|
nsIInputStream *inStr,
|
||||||
|
@ -594,9 +608,16 @@ nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRUint32 msgFlags;
|
PRUint32 msgFlags;
|
||||||
|
PRBool checkForKeyword = m_startOfMsg;
|
||||||
|
PRBool addKeywordHdr = PR_FALSE;
|
||||||
|
PRUint32 needToGrowKeywords = 0;
|
||||||
|
PRUint32 statusOffset;
|
||||||
|
nsXPIDLCString msgHdrKeywords;
|
||||||
|
|
||||||
if (m_startOfMsg)
|
if (m_startOfMsg)
|
||||||
{
|
{
|
||||||
m_statusOffset = 0;
|
m_statusOffset = 0;
|
||||||
|
m_addedHeaderSize = 0;
|
||||||
m_messageUri.SetLength(0); // clear the previous message uri
|
m_messageUri.SetLength(0); // clear the previous message uri
|
||||||
if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray[m_curIndex],
|
if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray[m_curIndex],
|
||||||
m_messageUri)))
|
m_messageUri)))
|
||||||
|
@ -606,7 +627,6 @@ nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
if (m_curSrcHdr)
|
if (m_curSrcHdr)
|
||||||
{
|
{
|
||||||
(void) m_curSrcHdr->GetFlags(&msgFlags);
|
(void) m_curSrcHdr->GetFlags(&msgFlags);
|
||||||
PRUint32 statusOffset;
|
|
||||||
(void) m_curSrcHdr->GetStatusOffset(&statusOffset);
|
(void) m_curSrcHdr->GetStatusOffset(&statusOffset);
|
||||||
if (statusOffset == 0)
|
if (statusOffset == 0)
|
||||||
m_needStatusLine = PR_TRUE;
|
m_needStatusLine = PR_TRUE;
|
||||||
|
@ -618,9 +638,21 @@ nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
while (NS_SUCCEEDED(rv) && (PRInt32) count > 0)
|
while (NS_SUCCEEDED(rv) && (PRInt32) count > 0)
|
||||||
{
|
{
|
||||||
maxReadCount = count > 4096 ? 4096 : count;
|
maxReadCount = count > 4096 ? 4096 : count;
|
||||||
|
writeCount = 0;
|
||||||
rv = inStr->Read(m_dataBuffer, maxReadCount, &readCount);
|
rv = inStr->Read(m_dataBuffer, maxReadCount, &readCount);
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
{
|
{
|
||||||
|
if (checkForKeyword)
|
||||||
|
{
|
||||||
|
const char *keywordHdr = PL_strnrstr(m_dataBuffer, HEADER_X_MOZILLA_KEYWORDS, readCount);
|
||||||
|
if (keywordHdr)
|
||||||
|
m_curSrcHdr->GetUint32Property("growKeywords", &needToGrowKeywords);
|
||||||
|
else
|
||||||
|
addKeywordHdr = PR_TRUE;
|
||||||
|
checkForKeyword = PR_FALSE;
|
||||||
|
m_curSrcHdr->GetStringProperty("keywords", getter_Copies(msgHdrKeywords));
|
||||||
|
}
|
||||||
|
PRUint32 blockOffset = 0;
|
||||||
if (m_needStatusLine)
|
if (m_needStatusLine)
|
||||||
{
|
{
|
||||||
m_needStatusLine = PR_FALSE;
|
m_needStatusLine = PR_FALSE;
|
||||||
|
@ -630,26 +662,16 @@ nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
// in OnEndCopy).
|
// in OnEndCopy).
|
||||||
if (!strncmp(m_dataBuffer, "From ", 5))
|
if (!strncmp(m_dataBuffer, "From ", 5))
|
||||||
{
|
{
|
||||||
PRInt32 charIndex;
|
blockOffset = 5;
|
||||||
for (charIndex = 5; charIndex < readCount; charIndex++)
|
// skip from line
|
||||||
{
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount);
|
||||||
if (m_dataBuffer[charIndex] == nsCRT::CR || m_dataBuffer[charIndex] == nsCRT::LF)
|
|
||||||
{
|
|
||||||
charIndex++;
|
|
||||||
if (m_dataBuffer[charIndex- 1] == nsCRT::CR && m_dataBuffer[charIndex] == nsCRT::LF)
|
|
||||||
charIndex++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char statusLine[50];
|
char statusLine[50];
|
||||||
writeCount = m_fileStream->write(m_dataBuffer, charIndex);
|
writeCount = m_fileStream->write(m_dataBuffer, blockOffset);
|
||||||
m_statusOffset = charIndex;
|
m_statusOffset = blockOffset;
|
||||||
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF);
|
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF);
|
||||||
m_statusLineSize = m_fileStream->write(statusLine, strlen(statusLine));
|
m_addedHeaderSize = m_fileStream->write(statusLine, strlen(statusLine));
|
||||||
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000);
|
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000);
|
||||||
m_statusLineSize += m_fileStream->write(statusLine, strlen(statusLine));
|
m_addedHeaderSize += m_fileStream->write(statusLine, strlen(statusLine));
|
||||||
writeCount += m_fileStream->write(m_dataBuffer + charIndex, readCount - charIndex);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -665,10 +687,99 @@ nsFolderCompactState::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
#define EXTRA_KEYWORD_HDR " "MSG_LINEBREAK
|
||||||
|
|
||||||
|
if (addKeywordHdr)
|
||||||
{
|
{
|
||||||
writeCount = m_fileStream->write(m_dataBuffer, readCount);
|
// if blockOffset is set, we added x-mozilla-status headers so
|
||||||
|
// file pointer is already past them.
|
||||||
|
if (!blockOffset)
|
||||||
|
{
|
||||||
|
blockOffset = statusOffset;
|
||||||
|
// skip x-mozilla-status and status2 lines.
|
||||||
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount);
|
||||||
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount);
|
||||||
|
// need to rewrite the headers up to and including the x-mozilla-status2 header
|
||||||
|
writeCount = m_fileStream->write(m_dataBuffer, blockOffset);
|
||||||
|
}
|
||||||
|
// we should write out the existing keywords from the msg hdr, if any.
|
||||||
|
if (msgHdrKeywords.IsEmpty())
|
||||||
|
{ // no keywords, so write blank header
|
||||||
|
m_addedHeaderSize += m_fileStream->write(X_MOZILLA_KEYWORDS, sizeof(X_MOZILLA_KEYWORDS) - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (msgHdrKeywords.Length() < sizeof(X_MOZILLA_KEYWORDS) - sizeof(HEADER_X_MOZILLA_KEYWORDS) + 10 /* allow some slop */)
|
||||||
|
{ // keywords fit in normal blank header, so replace blanks in keyword hdr with keywords
|
||||||
|
nsCAutoString keywordsHdr(X_MOZILLA_KEYWORDS);
|
||||||
|
keywordsHdr.Replace(sizeof(HEADER_X_MOZILLA_KEYWORDS) + 1, msgHdrKeywords.Length(), msgHdrKeywords);
|
||||||
|
m_addedHeaderSize += m_fileStream->write(keywordsHdr.get(), keywordsHdr.Length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // keywords don't fit, so write out keywords on one line and an extra blank line
|
||||||
|
nsCString newKeywordHeader(HEADER_X_MOZILLA_KEYWORDS ": ");
|
||||||
|
newKeywordHeader.Append(msgHdrKeywords);
|
||||||
|
newKeywordHeader.Append(MSG_LINEBREAK EXTRA_KEYWORD_HDR);
|
||||||
|
m_addedHeaderSize += m_fileStream->write(newKeywordHeader.get(), newKeywordHeader.Length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addKeywordHdr = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
else if (needToGrowKeywords)
|
||||||
|
{
|
||||||
|
blockOffset = statusOffset;
|
||||||
|
if (!strncmp(m_dataBuffer + blockOffset, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN))
|
||||||
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount); // skip x-mozilla-status hdr
|
||||||
|
if (!strncmp(m_dataBuffer + blockOffset, X_MOZILLA_STATUS2, X_MOZILLA_STATUS2_LEN))
|
||||||
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount); // skip x-mozilla-status2 hdr
|
||||||
|
PRUint32 preKeywordBlockOffset = blockOffset;
|
||||||
|
if (!strncmp(m_dataBuffer + blockOffset, HEADER_X_MOZILLA_KEYWORDS, sizeof(HEADER_X_MOZILLA_KEYWORDS) - 1))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// skip x-mozilla-keywords hdr and any existing continuation headers
|
||||||
|
AdvanceToNextLine(m_dataBuffer, blockOffset, readCount);
|
||||||
|
}
|
||||||
|
while (m_dataBuffer[blockOffset] == ' ');
|
||||||
|
}
|
||||||
|
PRInt32 oldKeywordSize = blockOffset - preKeywordBlockOffset;
|
||||||
|
|
||||||
|
// rewrite the headers up to and including the x-mozilla-status2 header
|
||||||
|
writeCount = m_fileStream->write(m_dataBuffer, preKeywordBlockOffset);
|
||||||
|
// let's just rewrite all the keywords on several lines and add a blank line,
|
||||||
|
// instead of worrying about which are missing.
|
||||||
|
PRBool done = PR_FALSE;
|
||||||
|
nsCAutoString keywordHdr(HEADER_X_MOZILLA_KEYWORDS ": ");
|
||||||
|
PRInt32 nextBlankOffset = 0;
|
||||||
|
PRInt32 curHdrLineStart = 0;
|
||||||
|
PRInt32 newKeywordSize = 0;
|
||||||
|
while (!done)
|
||||||
|
{
|
||||||
|
nextBlankOffset = msgHdrKeywords.FindChar(' ', nextBlankOffset);
|
||||||
|
if (nextBlankOffset == kNotFound)
|
||||||
|
{
|
||||||
|
nextBlankOffset = msgHdrKeywords.Length();
|
||||||
|
done = PR_TRUE;
|
||||||
|
}
|
||||||
|
if (nextBlankOffset - curHdrLineStart > 90 || done)
|
||||||
|
{
|
||||||
|
keywordHdr.Append(nsDependentCSubstring(msgHdrKeywords, curHdrLineStart, msgHdrKeywords.Length() - curHdrLineStart));
|
||||||
|
keywordHdr.Append(MSG_LINEBREAK);
|
||||||
|
newKeywordSize += m_fileStream->write(keywordHdr.get(), keywordHdr.Length());
|
||||||
|
curHdrLineStart = nextBlankOffset;
|
||||||
|
keywordHdr.Assign(' ');
|
||||||
|
}
|
||||||
|
nextBlankOffset++;
|
||||||
|
}
|
||||||
|
newKeywordSize += m_fileStream->write(EXTRA_KEYWORD_HDR, sizeof(EXTRA_KEYWORD_HDR) - 1);
|
||||||
|
m_addedHeaderSize += newKeywordSize - oldKeywordSize;
|
||||||
|
m_curSrcHdr->SetUint32Property("growKeywords", 0);
|
||||||
|
needToGrowKeywords = PR_FALSE;
|
||||||
|
writeCount += blockOffset - preKeywordBlockOffset; // fudge writeCount
|
||||||
|
|
||||||
|
}
|
||||||
|
NS_ASSERTION(readCount > blockOffset, "bad block offset");
|
||||||
|
writeCount += m_fileStream->write(m_dataBuffer + blockOffset, readCount - blockOffset);
|
||||||
count -= readCount;
|
count -= readCount;
|
||||||
if (writeCount != readCount)
|
if (writeCount != readCount)
|
||||||
{
|
{
|
||||||
|
@ -860,12 +971,16 @@ nsFolderCompactState::EndCopy(nsISupports *url, nsresult aStatus)
|
||||||
m_db->CopyHdrFromExistingHdr(m_startOfNewMsg, m_curSrcHdr, PR_TRUE,
|
m_db->CopyHdrFromExistingHdr(m_startOfNewMsg, m_curSrcHdr, PR_TRUE,
|
||||||
getter_AddRefs(newMsgHdr));
|
getter_AddRefs(newMsgHdr));
|
||||||
m_curSrcHdr = nsnull;
|
m_curSrcHdr = nsnull;
|
||||||
if (newMsgHdr && m_statusOffset != 0)
|
if (newMsgHdr)
|
||||||
{
|
{
|
||||||
PRUint32 oldMsgSize;
|
if ( m_statusOffset != 0)
|
||||||
newMsgHdr->SetStatusOffset(m_statusOffset);
|
newMsgHdr->SetStatusOffset(m_statusOffset);
|
||||||
(void) newMsgHdr->GetMessageSize(&oldMsgSize);
|
if (m_addedHeaderSize != 0)
|
||||||
newMsgHdr->SetMessageSize(oldMsgSize + m_statusLineSize);
|
{
|
||||||
|
PRUint32 oldMsgSize;
|
||||||
|
(void) newMsgHdr->GetMessageSize(&oldMsgSize);
|
||||||
|
newMsgHdr->SetMessageSize(oldMsgSize + m_addedHeaderSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// m_db->Commit(nsMsgDBCommitType::kLargeCommit); // no sense commiting until the end
|
// m_db->Commit(nsMsgDBCommitType::kLargeCommit); // no sense commiting until the end
|
||||||
|
|
|
@ -79,6 +79,7 @@ protected:
|
||||||
void ShowCompactingStatusMsg();
|
void ShowCompactingStatusMsg();
|
||||||
void ShowDoneStatus();
|
void ShowDoneStatus();
|
||||||
nsresult CompactNextFolder();
|
nsresult CompactNextFolder();
|
||||||
|
void AdvanceToNextLine(const char *buffer, PRUint32 &bufferOffset, PRUint32 maxBufferOffset);
|
||||||
|
|
||||||
|
|
||||||
nsCString m_baseMessageUri; // base message uri
|
nsCString m_baseMessageUri; // base message uri
|
||||||
|
@ -106,7 +107,7 @@ protected:
|
||||||
PRBool m_needStatusLine;
|
PRBool m_needStatusLine;
|
||||||
PRBool m_startOfMsg;
|
PRBool m_startOfMsg;
|
||||||
PRInt32 m_statusOffset;
|
PRInt32 m_statusOffset;
|
||||||
PRInt32 m_statusLineSize;
|
PRInt32 m_addedHeaderSize;
|
||||||
nsCOMPtr <nsISupportsArray> m_offlineFolderArray;
|
nsCOMPtr <nsISupportsArray> m_offlineFolderArray;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,329 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Netscape Communications Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Bienvenu <bienvenu@mozilla.org>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "msgCore.h"
|
||||||
|
#include "nsMsgTagService.h"
|
||||||
|
#include "nsIPrefService.h"
|
||||||
|
#include "nsISupportsPrimitives.h"
|
||||||
|
#include "nsMsgI18N.h"
|
||||||
|
#include "nsIPrefLocalizedString.h"
|
||||||
|
#include "nsMsgDBView.h" // for labels migration
|
||||||
|
#include "nsStringEnumerator.h"
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS1(nsMsgTagService, nsIMsgTagService)
|
||||||
|
|
||||||
|
nsMsgTagService::nsMsgTagService()
|
||||||
|
{
|
||||||
|
m_prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||||
|
// need to figure out how to migrate the tags only once.
|
||||||
|
MigrateLabelsToTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsMsgTagService::~nsMsgTagService()
|
||||||
|
{
|
||||||
|
/* destructor code */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wstring getTagForKey (in string key); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::GetTagForKey(const nsACString &key, nsAString &_retval)
|
||||||
|
{
|
||||||
|
nsCAutoString prefName("mailnews.tags.");
|
||||||
|
prefName.Append(key);
|
||||||
|
prefName.AppendLiteral(".tag");
|
||||||
|
return GetUnicharPref(prefName.get(), _retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void setTagForKey (in string key); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::SetTagForKey(const nsACString &key, const nsAString &tag )
|
||||||
|
{
|
||||||
|
nsCAutoString prefName("mailnews.tags.");
|
||||||
|
prefName.Append(key);
|
||||||
|
prefName.AppendLiteral(".tag");
|
||||||
|
return SetUnicharPref(prefName.get(), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void getKeyForTag (in wstring tag); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::GetKeyForTag(const nsAString &aTag, nsACString &aKey)
|
||||||
|
{
|
||||||
|
PRUint32 count;
|
||||||
|
char **prefList;
|
||||||
|
nsresult rv = m_prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
// traverse the list, and look for a pref with the desired tag value.
|
||||||
|
for (PRUint32 i = count; i--; )
|
||||||
|
{
|
||||||
|
// The prefname we passed to GetChildList was of the form
|
||||||
|
// "mailnews.tags." and we are returned the descendants
|
||||||
|
// in the form of ""mailnews.tags.<key>.tag"
|
||||||
|
// But we only want the tags, so check that the string
|
||||||
|
// ends with tag.
|
||||||
|
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
|
||||||
|
{
|
||||||
|
nsAutoString curTag;
|
||||||
|
GetUnicharPref(prefList[i], curTag);
|
||||||
|
if (aTag.Equals(curTag))
|
||||||
|
{
|
||||||
|
aKey = Substring(nsDependentCString(prefList[i]), 14, strlen(prefList[i]) - 18);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
|
||||||
|
return aKey.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void addTagForKey (in string key, in wstring tag, in long color); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::AddTagForKey(const nsACString &key, const nsAString &tag, const nsACString &color)
|
||||||
|
{
|
||||||
|
nsCAutoString prefName("mailnews.tags.");
|
||||||
|
prefName.Append(key);
|
||||||
|
prefName.AppendLiteral(".tag");
|
||||||
|
SetUnicharPref(prefName.get(), tag);
|
||||||
|
prefName.Replace(prefName.Length() - 3, 3, NS_LITERAL_CSTRING("color"));
|
||||||
|
m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(color).get());
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void addTag (in wstring tag, in long color); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::AddTag(const nsAString &tag, const nsACString &color)
|
||||||
|
{
|
||||||
|
nsCAutoString prefName("mailnews.tags.");
|
||||||
|
// figure out key from tag. Apply transformation stripping out
|
||||||
|
// illegal characters like <SP> and then convert to imap mod utf7.
|
||||||
|
// Then, check if we have a tag with that key yet, and if so,
|
||||||
|
// make it unique by appending -1, -2, etc.
|
||||||
|
// Should we use an iterator?
|
||||||
|
nsAutoString transformedTag(tag);
|
||||||
|
transformedTag.ReplaceChar(" ()/{%*<>\\\"", '_');
|
||||||
|
nsCAutoString key;
|
||||||
|
CopyUTF16toMUTF7(transformedTag, key);
|
||||||
|
prefName.Append(key);
|
||||||
|
while (PR_TRUE)
|
||||||
|
{
|
||||||
|
nsAutoString tagValue;
|
||||||
|
GetUnicharPref(prefName.get(), tagValue);
|
||||||
|
if (tagValue.IsEmpty() || tagValue.Equals(tag))
|
||||||
|
return AddTagForKey(key, tag, color);
|
||||||
|
prefName.Append('A');
|
||||||
|
}
|
||||||
|
NS_ASSERTION(PR_FALSE, "can't get here");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* long getColorForKey (in string key); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::GetColorForKey(const nsACString &key, nsACString &_retval)
|
||||||
|
{
|
||||||
|
nsCAutoString prefName("mailnews.tags.");
|
||||||
|
prefName.Append(key);
|
||||||
|
prefName.AppendLiteral(".color");
|
||||||
|
nsXPIDLCString color;
|
||||||
|
return m_prefBranch->GetCharPref(prefName.get(), getter_Copies(color));
|
||||||
|
_retval = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void deleteTag (in wstring tag); */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::DeleteTag(const nsAString &tag)
|
||||||
|
{
|
||||||
|
// do we want to set a .deleted pref, or just set the tag
|
||||||
|
// property to "", or clear the pref(s)?
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* readonly attribute nsIStringEnumerator tagEnumerator; */
|
||||||
|
NS_IMETHODIMP nsMsgTagService::GetTagEnumerator(nsIStringEnumerator * *aTagEnumerator)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
PRUint32 count;
|
||||||
|
char **prefList;
|
||||||
|
rv = prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsStringArray *stringArray = new nsStringArray(count); // or should it be count / 2?
|
||||||
|
if (!stringArray)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
// traverse the list, and truncate all the descendant strings to just
|
||||||
|
// one branch level below the root branch.
|
||||||
|
for (PRUint32 i = count; i--; )
|
||||||
|
{
|
||||||
|
// The prefname we passed to GetChildList was of the form
|
||||||
|
// "mailnews.tags." and we are returned the descendants
|
||||||
|
// in the form of ""mailnews.tags.<key>.tag"
|
||||||
|
// But we only want the tags, so check that the string
|
||||||
|
// ends with tag.
|
||||||
|
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
|
||||||
|
{
|
||||||
|
nsAutoString tag;
|
||||||
|
GetUnicharPref(prefList[i], tag);
|
||||||
|
stringArray->AppendString(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
|
||||||
|
return NS_NewAdoptingStringEnumerator(aTagEnumerator, stringArray);;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgTagService::GetKeyEnumerator(nsIUTF8StringEnumerator * *aKeyEnumerator)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
PRUint32 count;
|
||||||
|
char **prefList;
|
||||||
|
rv = prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsCStringArray *stringArray = new nsCStringArray; // or should it be count / 2?
|
||||||
|
if (!stringArray)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
// traverse the list, and truncate all the descendant strings to just
|
||||||
|
// one branch level below the root branch.
|
||||||
|
for (PRUint32 i = count; i--; )
|
||||||
|
{
|
||||||
|
// The prefname we passed to GetChildList was of the form
|
||||||
|
// "mailnews.tags." and we are returned the descendants
|
||||||
|
// in the form of ""mailnews.tags.<key>.tag"
|
||||||
|
// But we only want the keys, so check that the string
|
||||||
|
// ends with tag.
|
||||||
|
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
|
||||||
|
{
|
||||||
|
nsDependentCSubstring key(nsDependentCString(prefList[i]), 14, strlen(prefList[i]) - 18);
|
||||||
|
stringArray->AppendCString(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
|
||||||
|
return NS_NewAdoptingUTF8StringEnumerator(aKeyEnumerator, stringArray);;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of implementation class template. */
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsMsgTagService::getPrefService()
|
||||||
|
{
|
||||||
|
if (m_prefBranch)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
m_prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
m_prefBranch = nsnull;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsMsgTagService::SetUnicharPref(const char *prefName,
|
||||||
|
const nsAString &val)
|
||||||
|
{
|
||||||
|
nsresult rv = getPrefService();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (!val.IsEmpty())
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsISupportsString> supportsString =
|
||||||
|
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||||
|
if (supportsString)
|
||||||
|
{
|
||||||
|
supportsString->SetData(val);
|
||||||
|
rv = m_prefBranch->SetComplexValue(prefName,
|
||||||
|
NS_GET_IID(nsISupportsString),
|
||||||
|
supportsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_prefBranch->ClearUserPref(prefName);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsMsgTagService::GetUnicharPref(const char *prefName,
|
||||||
|
nsAString &prefValue)
|
||||||
|
{
|
||||||
|
nsresult rv = getPrefService();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupportsString> supportsString =
|
||||||
|
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||||
|
if (supportsString)
|
||||||
|
{
|
||||||
|
rv = m_prefBranch->GetComplexValue(prefName,
|
||||||
|
NS_GET_IID(nsISupportsString),
|
||||||
|
getter_AddRefs(supportsString));
|
||||||
|
if (supportsString)
|
||||||
|
rv = supportsString->GetData(prefValue);
|
||||||
|
else
|
||||||
|
prefValue.Truncate();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nsresult nsMsgTagService::MigrateLabelsToTags()
|
||||||
|
{
|
||||||
|
nsCString prefString;
|
||||||
|
|
||||||
|
PRInt32 prefVersion = 0;
|
||||||
|
nsresult rv = m_prefBranch->GetIntPref("mailnews.tags.version", &prefVersion);
|
||||||
|
if (NS_SUCCEEDED(rv) && prefVersion == 1)
|
||||||
|
return rv;
|
||||||
|
nsCOMPtr<nsIPrefLocalizedString> pls;
|
||||||
|
nsXPIDLString ucsval;
|
||||||
|
nsCAutoString labelKey("$label1");
|
||||||
|
for(PRInt32 i = 0; i < PREF_LABELS_MAX; )
|
||||||
|
{
|
||||||
|
prefString.Assign(PREF_LABELS_DESCRIPTION);
|
||||||
|
prefString.AppendInt(i + 1);
|
||||||
|
rv = m_prefBranch->GetComplexValue(prefString.get(), NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
pls->ToString(getter_Copies(ucsval));
|
||||||
|
|
||||||
|
prefString.Assign(PREF_LABELS_COLOR);
|
||||||
|
prefString.AppendInt(i + 1);
|
||||||
|
nsXPIDLCString csval;
|
||||||
|
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = m_prefBranch->GetCharPref(prefString.get(), getter_Copies(csval));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = AddTagForKey(labelKey, ucsval, csval);
|
||||||
|
labelKey.SetCharAt(++i + '1', 6);
|
||||||
|
}
|
||||||
|
m_prefBranch->SetIntPref("mailnews.tags.version", 1);
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Netscape Communications Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Bienvenu <bienvenu@mozilla.org>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef nsMsgTagService_h__
|
||||||
|
#define nsMsgTagService_h__
|
||||||
|
|
||||||
|
#include "nsIMsgTagService.h"
|
||||||
|
#include "nsIPrefBranch.h"
|
||||||
|
|
||||||
|
class nsMsgTagEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsMsgTagEntry(const char *key, const PRUnichar *tag, PRUint32 color);
|
||||||
|
nsString m_tag;
|
||||||
|
nsCString m_key;
|
||||||
|
PRUint32 m_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
class nsMsgTagService : public nsIMsgTagService
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIMSGTAGSERVICE
|
||||||
|
|
||||||
|
nsMsgTagService();
|
||||||
|
|
||||||
|
private:
|
||||||
|
~nsMsgTagService();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsresult getPrefService() ;
|
||||||
|
nsresult SetUnicharPref(const char *prefName,
|
||||||
|
const nsAString &prefValue);
|
||||||
|
nsresult GetUnicharPref(const char *prefName,
|
||||||
|
nsAString &prefValue);
|
||||||
|
nsresult MigrateLabelsToTags();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrefBranch> m_prefBranch;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -5250,3 +5250,79 @@ void nsMsgDBFolder::SetMRUTime()
|
||||||
SetStringProperty(MRU_TIME_PROPERTY, nowStr.get());
|
SetStringProperty(MRU_TIME_PROPERTY, nowStr.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgDBFolder::AddKeywordToMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
GetDatabase(nsnull);
|
||||||
|
if (mDatabase)
|
||||||
|
{
|
||||||
|
PRUint32 count;
|
||||||
|
NS_ENSURE_ARG(aMessages);
|
||||||
|
nsresult rv = aMessages->Count(&count);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
|
||||||
|
for(PRUint32 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
nsMsgKey msgKey;
|
||||||
|
nsCOMPtr<nsIMsgDBHdr> message = do_QueryElementAt(aMessages, i, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
(void) message->GetMessageKey(&msgKey);
|
||||||
|
|
||||||
|
message->GetStringProperty("keywords", getter_Copies(keywords));
|
||||||
|
nsACString::const_iterator start, end;
|
||||||
|
if (!MsgFindKeyword(nsDependentCString(aKeyword), keywords, start, end))
|
||||||
|
{
|
||||||
|
if (!keywords.IsEmpty())
|
||||||
|
keywords.Append(' ');
|
||||||
|
keywords.Append(aKeyword);
|
||||||
|
mDatabase->SetStringProperty(msgKey, "keywords", keywords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgDBFolder::RemoveKeywordFromMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
GetDatabase(nsnull);
|
||||||
|
if (mDatabase)
|
||||||
|
{
|
||||||
|
PRUint32 count;
|
||||||
|
NS_ENSURE_ARG(aMessages);
|
||||||
|
nsresult rv = aMessages->Count(&count);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
// If the tag is also a label, we should remove the label too...
|
||||||
|
PRBool keywordIsLabel = (!strncmp(aKeyword, "$label", 6) && aKeyword[6] >= '1' && aKeyword[6] <= '5');
|
||||||
|
|
||||||
|
for(PRUint32 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
nsMsgKey msgKey;
|
||||||
|
nsCOMPtr<nsIMsgDBHdr> message = do_QueryElementAt(aMessages, i, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
(void) message->GetMessageKey(&msgKey);
|
||||||
|
if (keywordIsLabel)
|
||||||
|
{
|
||||||
|
nsMsgLabelValue labelValue;
|
||||||
|
message->GetLabel(&labelValue);
|
||||||
|
if (labelValue == aKeyword[6])
|
||||||
|
message->SetLabel(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = message->GetStringProperty("keywords", getter_Copies(keywords));
|
||||||
|
nsACString::const_iterator start, end;
|
||||||
|
nsACString::const_iterator saveStart;
|
||||||
|
keywords.BeginReading(saveStart);
|
||||||
|
if (MsgFindKeyword(nsDependentCString(aKeyword), keywords, start, end))
|
||||||
|
{
|
||||||
|
keywords.Cut(Distance(saveStart, start), Distance(start, end));
|
||||||
|
mDatabase->SetStringProperty(msgKey, "keywords", keywords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,10 +73,10 @@ class NS_MSG_BASE nsMsgLineBuffer : public nsMsgLineBufferHandler
|
||||||
public:
|
public:
|
||||||
nsMsgLineBuffer(nsMsgLineBufferHandler *handler, PRBool convertNewlinesP);
|
nsMsgLineBuffer(nsMsgLineBufferHandler *handler, PRBool convertNewlinesP);
|
||||||
|
|
||||||
virtual ~nsMsgLineBuffer();
|
virtual ~nsMsgLineBuffer();
|
||||||
PRInt32 BufferInput(const char *net_buffer, PRInt32 net_buffer_size);
|
PRInt32 BufferInput(const char *net_buffer, PRInt32 net_buffer_size);
|
||||||
// Not sure why anyone cares, by NNTPHost seems to want to know the buf pos.
|
// Not sure why anyone cares, by NNTPHost seems to want to know the buf pos.
|
||||||
PRUint32 GetBufferPos() {return m_bufferPos;}
|
PRUint32 GetBufferPos() {return m_bufferPos;}
|
||||||
|
|
||||||
virtual PRInt32 HandleLine(char *line, PRUint32 line_length);
|
virtual PRInt32 HandleLine(char *line, PRUint32 line_length);
|
||||||
// flush last line, though it won't be CRLF terminated.
|
// flush last line, though it won't be CRLF terminated.
|
||||||
|
@ -88,7 +88,7 @@ protected:
|
||||||
void SetLookingForCRLF(PRBool b);
|
void SetLookingForCRLF(PRBool b);
|
||||||
|
|
||||||
nsMsgLineBufferHandler *m_handler;
|
nsMsgLineBufferHandler *m_handler;
|
||||||
PRBool m_convertNewlinesP;
|
PRBool m_convertNewlinesP;
|
||||||
PRBool m_lookingForCRLF;
|
PRBool m_lookingForCRLF;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1221,3 +1221,36 @@ void GetSummaryFileLocation(nsFileSpec& fileLocation, nsFileSpec* summaryLocatio
|
||||||
summaryLocation->SetLeafName(fileName);
|
summaryLocation->SetLeafName(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool MsgFindKeyword(nsACString &keyword, nsACString &keywords, nsACString::const_iterator &start, nsACString::const_iterator &end)
|
||||||
|
{
|
||||||
|
keywords.BeginReading(start);
|
||||||
|
keywords.EndReading(end);
|
||||||
|
if (*start == ' ')
|
||||||
|
start++;
|
||||||
|
nsACString::const_iterator saveStart(start), saveEnd(end);
|
||||||
|
while (PR_TRUE)
|
||||||
|
{
|
||||||
|
if (FindInReadable(keyword, start, end))
|
||||||
|
{
|
||||||
|
PRBool beginMatches = start == saveStart;
|
||||||
|
PRBool endMatches = end == saveEnd;
|
||||||
|
nsACString::const_iterator beforeStart(start);
|
||||||
|
beforeStart--;
|
||||||
|
// start and end point to the beginning and end of the match
|
||||||
|
if (beginMatches && (end == saveEnd || *end == ' ')
|
||||||
|
|| (endMatches && *beforeStart == ' ')
|
||||||
|
|| *beforeStart == ' ' && *end == ' ')
|
||||||
|
{
|
||||||
|
if (*end == ' ')
|
||||||
|
end++;
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
start = end; // advance past bogus match.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,11 @@ NS_MSG_BASE nsresult GetSummaryFileLocation(nsIFileSpec* fileLocation,
|
||||||
// on bug 33451 to remove nsIFileSpec from mailnews.
|
// on bug 33451 to remove nsIFileSpec from mailnews.
|
||||||
NS_MSG_BASE void GetSummaryFileLocation(nsFileSpec& fileLocation,
|
NS_MSG_BASE void GetSummaryFileLocation(nsFileSpec& fileLocation,
|
||||||
nsFileSpec* summaryLocation);
|
nsFileSpec* summaryLocation);
|
||||||
|
// fills in the position of the passed in keyword in the passed in keyword list
|
||||||
|
// and returns false if the keyword isn't present
|
||||||
|
NS_MSG_BASE PRBool MsgFindKeyword(nsACString &keyword, nsACString &keywords,
|
||||||
|
nsACString::const_iterator &start,
|
||||||
|
nsACString::const_iterator &end);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,8 @@
|
||||||
#include "nsCidProtocolHandler.h"
|
#include "nsCidProtocolHandler.h"
|
||||||
#include "nsRssIncomingServer.h"
|
#include "nsRssIncomingServer.h"
|
||||||
#include "nsRssService.h"
|
#include "nsRssService.h"
|
||||||
|
#include "nsMsgTagService.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
#include "nsMessengerWinIntegration.h"
|
#include "nsMessengerWinIntegration.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -330,6 +332,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgGroupView)
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgOfflineManager)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgOfflineManager)
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgProgress)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgProgress)
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSpamSettings)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSpamSettings)
|
||||||
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgTagService)
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCidProtocolHandler)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCidProtocolHandler)
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerWinIntegration, Init)
|
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerWinIntegration, Init)
|
||||||
|
@ -826,6 +829,10 @@ static const nsModuleComponentInfo gComponents[] = {
|
||||||
NS_SPAMSETTINGS_CONTRACTID,
|
NS_SPAMSETTINGS_CONTRACTID,
|
||||||
nsSpamSettingsConstructor,
|
nsSpamSettingsConstructor,
|
||||||
},
|
},
|
||||||
|
{ "Tag Service", NS_MSGTAGSERVICE_CID,
|
||||||
|
NS_MSGTAGSERVICE_CONTRACTID,
|
||||||
|
nsMsgTagServiceConstructor,
|
||||||
|
},
|
||||||
{ "cid protocol", NS_CIDPROTOCOL_CID,
|
{ "cid protocol", NS_CIDPROTOCOL_CID,
|
||||||
NS_CIDPROTOCOLHANDLER_CONTRACTID,
|
NS_CIDPROTOCOLHANDLER_CONTRACTID,
|
||||||
nsCidProtocolHandlerConstructor,
|
nsCidProtocolHandlerConstructor,
|
||||||
|
|
|
@ -47,8 +47,7 @@ nsMsgRecipientArray::nsMsgRecipientArray()
|
||||||
|
|
||||||
nsMsgRecipientArray::~nsMsgRecipientArray()
|
nsMsgRecipientArray::~nsMsgRecipientArray()
|
||||||
{
|
{
|
||||||
if (m_array)
|
delete m_array;
|
||||||
delete m_array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the following macro actually implement addref, release and query interface for our class. */
|
/* the following macro actually implement addref, release and query interface for our class. */
|
||||||
|
@ -56,13 +55,13 @@ NS_IMPL_ISUPPORTS1(nsMsgRecipientArray, nsIMsgRecipientArray)
|
||||||
|
|
||||||
nsresult nsMsgRecipientArray::StringAt(PRInt32 idx, PRUnichar **_retval)
|
nsresult nsMsgRecipientArray::StringAt(PRInt32 idx, PRUnichar **_retval)
|
||||||
{
|
{
|
||||||
if (!_retval || !m_array)
|
if (!_retval || !m_array)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
nsString aStr;
|
nsString aStr;
|
||||||
m_array->StringAt(idx, aStr);
|
m_array->StringAt(idx, aStr);
|
||||||
*_retval = ToNewUnicode(aStr);
|
*_retval = ToNewUnicode(aStr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMsgRecipientArray::AppendString(const PRUnichar *aString, PRBool *_retval)
|
nsresult nsMsgRecipientArray::AppendString(const PRUnichar *aString, PRBool *_retval)
|
||||||
|
|
|
@ -876,6 +876,8 @@ nsMsgSendLater::BuildHeaders()
|
||||||
prune_p = do_flags_p = PR_TRUE;
|
prune_p = do_flags_p = PR_TRUE;
|
||||||
else if (!PL_strncasecmp(HEADER_X_MOZILLA_DRAFT_INFO, buf, end - buf))
|
else if (!PL_strncasecmp(HEADER_X_MOZILLA_DRAFT_INFO, buf, end - buf))
|
||||||
prune_p = do_return_receipt_p = PR_TRUE;
|
prune_p = do_return_receipt_p = PR_TRUE;
|
||||||
|
else if (!PL_strncasecmp(HEADER_X_MOZILLA_KEYWORDS, buf, end - buf))
|
||||||
|
prune_p = PR_TRUE;
|
||||||
else if (!PL_strncasecmp(HEADER_X_MOZILLA_NEWSHOST, buf, end - buf))
|
else if (!PL_strncasecmp(HEADER_X_MOZILLA_NEWSHOST, buf, end - buf))
|
||||||
{
|
{
|
||||||
prune_p = PR_TRUE;
|
prune_p = PR_TRUE;
|
||||||
|
|
|
@ -290,7 +290,9 @@ interface nsIMsgDatabase : nsIDBChangeAnnouncer {
|
||||||
// for msg hdr hash table allocation. controllable by caller to improve folder loading preformance.
|
// for msg hdr hash table allocation. controllable by caller to improve folder loading preformance.
|
||||||
attribute unsigned long msgHdrCacheSize;
|
attribute unsigned long msgHdrCacheSize;
|
||||||
|
|
||||||
void setFolderStream(in nsIOFileStream aFileStream);
|
// extremely deprecated - this is going away when we get rid of nsFileSpec and friends.
|
||||||
|
// and it's [noscript] though I don't know if you can make an attribute noscript.
|
||||||
|
attribute nsIOFileStream folderStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of messages currently in the NEW state.
|
* The list of messages currently in the NEW state.
|
||||||
|
|
|
@ -43,21 +43,23 @@ typedef unsigned short imapMessageFlagsType;
|
||||||
|
|
||||||
typedef long nsOfflineImapOperationType;
|
typedef long nsOfflineImapOperationType;
|
||||||
|
|
||||||
[scriptable, uuid(7cc7dec6-ea50-11d4-a5b7-0060b0fc04b7)]
|
[scriptable, uuid(2728cb2b-4716-4b5e-98a7-ce22569378e5)]
|
||||||
|
|
||||||
interface nsIMsgOfflineImapOperation : nsISupports
|
interface nsIMsgOfflineImapOperation : nsISupports
|
||||||
{
|
{
|
||||||
// type of stored imap operations
|
// type of stored imap operations
|
||||||
const long kFlagsChanged = 0x1;
|
const long kFlagsChanged = 0x1;
|
||||||
const long kMsgMoved = 0x2;
|
const long kMsgMoved = 0x2;
|
||||||
const long kMsgCopy = 0x4;
|
const long kMsgCopy = 0x4;
|
||||||
const long kMoveResult = 0x8;
|
const long kMoveResult = 0x8;
|
||||||
const long kAppendDraft = 0x10;
|
const long kAppendDraft = 0x10;
|
||||||
const long kAddedHeader = 0x20;
|
const long kAddedHeader = 0x20;
|
||||||
const long kDeletedMsg = 0x40;
|
const long kDeletedMsg = 0x40;
|
||||||
const long kMsgMarkedDeleted = 0x80;
|
const long kMsgMarkedDeleted = 0x80;
|
||||||
const long kAppendTemplate = 0x100;
|
const long kAppendTemplate = 0x100;
|
||||||
const long kDeleteAllMsgs = 0x200;
|
const long kDeleteAllMsgs = 0x200;
|
||||||
|
const long kAddKeywords = 0x400;
|
||||||
|
const long kRemoveKeywords = 0x800;
|
||||||
|
|
||||||
attribute nsOfflineImapOperationType operation;
|
attribute nsOfflineImapOperationType operation;
|
||||||
void clearOperation(in nsOfflineImapOperationType operation);
|
void clearOperation(in nsOfflineImapOperationType operation);
|
||||||
|
@ -66,6 +68,10 @@ interface nsIMsgOfflineImapOperation : nsISupports
|
||||||
attribute imapMessageFlagsType newFlags; // for kFlagsChanged
|
attribute imapMessageFlagsType newFlags; // for kFlagsChanged
|
||||||
attribute string destinationFolderURI; // for move or copy
|
attribute string destinationFolderURI; // for move or copy
|
||||||
attribute string sourceFolderURI;
|
attribute string sourceFolderURI;
|
||||||
|
void addKeywordToAdd(in string aKeyword);
|
||||||
|
void addKeywordToRemove(in string aKeyword);
|
||||||
|
readonly attribute string keywordsToAdd;
|
||||||
|
readonly attribute string keywordsToRemove;
|
||||||
readonly attribute long numberOfCopies;
|
readonly attribute long numberOfCopies;
|
||||||
void addMessageCopyOperation(in string destinationBox);
|
void addMessageCopyOperation(in string destinationBox);
|
||||||
string getCopyDestination(in long copyIndex);
|
string getCopyDestination(in long copyIndex);
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD ForceClosed();
|
NS_IMETHOD ForceClosed();
|
||||||
NS_IMETHOD SetFolderStream(nsIOFileStream *aFileStream);
|
NS_IMETHOD SetFolderStream(nsIOFileStream *aFileStream);
|
||||||
|
NS_IMETHOD GetFolderStream(nsIOFileStream **aFileStream);
|
||||||
NS_IMETHOD AddNewHdrToDB(nsIMsgDBHdr *newHdr, PRBool notify);
|
NS_IMETHOD AddNewHdrToDB(nsIMsgDBHdr *newHdr, PRBool notify);
|
||||||
NS_IMETHOD SetAttributesOnPendingHdr(nsIMsgDBHdr *pendingHdr, const char *property,
|
NS_IMETHOD SetAttributesOnPendingHdr(nsIMsgDBHdr *pendingHdr, const char *property,
|
||||||
const char *propertyVal, PRInt32 flags);
|
const char *propertyVal, PRInt32 flags);
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
NS_IMETHOD ListAllOfflineDeletes(nsMsgKeyArray *offlineDeletes);
|
NS_IMETHOD ListAllOfflineDeletes(nsMsgKeyArray *offlineDeletes);
|
||||||
|
|
||||||
NS_IMETHOD SetFolderStream(nsIOFileStream *aFileStream);
|
NS_IMETHOD SetFolderStream(nsIOFileStream *aFileStream);
|
||||||
|
NS_IMETHOD GetFolderStream(nsIOFileStream **aFileStream);
|
||||||
|
|
||||||
friend class nsMsgOfflineOpEnumerator;
|
friend class nsMsgOfflineOpEnumerator;
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -188,7 +188,7 @@ protected:
|
||||||
static void AddToCache(nsMsgDatabase* pMessageDB)
|
static void AddToCache(nsMsgDatabase* pMessageDB)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_David_Bienvenu
|
#ifdef DEBUG_David_Bienvenu
|
||||||
NS_ASSERTION(GetNumInCache() < 28, "28 or more open db's");
|
NS_ASSERTION(GetNumInCache() < 40, "40 or more open db's");
|
||||||
#endif
|
#endif
|
||||||
GetDBCache()->AppendElement(pMessageDB);}
|
GetDBCache()->AppendElement(pMessageDB);}
|
||||||
static void RemoveFromCache(nsMsgDatabase* pMessageDB);
|
static void RemoveFromCache(nsMsgDatabase* pMessageDB);
|
||||||
|
|
|
@ -117,6 +117,11 @@ NS_IMETHODIMP nsImapMailDatabase::ForceClosed()
|
||||||
return nsMailDatabase::ForceClosed();
|
return nsMailDatabase::ForceClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsImapMailDatabase::GetFolderStream(nsIOFileStream **aFileStream)
|
||||||
|
{
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsImapMailDatabase::SetFolderStream(nsIOFileStream *aFileStream)
|
NS_IMETHODIMP nsImapMailDatabase::SetFolderStream(nsIOFileStream *aFileStream)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(0, "Trying to set folderStream, not implemented");
|
NS_ASSERTION(0, "Trying to set folderStream, not implemented");
|
||||||
|
|
|
@ -79,6 +79,19 @@ NS_IMETHODIMP nsMailDatabase::SetFolderStream(nsIOFileStream *aFileStream)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMailDatabase::GetFolderStream(nsIOFileStream **aFileStream)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aFileStream);
|
||||||
|
if (!m_folderStream)
|
||||||
|
{
|
||||||
|
m_folderStream = new nsIOFileStream(nsFileSpec(*m_folderSpec));
|
||||||
|
m_ownFolderStream = PR_TRUE;
|
||||||
|
}
|
||||||
|
// N.B. - not a ref-counted interface pointer
|
||||||
|
*aFileStream = m_folderStream;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static PRBool gGotGlobalPrefs = PR_FALSE;
|
static PRBool gGotGlobalPrefs = PR_FALSE;
|
||||||
static PRInt32 gTimeStampLeeway;
|
static PRInt32 gTimeStampLeeway;
|
||||||
|
|
||||||
|
|
|
@ -4756,6 +4756,11 @@ NS_IMETHODIMP nsMsgDatabase::ResetHdrCacheSize(PRUint32 aSize)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgDatabase::GetFolderStream(nsIOFileStream **aFileStream)
|
||||||
|
{
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsMsgDatabase::SetFolderStream(nsIOFileStream *aFileStream)
|
NS_IMETHODIMP nsMsgDatabase::SetFolderStream(nsIOFileStream *aFileStream)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(0, "Trying to set the folderStream, not implemented");
|
NS_ASSERTION(0, "Trying to set the folderStream, not implemented");
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "msgCore.h"
|
#include "msgCore.h"
|
||||||
#include "nsMsgOfflineImapOperation.h"
|
#include "nsMsgOfflineImapOperation.h"
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
|
#include "nsMsgUtils.h"
|
||||||
|
|
||||||
PRLogModuleInfo *IMAPOffline;
|
PRLogModuleInfo *IMAPOffline;
|
||||||
|
|
||||||
|
@ -61,6 +62,8 @@ NS_IMPL_ISUPPORTS1(nsMsgOfflineImapOperation, nsIMsgOfflineImapOperation)
|
||||||
#define PROP_NUM_COPY_DESTS "numCopyDests"
|
#define PROP_NUM_COPY_DESTS "numCopyDests"
|
||||||
#define PROP_COPY_DESTS "copyDests" // how to delimit these? Or should we do the "dest1","dest2" etc trick? But then we'd need to shuffle
|
#define PROP_COPY_DESTS "copyDests" // how to delimit these? Or should we do the "dest1","dest2" etc trick? But then we'd need to shuffle
|
||||||
// them around since we delete off the front first.
|
// them around since we delete off the front first.
|
||||||
|
#define PROP_KEYWORD_ADD "addedKeywords"
|
||||||
|
#define PROP_KEYWORD_REMOVE "removedKeywords"
|
||||||
|
|
||||||
nsMsgOfflineImapOperation::nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row)
|
nsMsgOfflineImapOperation::nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +212,77 @@ NS_IMETHODIMP nsMsgOfflineImapOperation::SetSourceFolderURI(const char * aSource
|
||||||
return m_mdb->SetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, aSourceFolderURI);
|
return m_mdb->SetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, aSourceFolderURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* attribute string keyword; */
|
||||||
|
NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToAdd(char * *aKeywords)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG(aKeywords);
|
||||||
|
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_ADD, getter_Copies(m_keywordsToAdd));
|
||||||
|
*aKeywords = nsCRT::strdup(m_keywordsToAdd);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToAdd(const char * aKeyword)
|
||||||
|
{
|
||||||
|
return AddKeyword(aKeyword, m_keywordsToAdd, PROP_KEYWORD_ADD, m_keywordsToRemove, PROP_KEYWORD_REMOVE);
|
||||||
|
nsACString::const_iterator start, end;
|
||||||
|
if (!MsgFindKeyword(nsDependentCString(aKeyword), m_keywordsToAdd, start, end))
|
||||||
|
{
|
||||||
|
if (!m_keywordsToAdd.IsEmpty())
|
||||||
|
m_keywordsToAdd.Append(' ');
|
||||||
|
m_keywordsToAdd.Append(aKeyword);
|
||||||
|
}
|
||||||
|
// if the keyword we're adding was in the list of keywords to remove,
|
||||||
|
// cut it from that list.
|
||||||
|
nsACString::const_iterator removeStart, removeEnd;
|
||||||
|
if (MsgFindKeyword(nsDependentCString(aKeyword), m_keywordsToRemove, removeStart, removeEnd))
|
||||||
|
{
|
||||||
|
nsACString::const_iterator saveStart;
|
||||||
|
m_keywordsToRemove.BeginReading(saveStart);
|
||||||
|
m_keywordsToRemove.Cut(Distance(saveStart, removeStart), Distance(removeStart, removeEnd));
|
||||||
|
m_mdb->SetProperty(m_mdbRow, PROP_KEYWORD_REMOVE, m_keywordsToRemove.get());
|
||||||
|
}
|
||||||
|
SetOperation(kAddKeywords);
|
||||||
|
return m_mdb->SetProperty(m_mdbRow, PROP_KEYWORD_ADD, m_keywordsToAdd.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToRemove(char * *aKeywords)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG(aKeywords);
|
||||||
|
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_REMOVE, getter_Copies(m_keywordsToRemove));
|
||||||
|
*aKeywords = nsCRT::strdup(m_keywordsToRemove);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsMsgOfflineImapOperation::AddKeyword(const char *aKeyword, nsCString &addList, const char *addProp,
|
||||||
|
nsCString &removeList, const char *removeProp)
|
||||||
|
{
|
||||||
|
nsACString::const_iterator start, end;
|
||||||
|
if (!MsgFindKeyword(nsDependentCString(aKeyword), addList, start, end))
|
||||||
|
{
|
||||||
|
if (!addList.IsEmpty())
|
||||||
|
addList.Append(' ');
|
||||||
|
addList.Append(aKeyword);
|
||||||
|
}
|
||||||
|
// if the keyword we're removing was in the list of keywords to add,
|
||||||
|
// cut it from that list.
|
||||||
|
nsACString::const_iterator addStart, addEnd;
|
||||||
|
if (MsgFindKeyword(nsDependentCString(aKeyword), removeList, addStart, addEnd))
|
||||||
|
{
|
||||||
|
nsACString::const_iterator saveStart;
|
||||||
|
removeList.BeginReading(saveStart);
|
||||||
|
removeList.Cut(Distance(saveStart, addStart), Distance(addStart, addEnd));
|
||||||
|
m_mdb->SetProperty(m_mdbRow, removeProp, removeList.get());
|
||||||
|
}
|
||||||
|
SetOperation(kRemoveKeywords);
|
||||||
|
return m_mdb->SetProperty(m_mdbRow, addProp, addList.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToRemove(const char * aKeyword)
|
||||||
|
{
|
||||||
|
return AddKeyword(aKeyword, m_keywordsToRemove, PROP_KEYWORD_REMOVE, m_keywordsToAdd, PROP_KEYWORD_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP nsMsgOfflineImapOperation::AddMessageCopyOperation(const char *destinationBox)
|
NS_IMETHODIMP nsMsgOfflineImapOperation::AddMessageCopyOperation(const char *destinationBox)
|
||||||
{
|
{
|
||||||
SetOperation(kMsgCopy);
|
SetOperation(kMsgCopy);
|
||||||
|
@ -325,5 +399,13 @@ void nsMsgOfflineImapOperation::Log(PRLogModuleInfo *logFile)
|
||||||
{
|
{
|
||||||
PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x append draft", m_messageKey));
|
PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x append draft", m_messageKey));
|
||||||
}
|
}
|
||||||
|
if (m_operation & nsIMsgOfflineImapOperation::kAddKeywords)
|
||||||
|
{
|
||||||
|
PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x add keyword:%s", m_messageKey, m_keywordsToAdd.get()));
|
||||||
|
}
|
||||||
|
if (m_operation & nsIMsgOfflineImapOperation::kRemoveKeywords)
|
||||||
|
{
|
||||||
|
PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x remove keyword:%s", m_messageKey, m_keywordsToRemove.get()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,29 +45,35 @@
|
||||||
class nsMsgOfflineImapOperation : public nsIMsgOfflineImapOperation
|
class nsMsgOfflineImapOperation : public nsIMsgOfflineImapOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Instance Methods **/
|
/** Instance Methods **/
|
||||||
nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row);
|
nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row);
|
||||||
virtual ~nsMsgOfflineImapOperation();
|
virtual ~nsMsgOfflineImapOperation();
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIMSGOFFLINEIMAPOPERATION
|
NS_DECL_NSIMSGOFFLINEIMAPOPERATION
|
||||||
|
|
||||||
|
|
||||||
nsIMdbRow *GetMDBRow() {return m_mdbRow;}
|
nsIMdbRow *GetMDBRow() {return m_mdbRow;}
|
||||||
nsresult GetCopiesFromDB();
|
nsresult GetCopiesFromDB();
|
||||||
nsresult SetCopiesToDB();
|
nsresult SetCopiesToDB();
|
||||||
void Log(PRLogModuleInfo *logFile);
|
void Log(PRLogModuleInfo *logFile);
|
||||||
protected:
|
protected:
|
||||||
|
nsresult AddKeyword(const char *aKeyword, nsCString &addList, const char *addProp,
|
||||||
|
nsCString &removeList, const char *removeProp);
|
||||||
|
|
||||||
nsOfflineImapOperationType m_operation;
|
nsOfflineImapOperationType m_operation;
|
||||||
nsMsgKey m_messageKey;
|
nsMsgKey m_messageKey;
|
||||||
nsMsgKey m_sourceMessageKey;
|
nsMsgKey m_sourceMessageKey;
|
||||||
PRUint32 m_operationFlags; // what to do on sync
|
PRUint32 m_operationFlags; // what to do on sync
|
||||||
imapMessageFlagsType m_newFlags; // used for kFlagsChanged
|
imapMessageFlagsType m_newFlags; // used for kFlagsChanged
|
||||||
|
|
||||||
// these are URI's, and are escaped. Thus, we can use a delimter like ' '
|
// these are URI's, and are escaped. Thus, we can use a delimter like ' '
|
||||||
// because the real spaces should be escaped.
|
// because the real spaces should be escaped.
|
||||||
nsXPIDLCString m_sourceFolder;
|
nsXPIDLCString m_sourceFolder;
|
||||||
nsXPIDLCString m_moveDestination;
|
nsXPIDLCString m_moveDestination;
|
||||||
nsCStringArray m_copyDestinations;
|
nsCStringArray m_copyDestinations;
|
||||||
|
|
||||||
|
nsXPIDLCString m_keywordsToAdd;
|
||||||
|
nsXPIDLCString m_keywordsToRemove;
|
||||||
|
|
||||||
// nsMsgOfflineImapOperation will have to know what db and row they belong to, since they are really
|
// nsMsgOfflineImapOperation will have to know what db and row they belong to, since they are really
|
||||||
// just a wrapper around the offline operation row in the mdb.
|
// just a wrapper around the offline operation row in the mdb.
|
||||||
|
|
|
@ -3462,6 +3462,16 @@ NS_IMETHODIMP nsImapMailFolder::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWindo
|
||||||
keysToFlag.GetSize(), nsnull);
|
keysToFlag.GetSize(), nsnull);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nsMsgFilterAction::AddTag:
|
||||||
|
{
|
||||||
|
nsXPIDLCString keyword;
|
||||||
|
filterAction->GetStrValue(getter_Copies(keyword));
|
||||||
|
nsCOMPtr<nsISupportsArray> messageArray;
|
||||||
|
NS_NewISupportsArray(getter_AddRefs(messageArray));
|
||||||
|
messageArray->AppendElement(msgHdr);
|
||||||
|
AddKeywordToMessages(messageArray, keyword.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
case nsMsgFilterAction::JunkScore:
|
case nsMsgFilterAction::JunkScore:
|
||||||
{
|
{
|
||||||
nsCAutoString junkScoreStr;
|
nsCAutoString junkScoreStr;
|
||||||
|
@ -7063,7 +7073,7 @@ nsImapFolderCopyState::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
|
||||||
PRUint32 childCount;
|
PRUint32 childCount;
|
||||||
m_srcFolder->Count(&childCount);
|
m_srcFolder->Count(&childCount);
|
||||||
|
|
||||||
for (PRInt32 childIndex = 0; childIndex < childCount; childIndex++)
|
for (PRUint32 childIndex = 0; childIndex < childCount; childIndex++)
|
||||||
{
|
{
|
||||||
nsCOMPtr <nsISupports> child = do_QueryElementAt(m_srcFolder, childIndex, &rv);
|
nsCOMPtr <nsISupports> child = do_QueryElementAt(m_srcFolder, childIndex, &rv);
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
|
@ -7931,7 +7941,7 @@ NS_IMETHODIMP nsImapMailFolder::RenameClient(nsIMsgWindow *msgWindow, nsIMsgFold
|
||||||
nsCOMPtr<nsIMsgFolder> msgParent;
|
nsCOMPtr<nsIMsgFolder> msgParent;
|
||||||
msgFolder->GetParentMsgFolder(getter_AddRefs(msgParent));
|
msgFolder->GetParentMsgFolder(getter_AddRefs(msgParent));
|
||||||
msgFolder->SetParent(nsnull);
|
msgFolder->SetParent(nsnull);
|
||||||
msgParent->PropagateDelete(msgFolder,PR_FALSE, nsnull);
|
msgParent->PropagateDelete(msgFolder, PR_TRUE, nsnull);
|
||||||
|
|
||||||
// Reset online status now that the folder is renamed.
|
// Reset online status now that the folder is renamed.
|
||||||
nsCOMPtr <nsIMsgImapMailFolder> oldImapFolder = do_QueryInterface(msgFolder);
|
nsCOMPtr <nsIMsgImapMailFolder> oldImapFolder = do_QueryInterface(msgFolder);
|
||||||
|
@ -8149,6 +8159,28 @@ nsImapMailFolder::StoreCustomKeywords(nsIMsgWindow *aMsgWindow, const char *aFla
|
||||||
const char *aFlagsToSubtract, nsMsgKey *aKeysToStore, PRUint32 aNumKeys, nsIURI **_retval)
|
const char *aFlagsToSubtract, nsMsgKey *aKeysToStore, PRUint32 aNumKeys, nsIURI **_retval)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
if (WeAreOffline())
|
||||||
|
{
|
||||||
|
GetDatabase(nsnull);
|
||||||
|
if (mDatabase)
|
||||||
|
{
|
||||||
|
for (PRUint32 keyIndex = 0; keyIndex < aNumKeys; keyIndex++)
|
||||||
|
{
|
||||||
|
nsCOMPtr <nsIMsgOfflineImapOperation> op;
|
||||||
|
rv = mDatabase->GetOfflineOpForKey(aKeysToStore[keyIndex], PR_TRUE, getter_AddRefs(op));
|
||||||
|
SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
|
||||||
|
if (NS_SUCCEEDED(rv) && op)
|
||||||
|
{
|
||||||
|
if (aFlagsToAdd)
|
||||||
|
op->AddKeywordToAdd(aFlagsToAdd);
|
||||||
|
if (aFlagsToSubtract)
|
||||||
|
op->AddKeywordToRemove(aFlagsToSubtract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDatabase->Commit(nsMsgDBCommitType::kLargeCommit); // flush offline ops
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
nsCOMPtr<nsIImapService> imapService(do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv));
|
nsCOMPtr<nsIImapService> imapService(do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
nsCAutoString msgIds;
|
nsCAutoString msgIds;
|
||||||
|
@ -8471,3 +8503,34 @@ NS_IMETHODIMP nsImapMailFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUi
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsImapMailFolder::AddKeywordToMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
nsresult rv = nsMsgDBFolder::AddKeywordToMessages(aMessages, aKeyword);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
{
|
||||||
|
nsCAutoString messageIds;
|
||||||
|
nsMsgKeyArray keys;
|
||||||
|
rv = BuildIdsAndKeyArray(aMessages, messageIds, keys);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = StoreCustomKeywords(nsnull, aKeyword, nsnull, keys.GetArray(), keys.GetSize(), nsnull);
|
||||||
|
if (mDatabase)
|
||||||
|
mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsImapMailFolder::RemoveKeywordFromMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
nsresult rv = nsMsgDBFolder::RemoveKeywordFromMessages(aMessages, aKeyword);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
{
|
||||||
|
nsCAutoString messageIds;
|
||||||
|
nsMsgKeyArray keys;
|
||||||
|
nsresult rv = BuildIdsAndKeyArray(aMessages, messageIds, keys);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = StoreCustomKeywords(nsnull, nsnull, aKeyword, keys.GetArray(), keys.GetSize(), nsnull);
|
||||||
|
if (mDatabase)
|
||||||
|
mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
|
@ -291,6 +291,9 @@ public:
|
||||||
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
|
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
|
||||||
PRBool *aAsyncResults);
|
PRBool *aAsyncResults);
|
||||||
|
|
||||||
|
NS_IMETHOD AddKeywordToMessages(nsISupportsArray *aMessages, const char *aKeyword);
|
||||||
|
NS_IMETHOD RemoveKeywordFromMessages(nsISupportsArray *aMessages, const char *aKeyword);
|
||||||
|
|
||||||
// nsIMsgImapMailFolder methods
|
// nsIMsgImapMailFolder methods
|
||||||
NS_DECL_NSIMSGIMAPMAILFOLDER
|
NS_DECL_NSIMSGIMAPMAILFOLDER
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,77 @@ void nsImapOfflineSync::ProcessFlagOperation(nsIMsgOfflineImapOperation *op)
|
||||||
ProcessNextOperation();
|
ProcessNextOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsImapOfflineSync::ProcessKeywordOperation(nsIMsgOfflineImapOperation *op)
|
||||||
|
{
|
||||||
|
nsCOMPtr <nsIMsgOfflineImapOperation> currentOp = op;
|
||||||
|
nsMsgKeyArray matchingKeywordKeys;
|
||||||
|
PRUint32 currentKeyIndex = m_KeyIndex;
|
||||||
|
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kAddKeywords)
|
||||||
|
currentOp->GetKeywordsToAdd(getter_Copies(keywords));
|
||||||
|
else
|
||||||
|
currentOp->GetKeywordsToRemove(getter_Copies(keywords));
|
||||||
|
PRBool keywordsMatch = PR_TRUE;
|
||||||
|
do
|
||||||
|
{ // loop for all messsages with the same keywords
|
||||||
|
if (keywordsMatch)
|
||||||
|
{
|
||||||
|
nsMsgKey curKey;
|
||||||
|
currentOp->GetMessageKey(&curKey);
|
||||||
|
matchingKeywordKeys.Add(curKey);
|
||||||
|
currentOp->ClearOperation(mCurrentPlaybackOpType);
|
||||||
|
}
|
||||||
|
currentOp = nsnull;
|
||||||
|
if (++currentKeyIndex < m_CurrentKeys.GetSize())
|
||||||
|
m_currentDB->GetOfflineOpForKey(m_CurrentKeys[currentKeyIndex], PR_FALSE,
|
||||||
|
getter_AddRefs(currentOp));
|
||||||
|
if (currentOp)
|
||||||
|
{
|
||||||
|
nsXPIDLCString curOpKeywords;
|
||||||
|
nsOfflineImapOperationType operation;
|
||||||
|
currentOp->GetOperation(&operation);
|
||||||
|
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kAddKeywords)
|
||||||
|
currentOp->GetKeywordsToAdd(getter_Copies(curOpKeywords));
|
||||||
|
else
|
||||||
|
currentOp->GetKeywordsToRemove(getter_Copies(curOpKeywords));
|
||||||
|
keywordsMatch = (operation & mCurrentPlaybackOpType)
|
||||||
|
&& (curOpKeywords.Equals(keywords));
|
||||||
|
}
|
||||||
|
} while (currentOp);
|
||||||
|
|
||||||
|
if (matchingKeywordKeys.GetSize() > 0)
|
||||||
|
{
|
||||||
|
PRUint32 curFolderFlags;
|
||||||
|
m_currentFolder->GetFlags(&curFolderFlags);
|
||||||
|
|
||||||
|
if (curFolderFlags & MSG_FOLDER_FLAG_IMAPBOX)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(m_currentFolder);
|
||||||
|
nsCOMPtr <nsIURI> uriToStoreCustomKeywords;
|
||||||
|
if (imapFolder)
|
||||||
|
{
|
||||||
|
rv = imapFolder->StoreCustomKeywords(m_window,
|
||||||
|
(mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kAddKeywords) ? keywords.get() : nsnull,
|
||||||
|
(mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kRemoveKeywords) ? keywords.get() : nsnull,
|
||||||
|
matchingKeywordKeys.GetArray(),
|
||||||
|
matchingKeywordKeys.GetSize(), getter_AddRefs(uriToStoreCustomKeywords));
|
||||||
|
if (NS_SUCCEEDED(rv) && uriToStoreCustomKeywords)
|
||||||
|
{
|
||||||
|
nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(uriToStoreCustomKeywords);
|
||||||
|
if (mailnewsUrl)
|
||||||
|
mailnewsUrl->RegisterListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ProcessNextOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsImapOfflineSync::ProcessAppendMsgOperation(nsIMsgOfflineImapOperation *currentOp, PRInt32 opType)
|
nsImapOfflineSync::ProcessAppendMsgOperation(nsIMsgOfflineImapOperation *currentOp, PRInt32 opType)
|
||||||
{
|
{
|
||||||
|
@ -800,6 +871,20 @@ nsresult nsImapOfflineSync::ProcessNextOperation()
|
||||||
{
|
{
|
||||||
// we are done with the current type
|
// we are done with the current type
|
||||||
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kFlagsChanged)
|
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kFlagsChanged)
|
||||||
|
{
|
||||||
|
mCurrentPlaybackOpType = nsIMsgOfflineImapOperation::kAddKeywords;
|
||||||
|
// recurse to deal with next type of operation
|
||||||
|
m_KeyIndex = 0;
|
||||||
|
ProcessNextOperation();
|
||||||
|
}
|
||||||
|
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kAddKeywords)
|
||||||
|
{
|
||||||
|
mCurrentPlaybackOpType = nsIMsgOfflineImapOperation::kRemoveKeywords;
|
||||||
|
// recurse to deal with next type of operation
|
||||||
|
m_KeyIndex = 0;
|
||||||
|
ProcessNextOperation();
|
||||||
|
}
|
||||||
|
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kRemoveKeywords)
|
||||||
{
|
{
|
||||||
mCurrentPlaybackOpType = nsIMsgOfflineImapOperation::kMsgCopy;
|
mCurrentPlaybackOpType = nsIMsgOfflineImapOperation::kMsgCopy;
|
||||||
// recurse to deal with next type of operation
|
// recurse to deal with next type of operation
|
||||||
|
@ -844,6 +929,9 @@ nsresult nsImapOfflineSync::ProcessNextOperation()
|
||||||
{
|
{
|
||||||
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kFlagsChanged)
|
if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kFlagsChanged)
|
||||||
ProcessFlagOperation(currentOp);
|
ProcessFlagOperation(currentOp);
|
||||||
|
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kAddKeywords
|
||||||
|
||mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kRemoveKeywords)
|
||||||
|
ProcessKeywordOperation(currentOp);
|
||||||
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kMsgCopy)
|
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kMsgCopy)
|
||||||
ProcessCopyOperation(currentOp);
|
ProcessCopyOperation(currentOp);
|
||||||
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kMsgMoved)
|
else if (mCurrentPlaybackOpType == nsIMsgOfflineImapOperation::kMsgMoved)
|
||||||
|
|
|
@ -73,6 +73,7 @@ protected:
|
||||||
void DeleteAllOfflineOpsForCurrentDB();
|
void DeleteAllOfflineOpsForCurrentDB();
|
||||||
|
|
||||||
void ProcessFlagOperation(nsIMsgOfflineImapOperation *currentOp);
|
void ProcessFlagOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||||
|
void ProcessKeywordOperation(nsIMsgOfflineImapOperation *op);
|
||||||
void ProcessMoveOperation(nsIMsgOfflineImapOperation *currentOp);
|
void ProcessMoveOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||||
void ProcessCopyOperation(nsIMsgOfflineImapOperation *currentOp);
|
void ProcessCopyOperation(nsIMsgOfflineImapOperation *currentOp);
|
||||||
void ProcessEmptyTrash(nsIMsgOfflineImapOperation *currentOp);
|
void ProcessEmptyTrash(nsIMsgOfflineImapOperation *currentOp);
|
||||||
|
|
|
@ -86,7 +86,6 @@
|
||||||
#include "nsICopyMsgStreamListener.h"
|
#include "nsICopyMsgStreamListener.h"
|
||||||
#include "nsIFileStream.h"
|
#include "nsIFileStream.h"
|
||||||
#include "nsIMsgParseMailMsgState.h"
|
#include "nsIMsgParseMailMsgState.h"
|
||||||
#include "nsMsgLineBuffer.h"
|
|
||||||
#include "nsMsgLocalCID.h"
|
#include "nsMsgLocalCID.h"
|
||||||
#include "nsIOutputStream.h"
|
#include "nsIOutputStream.h"
|
||||||
#include "nsIDocShell.h"
|
#include "nsIDocShell.h"
|
||||||
|
@ -1589,10 +1588,6 @@ nsImapService::SetMessageFlags(nsIEventTarget * aClientEventTarget,
|
||||||
imapMessageFlagsType flags,
|
imapMessageFlagsType flags,
|
||||||
PRBool messageIdsAreUID)
|
PRBool messageIdsAreUID)
|
||||||
{
|
{
|
||||||
// create a protocol instance to handle the request.
|
|
||||||
// NOTE: once we start working with multiple connections, this step will be much more complicated...but for now
|
|
||||||
// just create a connection and process the request.
|
|
||||||
|
|
||||||
return DiddleFlags(aClientEventTarget, aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
|
return DiddleFlags(aClientEventTarget, aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
|
||||||
"setmsgflags", flags, messageIdsAreUID);
|
"setmsgflags", flags, messageIdsAreUID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2507,11 +2507,13 @@ keepGoing:
|
||||||
|
|
||||||
void nsMsgLocalMailFolder::CopyPropertiesToMsgHdr(nsIMsgDBHdr *destHdr, nsIMsgDBHdr *srcHdr)
|
void nsMsgLocalMailFolder::CopyPropertiesToMsgHdr(nsIMsgDBHdr *destHdr, nsIMsgDBHdr *srcHdr)
|
||||||
{
|
{
|
||||||
nsXPIDLCString sourceJunkScore;
|
nsXPIDLCString sourceString;
|
||||||
srcHdr->GetStringProperty("junkscore", getter_Copies(sourceJunkScore));
|
srcHdr->GetStringProperty("junkscore", getter_Copies(sourceString));
|
||||||
destHdr->SetStringProperty("junkscore", sourceJunkScore);
|
destHdr->SetStringProperty("junkscore", sourceString);
|
||||||
srcHdr->GetStringProperty("junkscoreorigin", getter_Copies(sourceJunkScore));
|
srcHdr->GetStringProperty("junkscoreorigin", getter_Copies(sourceString));
|
||||||
destHdr->SetStringProperty("junkscoreorigin", sourceJunkScore);
|
destHdr->SetStringProperty("junkscoreorigin", sourceString);
|
||||||
|
srcHdr->GetStringProperty("keywords", getter_Copies(sourceString));
|
||||||
|
destHdr->SetStringProperty("junkscoreorigin", sourceString);
|
||||||
|
|
||||||
nsMsgLabelValue label = 0;
|
nsMsgLabelValue label = 0;
|
||||||
srcHdr->GetLabel(&label);
|
srcHdr->GetLabel(&label);
|
||||||
|
@ -3873,3 +3875,141 @@ NS_IMETHODIMP nsMsgLocalMailFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgLocalMailFolder::AddKeywordToMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
return ChangeKeywordForMessages(aMessages, aKeyword, PR_TRUE /* add */);
|
||||||
|
}
|
||||||
|
nsresult nsMsgLocalMailFolder::ChangeKeywordForMessages(nsISupportsArray *aMessages, const char *aKeyword, PRBool add)
|
||||||
|
{
|
||||||
|
nsresult rv = (add) ? nsMsgDBFolder::AddKeywordToMessages(aMessages, aKeyword)
|
||||||
|
: nsMsgDBFolder::RemoveKeywordFromMessages(aMessages, aKeyword);
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
{
|
||||||
|
rv = GetDatabase(nsnull);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
// this will fail if the folder is locked.
|
||||||
|
rv = mDatabase->StartBatch();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsIOFileStream *fileStream;
|
||||||
|
rv = mDatabase->GetFolderStream(&fileStream);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
PRUint32 count;
|
||||||
|
NS_ENSURE_ARG(aMessages);
|
||||||
|
nsresult rv = aMessages->Count(&count);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsXPIDLCString keywords;
|
||||||
|
nsCAutoString keywordToWrite(" ");
|
||||||
|
keywordToWrite.Append(aKeyword);
|
||||||
|
// for each message, we seek to the beginning of the x-mozilla-status header, and
|
||||||
|
// start reading lines, looking for x-mozilla-keys: headers; If we're adding
|
||||||
|
// the keyword and we find
|
||||||
|
// a header with the desired keyword already in it, we don't need to
|
||||||
|
// do anything. Likewise, if removing keyword and we don't find it,
|
||||||
|
// we don't need to do anything. Otherwise, if adding, we need to
|
||||||
|
// see if there's an x-mozilla-keys
|
||||||
|
// header with room for the new keyword. If so, we replace the
|
||||||
|
// corresponding number of spaces with the keyword. If no room,
|
||||||
|
// we can't do anything until the folder is compacted and another
|
||||||
|
// x-mozilla-keys header is added. In that case, we set a property
|
||||||
|
// on the header, which the compaction code will check.
|
||||||
|
|
||||||
|
// don't return out of the for loop - otherwise, we won't call EndBatch();
|
||||||
|
for(PRUint32 i = 0; i < count; i++) // for each message
|
||||||
|
{
|
||||||
|
char lineBuff[500];
|
||||||
|
|
||||||
|
nsCOMPtr<nsIMsgDBHdr> message = do_QueryElementAt(aMessages, i, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
PRUint32 messageOffset;
|
||||||
|
PRUint32 len = 0;
|
||||||
|
nsCAutoString header;
|
||||||
|
nsCAutoString keywords;
|
||||||
|
message->GetMessageOffset(&messageOffset);
|
||||||
|
PRBool done = PR_FALSE;
|
||||||
|
PRUint32 statusOffset = 0;
|
||||||
|
(void)message->GetStatusOffset(&statusOffset);
|
||||||
|
PRUint32 desiredOffset = messageOffset + statusOffset;
|
||||||
|
fileStream->seek(PR_SEEK_SET, desiredOffset);
|
||||||
|
PRBool inKeywordHeader = PR_FALSE;
|
||||||
|
PRBool foundKeyword = PR_FALSE;
|
||||||
|
PRUint32 offsetToAddKeyword = 0;
|
||||||
|
message->GetMessageSize(&len);
|
||||||
|
// loop through
|
||||||
|
while (!done)
|
||||||
|
{
|
||||||
|
lineBuff[0] = '\0';
|
||||||
|
PRInt32 lineStartPos = fileStream->tell();
|
||||||
|
// readLine won't return line termination chars.
|
||||||
|
if (fileStream->readline(lineBuff, sizeof(lineBuff)))
|
||||||
|
{
|
||||||
|
if (EMPTY_MESSAGE_LINE(lineBuff))
|
||||||
|
break; // passed headers; no x-mozilla-keywords header; give up.
|
||||||
|
nsCString keywordHeaders;
|
||||||
|
if (!strncmp(lineBuff, HEADER_X_MOZILLA_KEYWORDS, sizeof(HEADER_X_MOZILLA_KEYWORDS) - 1))
|
||||||
|
{
|
||||||
|
inKeywordHeader = PR_TRUE;
|
||||||
|
keywordHeaders = lineBuff;
|
||||||
|
}
|
||||||
|
else if (inKeywordHeader && (lineBuff[0] == ' ' || lineBuff[0] == '\t'))
|
||||||
|
keywordHeaders = lineBuff;
|
||||||
|
else if (inKeywordHeader)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PRInt32 keywordHdrLength = keywordHeaders.Length();
|
||||||
|
nsACString::const_iterator start, end;
|
||||||
|
nsACString::const_iterator keywordHdrStart;
|
||||||
|
keywordHeaders.BeginReading(keywordHdrStart);
|
||||||
|
// check if we have the keyword
|
||||||
|
if (MsgFindKeyword(nsDependentCString(aKeyword), keywordHeaders, start, end))
|
||||||
|
{
|
||||||
|
foundKeyword = PR_TRUE;
|
||||||
|
if (!add) // if we're removing, remove it, and break;
|
||||||
|
{
|
||||||
|
PRInt32 keywordStartOffset = Distance(keywordHdrStart, start);
|
||||||
|
keywordHeaders.Cut(keywordStartOffset, Distance(start, end));
|
||||||
|
for (PRInt32 i = Distance(start, end); i > 0; i--)
|
||||||
|
keywordHeaders.Append(' ');
|
||||||
|
fileStream->seek(PR_SEEK_SET, lineStartPos);
|
||||||
|
fileStream->write(keywordHeaders.get(), keywordHeaders.Length());
|
||||||
|
}
|
||||||
|
offsetToAddKeyword = 0;
|
||||||
|
// if adding and we already have the keyword, done
|
||||||
|
done = PR_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// argh, we need to check all the lines to see if we already have the
|
||||||
|
// keyword, but if we don't find it, we want to remember the line and
|
||||||
|
// position where we have room to add the keyword.
|
||||||
|
if (add)
|
||||||
|
{
|
||||||
|
nsCAutoString curKeywordHdr(lineBuff);
|
||||||
|
// strip off line ending spaces.
|
||||||
|
curKeywordHdr.Trim(" ", PR_FALSE, PR_TRUE);
|
||||||
|
if (!offsetToAddKeyword && curKeywordHdr.Length() + keywordToWrite.Length() < keywordHdrLength)
|
||||||
|
offsetToAddKeyword = lineStartPos + curKeywordHdr.Length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (add && !foundKeyword)
|
||||||
|
{
|
||||||
|
if (!offsetToAddKeyword)
|
||||||
|
message->SetUint32Property("growKeywords", 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileStream->seek(PR_SEEK_SET, offsetToAddKeyword);
|
||||||
|
fileStream->write(keywordToWrite.get(), keywordToWrite.Length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDatabase->EndBatch();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsMsgLocalMailFolder::RemoveKeywordFromMessages(nsISupportsArray *aMessages, const char *aKeyword)
|
||||||
|
{
|
||||||
|
return ChangeKeywordForMessages(aMessages, aKeyword, PR_FALSE /* remove */);
|
||||||
|
}
|
||||||
|
|
|
@ -123,9 +123,6 @@ public:
|
||||||
NS_DECL_NSIMSGLOCALMAILFOLDER
|
NS_DECL_NSIMSGLOCALMAILFOLDER
|
||||||
NS_DECL_NSIJUNKMAILCLASSIFICATIONLISTENER
|
NS_DECL_NSIJUNKMAILCLASSIFICATIONLISTENER
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
#if 0
|
|
||||||
static nsresult GetRoot(nsIMsgFolder* *result);
|
|
||||||
#endif
|
|
||||||
// nsIRDFResource methods:
|
// nsIRDFResource methods:
|
||||||
NS_IMETHOD Init(const char *aURI);
|
NS_IMETHOD Init(const char *aURI);
|
||||||
|
|
||||||
|
@ -199,7 +196,8 @@ public:
|
||||||
NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
|
NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
|
||||||
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
|
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
|
||||||
PRBool *aAsyncResults);
|
PRBool *aAsyncResults);
|
||||||
|
NS_IMETHOD AddKeywordToMessages(nsISupportsArray *aMessages, const char *aKeyword);
|
||||||
|
NS_IMETHOD RemoveKeywordFromMessages(nsISupportsArray *aMessages, const char *aKeyword);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult CopyFolderAcrossServer(nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener);
|
nsresult CopyFolderAcrossServer(nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener);
|
||||||
|
@ -233,6 +231,7 @@ protected:
|
||||||
virtual nsresult CreateBaseMessageURI(const char *aURI);
|
virtual nsresult CreateBaseMessageURI(const char *aURI);
|
||||||
virtual nsresult SpamFilterClassifyMessage(const char *aURI, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
|
virtual nsresult SpamFilterClassifyMessage(const char *aURI, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
|
||||||
virtual nsresult SpamFilterClassifyMessages(const char **aURIArray, PRUint32 aURICount, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
|
virtual nsresult SpamFilterClassifyMessages(const char **aURIArray, PRUint32 aURICount, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
|
||||||
|
nsresult ChangeKeywordForMessages(nsISupportsArray *aMessages, const char *aKeyword, PRBool add);
|
||||||
protected:
|
protected:
|
||||||
nsLocalMailCopyState *mCopyState; //We only allow one of these at a time
|
nsLocalMailCopyState *mCopyState; //We only allow one of these at a time
|
||||||
const char *mType;
|
const char *mType;
|
||||||
|
|
|
@ -513,6 +513,7 @@ NS_IMETHODIMP nsParseMailMessageState::Clear()
|
||||||
m_envelope_from.length = 0;
|
m_envelope_from.length = 0;
|
||||||
m_envelope_date.length = 0;
|
m_envelope_date.length = 0;
|
||||||
m_priority.length = 0;
|
m_priority.length = 0;
|
||||||
|
m_keywords.length = 0;
|
||||||
m_mdn_dnt.length = 0;
|
m_mdn_dnt.length = 0;
|
||||||
m_return_path.length = 0;
|
m_return_path.length = 0;
|
||||||
m_account_key.length = 0;
|
m_account_key.length = 0;
|
||||||
|
@ -945,6 +946,9 @@ int nsParseMailMessageState::ParseHeaders ()
|
||||||
else if (!nsCRT::strncasecmp("X-Priority", buf, end - buf)
|
else if (!nsCRT::strncasecmp("X-Priority", buf, end - buf)
|
||||||
|| !nsCRT::strncasecmp("Priority", buf, end - buf))
|
|| !nsCRT::strncasecmp("Priority", buf, end - buf))
|
||||||
header = &m_priority;
|
header = &m_priority;
|
||||||
|
else if (!nsCRT::strncasecmp(HEADER_X_MOZILLA_KEYWORDS, buf, end - buf)
|
||||||
|
&& !m_keywords.length)
|
||||||
|
header = &m_keywords;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,6 +1162,7 @@ int nsParseMailMessageState::FinalizeHeaders()
|
||||||
struct message_header *mozstatus;
|
struct message_header *mozstatus;
|
||||||
struct message_header *mozstatus2;
|
struct message_header *mozstatus2;
|
||||||
struct message_header *priority;
|
struct message_header *priority;
|
||||||
|
struct message_header *keywords;
|
||||||
struct message_header *account_key;
|
struct message_header *account_key;
|
||||||
struct message_header *ccList;
|
struct message_header *ccList;
|
||||||
struct message_header *mdn_dnt;
|
struct message_header *mdn_dnt;
|
||||||
|
@ -1193,11 +1198,12 @@ int nsParseMailMessageState::FinalizeHeaders()
|
||||||
references = (m_references.length ? &m_references : 0);
|
references = (m_references.length ? &m_references : 0);
|
||||||
statush = (m_status.length ? &m_status : 0);
|
statush = (m_status.length ? &m_status : 0);
|
||||||
mozstatus = (m_mozstatus.length ? &m_mozstatus : 0);
|
mozstatus = (m_mozstatus.length ? &m_mozstatus : 0);
|
||||||
mozstatus2 = (m_mozstatus2.length ? &m_mozstatus2 : 0);
|
mozstatus2 = (m_mozstatus2.length ? &m_mozstatus2 : 0);
|
||||||
date = (m_date.length ? &m_date :
|
date = (m_date.length ? &m_date :
|
||||||
m_envelope_date.length ? &m_envelope_date :
|
m_envelope_date.length ? &m_envelope_date :
|
||||||
0);
|
0);
|
||||||
priority = (m_priority.length ? &m_priority : 0);
|
priority = (m_priority.length ? &m_priority : 0);
|
||||||
|
keywords = (m_keywords.length ? &m_keywords : 0);
|
||||||
mdn_dnt = (m_mdn_dnt.length ? &m_mdn_dnt : 0);
|
mdn_dnt = (m_mdn_dnt.length ? &m_mdn_dnt : 0);
|
||||||
inReplyTo = (m_in_reply_to.length ? &m_in_reply_to : 0);
|
inReplyTo = (m_in_reply_to.length ? &m_in_reply_to : 0);
|
||||||
replyTo = (m_replyTo.length ? &m_replyTo : 0);
|
replyTo = (m_replyTo.length ? &m_replyTo : 0);
|
||||||
|
@ -1422,6 +1428,8 @@ int nsParseMailMessageState::FinalizeHeaders()
|
||||||
m_newMsgHdr->SetPriorityString(priority->value);
|
m_newMsgHdr->SetPriorityString(priority->value);
|
||||||
else if (priorityFlags == nsMsgPriority::notSet)
|
else if (priorityFlags == nsMsgPriority::notSet)
|
||||||
m_newMsgHdr->SetPriority(nsMsgPriority::none);
|
m_newMsgHdr->SetPriority(nsMsgPriority::none);
|
||||||
|
if (keywords)
|
||||||
|
m_newMsgHdr->SetStringProperty("keywords", keywords->value);
|
||||||
if (content_type)
|
if (content_type)
|
||||||
{
|
{
|
||||||
char *substring = PL_strstr(content_type->value, "charset");
|
char *substring = PL_strstr(content_type->value, "charset");
|
||||||
|
@ -1887,6 +1895,16 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi
|
||||||
filterAction->GetPriority(&filterPriority);
|
filterAction->GetPriority(&filterPriority);
|
||||||
msgHdr->SetPriority(filterPriority);
|
msgHdr->SetPriority(filterPriority);
|
||||||
break;
|
break;
|
||||||
|
case nsMsgFilterAction::AddTag:
|
||||||
|
{
|
||||||
|
nsXPIDLCString keyword;
|
||||||
|
filterAction->GetStrValue(getter_Copies(keyword));
|
||||||
|
nsCOMPtr<nsISupportsArray> messageArray;
|
||||||
|
NS_NewISupportsArray(getter_AddRefs(messageArray));
|
||||||
|
messageArray->AppendElement(msgHdr);
|
||||||
|
m_downloadFolder->AddKeywordToMessages(messageArray, keyword.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
case nsMsgFilterAction::Label:
|
case nsMsgFilterAction::Label:
|
||||||
nsMsgLabelValue filterLabel;
|
nsMsgLabelValue filterLabel;
|
||||||
filterAction->GetLabel(&filterLabel);
|
filterAction->GetLabel(&filterLabel);
|
||||||
|
@ -1966,13 +1984,13 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi
|
||||||
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(msgHdr);
|
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(msgHdr);
|
||||||
messages->AppendElement(iSupports);
|
messages->AppendElement(iSupports);
|
||||||
localFolder->MarkMsgsOnPop3Server(messages, POP3_FETCH_BODY);
|
localFolder->MarkMsgsOnPop3Server(messages, POP3_FETCH_BODY);
|
||||||
// Don't add this header to the DB, we're going to replace it
|
// Don't add this header to the DB, we're going to replace it
|
||||||
// with the full message.
|
// with the full message.
|
||||||
m_msgMovedByFilter = PR_TRUE;
|
m_msgMovedByFilter = PR_TRUE;
|
||||||
msgIsNew = PR_FALSE;
|
msgIsNew = PR_FALSE;
|
||||||
// Don't do anything else in this filter, wait until we
|
// Don't do anything else in this filter, wait until we
|
||||||
// have the full message.
|
// have the full message.
|
||||||
*applyMore = PR_FALSE;
|
*applyMore = PR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -141,6 +141,7 @@ public:
|
||||||
struct message_header m_envelope_date;
|
struct message_header m_envelope_date;
|
||||||
struct message_header m_priority;
|
struct message_header m_priority;
|
||||||
struct message_header m_account_key;
|
struct message_header m_account_key;
|
||||||
|
struct message_header m_keywords;
|
||||||
// Mdn support
|
// Mdn support
|
||||||
struct message_header m_mdn_original_recipient;
|
struct message_header m_mdn_original_recipient;
|
||||||
struct message_header m_return_path;
|
struct message_header m_return_path;
|
||||||
|
|
|
@ -593,6 +593,8 @@ nsPop3Sink::IncorporateBegin(const char* uidlString,
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
rv = WriteLineToMailbox("X-Mozilla-Status2: 00000000" MSG_LINEBREAK);
|
rv = WriteLineToMailbox("X-Mozilla-Status2: 00000000" MSG_LINEBREAK);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
// leave space for 60 bytes worth of keys/tags
|
||||||
|
rv = WriteLineToMailbox(X_MOZILLA_KEYWORDS);
|
||||||
PR_smprintf_free(statusLine);
|
PR_smprintf_free(statusLine);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,5 +114,5 @@
|
||||||
#define HEADER_X_MOZILLA_PART_URL "X-Mozilla-PartURL"
|
#define HEADER_X_MOZILLA_PART_URL "X-Mozilla-PartURL"
|
||||||
#define HEADER_X_MOZILLA_IDENTITY_KEY "X-Identity-Key"
|
#define HEADER_X_MOZILLA_IDENTITY_KEY "X-Identity-Key"
|
||||||
#define HEADER_X_MOZILLA_ACCOUNT_KEY "X-Account-Key"
|
#define HEADER_X_MOZILLA_ACCOUNT_KEY "X-Account-Key"
|
||||||
|
#define HEADER_X_MOZILLA_KEYWORDS "X-Mozilla-Keys"
|
||||||
#endif /* nsMailHeaders_h_ */
|
#endif /* nsMailHeaders_h_ */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче