зеркало из https://github.com/mozilla/gecko-dev.git
fix for #86200. add search to the subscribe dialog (and remove typedown.)
like 4.x, the text area is disabled for IMAP servers. for news servers, when you type we show you the list of newsgroups that contain the substring. r=naving, sr=mscott
This commit is contained in:
Родитель
ac21c4b967
Коммит
5a43b8700a
|
@ -76,5 +76,9 @@ interface nsISubscribableServer : nsISupports {
|
|||
void getChildren(in string path, in nsISupportsArray array);
|
||||
// if path is null, use the root
|
||||
void getFirstChildURI(in string path, out string result);
|
||||
|
||||
// for searching
|
||||
void setSearchValue(in string searchValue);
|
||||
readonly attribute boolean supportsSubscribeSearch;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,18 +5,21 @@ var gServerURI = null;
|
|||
var gSubscribableServer = null;
|
||||
var gStatusBar = null;
|
||||
var gNameField = null;
|
||||
var gNameFieldLabel = null;
|
||||
var gFolderDelimiter = ".";
|
||||
var gStatusFeedback = new nsMsgStatusFeedback;
|
||||
|
||||
var gSubscribeDeck = null;
|
||||
var gSearchView = null;
|
||||
var gSearchOutlinerBoxObject = null;
|
||||
// the rdf service
|
||||
var RDF = '@mozilla.org/rdf/rdf-service;1'
|
||||
RDF = Components.classes[RDF].getService();
|
||||
RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
|
||||
var subscribeDS = RDF.GetDataSource("rdf:subscribe");
|
||||
|
||||
// used for caching the tree children (in typedown)
|
||||
var lastTreeChildrenValue = null;
|
||||
var lastTreeChildren = null;
|
||||
// get the "subscribed" atom
|
||||
var atomService = Components.classes["@mozilla.org/atom-service;1"].getService().QueryInterface(Components.interfaces.nsIAtomService);
|
||||
var gSubscribedAtom = atomService.getAtom("subscribed").QueryInterface(Components.interfaces.nsISupports);
|
||||
|
||||
var gSubscribeBundle;
|
||||
|
||||
|
@ -34,21 +37,17 @@ function Stop()
|
|||
|
||||
function SetServerTypeSpecificTextValues()
|
||||
{
|
||||
if (!gServerURI) return;
|
||||
if (!gServerURI) return;
|
||||
|
||||
var serverType = GetMsgFolderFromUri(gServerURI).server.type;
|
||||
var serverType = GetMsgFolderFromUri(gServerURI).server.type;
|
||||
|
||||
//set the server specific ui elements
|
||||
|
||||
var element = document.getElementById("foldertextlabel");
|
||||
var stringName = "foldertextfor-" + serverType;
|
||||
var stringval = gSubscribeBundle.getString(stringName);
|
||||
element.setAttribute('value',stringval);
|
||||
|
||||
stringName = "foldersheaderfor-" + serverType;
|
||||
stringval = gSubscribeBundle.getString(stringName);
|
||||
element = document.getElementById("foldersheaderlabel");
|
||||
element.setAttribute('label',stringval);
|
||||
// set the server specific ui elements
|
||||
var stringName = "foldersheaderfor-" + serverType;
|
||||
var stringval = gSubscribeBundle.getString(stringName);
|
||||
var element = document.getElementById("foldersheaderlabel");
|
||||
element.setAttribute('label',stringval);
|
||||
element = document.getElementById("nameCol");
|
||||
element.setAttribute('label',stringval);
|
||||
|
||||
//set the delimiter
|
||||
try {
|
||||
|
@ -116,35 +115,36 @@ function SetUpTree(forceToServer)
|
|||
{
|
||||
//dump("SetUpTree()\n");
|
||||
|
||||
// forget the cached tree children
|
||||
lastTreeChildrenValue = null;
|
||||
lastTreeChildren = null;
|
||||
|
||||
gStatusBar = document.getElementById('statusbar-icon');
|
||||
if (!gServerURI) return;
|
||||
|
||||
|
||||
var folder = GetMsgFolderFromUri(gServerURI);
|
||||
var server = folder.server;
|
||||
|
||||
try {
|
||||
gSubscribableServer = server.QueryInterface(Components.interfaces.nsISubscribableServer);
|
||||
gSubscribeTree.setAttribute('ref',null);
|
||||
gSubscribableServer = server.QueryInterface(Components.interfaces.nsISubscribableServer);
|
||||
gSubscribeTree.setAttribute('ref',null);
|
||||
|
||||
// clear out the text field when switching server
|
||||
gNameField.setAttribute('value',"");
|
||||
// enable (or disable) the search related UI
|
||||
EnableSearchUI();
|
||||
|
||||
gSubscribeTree.database.RemoveDataSource(subscribeDS);
|
||||
gSubscribableServer.subscribeListener = MySubscribeListener;
|
||||
// clear out the text field when switching server
|
||||
gNameField.setAttribute('value',"");
|
||||
|
||||
gStatusFeedback.showProgress(0);
|
||||
gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
|
||||
gStatusBar.setAttribute("mode","undetermined");
|
||||
// since there is no text, switch to the non-search view...
|
||||
SwitchToNormalView();
|
||||
|
||||
gSubscribableServer.startPopulating(msgWindow, forceToServer);
|
||||
gSubscribeTree.database.RemoveDataSource(subscribeDS);
|
||||
gSubscribableServer.subscribeListener = MySubscribeListener;
|
||||
|
||||
gStatusFeedback.showProgress(0);
|
||||
gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
|
||||
gStatusBar.setAttribute("mode","undetermined");
|
||||
|
||||
gSubscribableServer.startPopulating(msgWindow, forceToServer);
|
||||
}
|
||||
catch (ex) {
|
||||
//dump("failed to populate subscribe ds: " + ex + "\n");
|
||||
//dump("failed to populate subscribe ds: " + ex + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,19 +159,34 @@ function SubscribeOnUnload()
|
|||
}
|
||||
}
|
||||
|
||||
function EnableSearchUI()
|
||||
{
|
||||
if (gSubscribableServer.supportsSubscribeSearch) {
|
||||
gNameField.removeAttribute('disabled');
|
||||
gNameFieldLabel.removeAttribute('disabled');
|
||||
}
|
||||
else {
|
||||
gNameField.setAttribute('disabled',true);
|
||||
gNameFieldLabel.setAttribute('disabled',true);
|
||||
}
|
||||
}
|
||||
|
||||
function SubscribeOnLoad()
|
||||
{
|
||||
//dump("SubscribeOnLoad()\n");
|
||||
//dump("SubscribeOnLoad()\n");
|
||||
gSubscribeBundle = document.getElementById("bundle_subscribe");
|
||||
|
||||
gSubscribeTree = document.getElementById('subscribetree');
|
||||
gNameField = document.getElementById('namefield');
|
||||
gSubscribeTree = document.getElementById('subscribetree');
|
||||
gSearchOutlinerBoxObject = document.getElementById("searchOutliner").boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);
|
||||
gNameField = document.getElementById('namefield');
|
||||
gNameFieldLabel = document.getElementById('namefieldlabel');
|
||||
gSubscribeDeck = document.getElementById("subscribedeck");
|
||||
|
||||
msgWindow = Components.classes[msgWindowContractID].createInstance(Components.interfaces.nsIMsgWindow);
|
||||
msgWindow.statusFeedback = gStatusFeedback;
|
||||
msgWindow.SetDOMWindow(window);
|
||||
msgWindow = Components.classes[msgWindowContractID].createInstance(Components.interfaces.nsIMsgWindow);
|
||||
msgWindow.statusFeedback = gStatusFeedback;
|
||||
msgWindow.SetDOMWindow(window);
|
||||
|
||||
doSetOKCancel(subscribeOK,subscribeCancel);
|
||||
doSetOKCancel(subscribeOK,subscribeCancel);
|
||||
|
||||
// look in arguments[0] for parameters
|
||||
if (window.arguments && window.arguments[0]) {
|
||||
|
@ -189,6 +204,8 @@ function SubscribeOnLoad()
|
|||
//dump("folder.server="+folder.server+"\n");
|
||||
try {
|
||||
gSubscribableServer = folder.server.QueryInterface(Components.interfaces.nsISubscribableServer);
|
||||
// enable (or disable) the search related UI
|
||||
EnableSearchUI();
|
||||
gServerURI = folder.server.serverURI;
|
||||
}
|
||||
catch (ex) {
|
||||
|
@ -236,28 +253,26 @@ function subscribeOK()
|
|||
|
||||
function subscribeCancel()
|
||||
{
|
||||
//dump("in subscribeCancel()\n");
|
||||
Stop();
|
||||
if (gSubscribableServer) {
|
||||
gSubscribableServer.subscribeCleanup();
|
||||
}
|
||||
return true;
|
||||
Stop();
|
||||
if (gSubscribableServer) {
|
||||
gSubscribableServer.subscribeCleanup();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function SetState(name,state)
|
||||
{
|
||||
//dump("SetState(" + name + "," + state + ")\n");
|
||||
|
||||
var changed = gSubscribableServer.setState(name, state);
|
||||
if (changed) {
|
||||
StateChanged(name,state);
|
||||
}
|
||||
var changed = gSubscribableServer.setState(name, state);
|
||||
if (changed) {
|
||||
StateChanged(name,state);
|
||||
}
|
||||
}
|
||||
|
||||
function changeTableRecord(server, name, state) {
|
||||
this.server = server;
|
||||
this.name = name;
|
||||
this.state = state;
|
||||
function changeTableRecord(server, name, state)
|
||||
{
|
||||
this.server = server;
|
||||
this.name = name;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
function StateChanged(name,state)
|
||||
|
@ -278,35 +293,112 @@ function StateChanged(name,state)
|
|||
}
|
||||
}
|
||||
|
||||
function InSearchMode()
|
||||
{
|
||||
// search is the second card in the deck
|
||||
return (gSubscribeDeck.getAttribute("index") == "1");
|
||||
}
|
||||
|
||||
function SearchOnClick(event)
|
||||
{
|
||||
var t = event.originalTarget;
|
||||
|
||||
if (t.localName == "outlinerbody") {
|
||||
var row = new Object;
|
||||
var colID = new Object;
|
||||
var childElt = new Object;
|
||||
|
||||
gSearchOutlinerBoxObject.getCellAt(event.clientX, event.clientY, row, colID, childElt);
|
||||
|
||||
// if they are clicking on empty rows, drop the event
|
||||
if (row.value + 1 > gSearchView.rowCount) return;
|
||||
|
||||
if (colID.value == "subscribedCol") {
|
||||
if (event.detail != 2) {
|
||||
// single clicked on the check box
|
||||
// (in the "subscribedCol" column) reverse state
|
||||
// if double click, do nothing
|
||||
ReverseStateFromRow(row.value);
|
||||
}
|
||||
}
|
||||
else if (event.detail == 2) {
|
||||
// double clicked on a row, reverse state
|
||||
ReverseStateFromRow(row.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ReverseStateFromRow(row)
|
||||
{
|
||||
// to determine if the row is subscribed or not,
|
||||
// we get the properties for the "subscribedCol" cell in the row
|
||||
// and look for the "subscribed" property
|
||||
// if the "subscribed" atom is in the list of properties
|
||||
// we are subscribed
|
||||
var properties = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
|
||||
gSearchView.getCellProperties(row, "subscribedCol", properties);
|
||||
|
||||
var isSubscribed = (properties.GetIndexOf(gSubscribedAtom) != -1);
|
||||
|
||||
var name = gSearchView.getCellText(row,"nameCol");
|
||||
// we need to escape the name because
|
||||
// some news servers have newsgroups with non ASCII names
|
||||
// we need to escape those name before calling SetState()
|
||||
SetState(escape(name), !isSubscribed);
|
||||
}
|
||||
|
||||
function SetSubscribeState(state)
|
||||
{
|
||||
try {
|
||||
var groupList = gSubscribeTree.selectedItems;
|
||||
for (var i=0;i<groupList.length;i++) {
|
||||
var group = groupList[i];
|
||||
var name = group.getAttribute('name');
|
||||
SetState(name,state);
|
||||
}
|
||||
if (InSearchMode()) {
|
||||
// if we are in "search" mode, we need to iterate over the
|
||||
// outliner selection, and set the state for all elements
|
||||
// in the selection
|
||||
var outlinerSelection = gSearchView.selection;
|
||||
for (var i=0;i<outlinerSelection.getRangeCount();i++) {
|
||||
var start = new Object;
|
||||
var end = new Object;
|
||||
outlinerSelection.getRangeAt(i,start,end);
|
||||
for (var k=start.value;k<=end.value;k++) {
|
||||
var name = gSearchView.getCellText(k,"nameCol");
|
||||
// we need to escape the name because
|
||||
// some news servers have newsgroups with non ASCII names
|
||||
// we need to escape those name before calling SetState()
|
||||
SetState(escape(name),state);
|
||||
}
|
||||
}
|
||||
// force a repaint of the outliner since states have changed
|
||||
InvalidateSearchOutliner();
|
||||
}
|
||||
else {
|
||||
// we are in the "normal" mode
|
||||
var groupList = gSubscribeTree.selectedItems;
|
||||
for (var i=0;i<groupList.length;i++) {
|
||||
var group = groupList[i];
|
||||
var name = group.getAttribute('name');
|
||||
SetState(name,state);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
//dump("SetSubscribedState failed: " + ex + "\n");
|
||||
//dump("SetSubscribedState failed: " + ex + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
function ReverseStateFromNode(node)
|
||||
{
|
||||
var state;
|
||||
var state;
|
||||
|
||||
if (node.getAttribute('Subscribed') == "true") {
|
||||
state = false;
|
||||
}
|
||||
else {
|
||||
state = true;
|
||||
}
|
||||
|
||||
var uri = node.getAttribute('id');
|
||||
var name = node.getAttribute('name');
|
||||
SetState(name, state);
|
||||
if (node.getAttribute('Subscribed') == "true") {
|
||||
state = false;
|
||||
}
|
||||
else {
|
||||
state = true;
|
||||
}
|
||||
|
||||
var uri = node.getAttribute('id');
|
||||
var name = node.getAttribute('name');
|
||||
SetState(name, state);
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,10 +432,6 @@ function SubscribeOnClick(event)
|
|||
return;
|
||||
}
|
||||
|
||||
var name = t.parentNode.parentNode.getAttribute('name');
|
||||
if (name && (name.length > 0)) {
|
||||
gNameField.setAttribute('value',name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,144 +442,34 @@ function Refresh()
|
|||
SetUpTree(true);
|
||||
}
|
||||
|
||||
function trackGroupInTree()
|
||||
function InvalidateSearchOutliner()
|
||||
{
|
||||
var portion = gNameField.value;
|
||||
selectNodeByName( portion );
|
||||
gSearchOutlinerBoxObject.invalidate();
|
||||
}
|
||||
|
||||
|
||||
function selectNodeByName( aMatchString )
|
||||
function SwitchToNormalView()
|
||||
{
|
||||
var lastDot = aMatchString.lastIndexOf(gFolderDelimiter);
|
||||
var nodeValue = lastDot != -1 ? aMatchString.substring(0, lastDot) : aMatchString;
|
||||
|
||||
var chain = aMatchString.split(gFolderDelimiter);
|
||||
var node;
|
||||
if( chain.length == 1 ) {
|
||||
if (lastTreeChildrenValue != "") {
|
||||
node = getTreechildren(gSubscribeTree);
|
||||
if( !node ) return;
|
||||
lastTreeChildrenValue = "";
|
||||
lastTreeChildren = node;
|
||||
//dump("cache miss!\n");
|
||||
}
|
||||
else {
|
||||
node = lastTreeChildren;
|
||||
//dump("cache hit!\n");
|
||||
}
|
||||
// the first card in the deck is the "normal" view
|
||||
gSubscribeDeck.setAttribute("index","0");
|
||||
}
|
||||
|
||||
function SwitchToSearchView()
|
||||
{
|
||||
// the second card in the deck is the "search" view
|
||||
gSubscribeDeck.setAttribute("index","1");
|
||||
}
|
||||
|
||||
function Search()
|
||||
{
|
||||
var searchValue = gNameField.value;
|
||||
if (searchValue.length && gSubscribableServer.supportsSubscribeSearch) {
|
||||
SwitchToSearchView();
|
||||
gSubscribableServer.setSearchValue(searchValue);
|
||||
|
||||
gSearchView = gSubscribableServer.QueryInterface(Components.interfaces.nsIOutlinerView);
|
||||
gSearchOutlinerBoxObject.view = gSearchView;
|
||||
}
|
||||
else {
|
||||
// if we can, use the cached tree children
|
||||
if (nodeValue != lastTreeChildrenValue) {
|
||||
try {
|
||||
node = gSubscribeTree.getElementsByAttribute("name",nodeValue)[0];
|
||||
}
|
||||
catch (ex) {
|
||||
// this can happen if you do "spoon.foo" and there is no "spoon"
|
||||
return;
|
||||
}
|
||||
// expand the node, if we need to
|
||||
if( node.getAttribute("container") == "true" &&
|
||||
node.getAttribute("open") != "true" ) {
|
||||
node.setAttribute("open","true");
|
||||
}
|
||||
node = getTreechildren(node);
|
||||
|
||||
lastTreeChildren = node;
|
||||
lastTreeChildrenValue = nodeValue;
|
||||
//dump("cache miss!\n");
|
||||
}
|
||||
else {
|
||||
//dump("cache hit!\n");
|
||||
node = lastTreeChildren;
|
||||
}
|
||||
}
|
||||
|
||||
// find the match, using a binary search.
|
||||
var totalItems = node.childNodes.length;
|
||||
if (totalItems == 0) return;
|
||||
var lastLow = 0;
|
||||
var lastHigh = totalItems;
|
||||
while (true) {
|
||||
var i = Math.floor((lastHigh + lastLow) / 2);
|
||||
//dump(i+","+lastLow+","+lastHigh+"\n");
|
||||
var currItem = node.childNodes[i];
|
||||
var currValue = (currItem.getAttribute("name")).substring(0,aMatchString.length);
|
||||
//dump(currValue+" vs "+aMatchString+"\n");
|
||||
if (currValue > aMatchString) {
|
||||
if (lastHigh == i) return;
|
||||
lastHigh = i;
|
||||
}
|
||||
else if (currValue < aMatchString) {
|
||||
if (lastLow == i) return;
|
||||
lastLow = i;
|
||||
}
|
||||
else {
|
||||
SelectFirstMatch(lastLow, i, node.childNodes, aMatchString);
|
||||
return;
|
||||
}
|
||||
SwitchToNormalView();
|
||||
}
|
||||
}
|
||||
|
||||
function SelectFirstMatch(startNode, endNode, nodes, matchStr)
|
||||
{
|
||||
// this code is to make sure we select the alphabetically first match
|
||||
// not just any match (see bug #60242)
|
||||
|
||||
// find the match, using a binary search.
|
||||
|
||||
var lastMatch = nodes[endNode];
|
||||
var totalItems = endNode - startNode;
|
||||
if (totalItems == 0) {
|
||||
gSubscribeTree.selectItem( lastMatch );
|
||||
gSubscribeTree.ensureElementIsVisible( lastMatch );
|
||||
return;
|
||||
}
|
||||
|
||||
var lastLow = startNode;
|
||||
var lastHigh = endNode;
|
||||
while (true) {
|
||||
var i = Math.floor((lastHigh + lastLow) / 2);
|
||||
//dump(i+","+lastLow+","+lastHigh+"\n");
|
||||
var currItem = nodes[i];
|
||||
var currValue = (currItem.getAttribute("name")).substring(0,matchStr.length);
|
||||
//dump(currValue+" vs "+matchStr+"\n");
|
||||
if (currValue > matchStr) {
|
||||
gSubscribeTree.selectItem( lastMatch );
|
||||
gSubscribeTree.ensureElementIsVisible( lastMatch );
|
||||
return;
|
||||
}
|
||||
else if (currValue < matchStr) {
|
||||
if (lastLow == i) {
|
||||
gSubscribeTree.selectItem( lastMatch );
|
||||
gSubscribeTree.ensureElementIsVisible( lastMatch );
|
||||
return;
|
||||
}
|
||||
lastLow = i;
|
||||
}
|
||||
else {
|
||||
lastMatch = currItem;
|
||||
if (lastHigh == i) {
|
||||
gSubscribeTree.selectItem( lastMatch );
|
||||
gSubscribeTree.ensureElementIsVisible( lastMatch );
|
||||
return;
|
||||
}
|
||||
lastHigh = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTreechildren( aTreeNode )
|
||||
{
|
||||
if( aTreeNode.childNodes )
|
||||
{
|
||||
for( var i = 0; i < aTreeNode.childNodes.length; i++ )
|
||||
{
|
||||
if( aTreeNode.childNodes[i].localName.toLowerCase() == "treechildren" )
|
||||
return aTreeNode.childNodes[i];
|
||||
}
|
||||
return aTreeNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ Rights Reserved.
|
|||
</menulist>
|
||||
</row>
|
||||
<row>
|
||||
<text class="label" id="foldertextlabel" value="..." for="namefield"/>
|
||||
<textbox id="namefield" flex="1" oninput="trackGroupInTree();"/>
|
||||
<text class="label" id="namefieldlabel" value="&namefield.label;" for="namefield"/>
|
||||
<textbox id="namefield" flex="1" oninput="Search();"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
@ -93,6 +93,8 @@ Rights Reserved.
|
|||
<spring/>
|
||||
</row>
|
||||
<row flex="1">
|
||||
<deck id="subscribedeck" index="0">
|
||||
<box id="normalview">
|
||||
<tree class="inset" flex="1"
|
||||
id="subscribetree"
|
||||
datasources="rdf:null"
|
||||
|
@ -127,6 +129,18 @@ Rights Reserved.
|
|||
</treerow>
|
||||
</treehead>
|
||||
</tree>
|
||||
</box>
|
||||
<box id="searchview">
|
||||
<outliner id="searchOutliner" flex="1" onclick="SearchOnClick(event);">
|
||||
<outlinercol id="nameCol" label="..." class="outlinercol-header outlinercol-inset-header" flex="5" width="0" persist="hidden width" />
|
||||
<splitter class="tree-splitter" />
|
||||
<outlinercol id="subscribedCol" fixed="true" persist="hidden" class="outlinercol-header outlinercol-image outlinercol-inset-header subscribedColumnHeader" label="&subscribedHeader.label;" />
|
||||
<splitter class="tree-splitter" />
|
||||
<outlinercol id="messagesCol" label="&messagesHeader.label;" class="outlinercol-header outlinercol-inset-header" flex="1" width="0" persist="hidden width" />
|
||||
<outlinerbody id="searchOutlinerBody" flex="1" />
|
||||
</outliner>
|
||||
</box>
|
||||
</deck>
|
||||
<box orient="vertical">
|
||||
<button id="subscribe" class="dialog" label="&subscribeButton.label;" oncommand="SetSubscribeState(true)"/>
|
||||
<button id="unsubscribe" class="dialog" label="&unsubscribeButton.label;" oncommand="SetSubscribeState(false)"/>
|
||||
|
|
|
@ -26,3 +26,4 @@ Rights Reserved.
|
|||
<!ENTITY server.label "Server:">
|
||||
<!ENTITY subscribedHeader.label "Subscribe">
|
||||
<!ENTITY messagesHeader.label "Messages">
|
||||
<!ENTITY namefield.label "Show items that contain:">
|
||||
|
|
|
@ -18,10 +18,7 @@
|
|||
# Contributor(s):
|
||||
# Seth Spitzer <sspitzer@netscape.com>
|
||||
#
|
||||
|
||||
foldertextfor-nntp=Newsgroup:
|
||||
foldersheaderfor-nntp=Newsgroup name
|
||||
foldertextfor-imap=Folder:
|
||||
foldersheaderfor-imap=Folder name
|
||||
doneString=Done.
|
||||
pleaseWaitString=Please wait...
|
||||
|
|
|
@ -798,3 +798,14 @@ nsSubscribableServer::CommitSubscribeChanges()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSubscribableServer::SetSearchValue(const char *searchValue)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSubscribableServer::GetSupportsSubscribeSearch(PRBool *retVal)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -3131,3 +3131,15 @@ nsImapIncomingServer::GetFormattedName(const PRUnichar *prettyName, PRUnichar **
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapIncomingServer::SetSearchValue(const char *searchValue)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImapIncomingServer::GetSupportsSubscribeSearch(PRBool *retVal)
|
||||
{
|
||||
*retVal = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@
|
|||
#include "nsMsgUtils.h"
|
||||
|
||||
#define INVALID_VERSION 0
|
||||
#define VALID_VERSION 1
|
||||
#define NEW_NEWS_DIR_NAME "News"
|
||||
#define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root"
|
||||
#define HOSTINFO_FILE_NAME "hostinfo.dat"
|
||||
#define VALID_VERSION 1
|
||||
#define NEW_NEWS_DIR_NAME "News"
|
||||
#define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root"
|
||||
#define HOSTINFO_FILE_NAME "hostinfo.dat"
|
||||
|
||||
#define NEWS_DELIMITER '.'
|
||||
#define NEWS_DELIMITER '.'
|
||||
|
||||
// this platform specific junk is so the newsrc filenames we create
|
||||
// will resemble the migrated newsrc filenames.
|
||||
|
@ -71,6 +71,7 @@ NS_INTERFACE_MAP_BEGIN(nsNntpIncomingServer)
|
|||
NS_INTERFACE_MAP_ENTRY(nsINntpIncomingServer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUrlListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISubscribableServer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutlinerView)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsMsgIncomingServer)
|
||||
|
||||
nsNntpIncomingServer::nsNntpIncomingServer() : nsMsgLineBuffer(nsnull, PR_FALSE)
|
||||
|
@ -94,12 +95,16 @@ nsNntpIncomingServer::nsNntpIncomingServer() : nsMsgLineBuffer(nsnull, PR_FALSE)
|
|||
mPostingAllowed = PR_FALSE;
|
||||
mLastUpdatedTime = 0;
|
||||
|
||||
// these atoms are used for subscribe search
|
||||
mSubscribedAtom = getter_AddRefs(NS_NewAtom("subscribed"));
|
||||
mNntpAtom = getter_AddRefs(NS_NewAtom("nntp"));
|
||||
|
||||
SetupNewsrcSaveTimer();
|
||||
}
|
||||
|
||||
nsNntpIncomingServer::~nsNntpIncomingServer()
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv;
|
||||
|
||||
if (mGroupsEnumerator) {
|
||||
delete mGroupsEnumerator;
|
||||
|
@ -118,10 +123,10 @@ nsNntpIncomingServer::~nsNntpIncomingServer()
|
|||
}
|
||||
|
||||
rv = ClearInner();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
|
||||
|
||||
rv = CloseCachedConnections();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "CloseCachedConnections failed");
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "CloseCachedConnections failed");
|
||||
}
|
||||
|
||||
NS_IMPL_SERVERPREF_BOOL(nsNntpIncomingServer, NotifyOn, "notify.on");
|
||||
|
@ -132,53 +137,52 @@ NS_IMPL_SERVERPREF_INT(nsNntpIncomingServer, MaxArticles, "max_articles");
|
|||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetNewsrcFilePath(nsIFileSpec **aNewsrcFilePath)
|
||||
{
|
||||
nsresult rv;
|
||||
rv = GetFileValue("newsrc.file", aNewsrcFilePath);
|
||||
if (NS_SUCCEEDED(rv) && *aNewsrcFilePath) return rv;
|
||||
nsresult rv;
|
||||
rv = GetFileValue("newsrc.file", aNewsrcFilePath);
|
||||
if (NS_SUCCEEDED(rv) && *aNewsrcFilePath) return rv;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> path;
|
||||
nsCOMPtr<nsIFileSpec> path;
|
||||
|
||||
rv = GetNewsrcRootPath(getter_AddRefs(path));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = GetNewsrcRootPath(getter_AddRefs(path));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsXPIDLCString hostname;
|
||||
rv = GetHostName(getter_Copies(hostname));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsXPIDLCString hostname;
|
||||
rv = GetHostName(getter_Copies(hostname));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// set the leaf name to "dummy", and then call MakeUnique with a suggested leaf name
|
||||
rv = path->AppendRelativeUnixPath("dummy");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCAutoString newsrcFileName(NEWSRC_FILE_PREFIX);
|
||||
newsrcFileName.Append(hostname);
|
||||
newsrcFileName.Append(NEWSRC_FILE_SUFFIX);
|
||||
rv = path->MakeUniqueWithSuggestedName((const char *)newsrcFileName);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
// set the leaf name to "dummy", and then call MakeUnique with a suggested leaf name
|
||||
rv = path->AppendRelativeUnixPath("dummy");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCAutoString newsrcFileName(NEWSRC_FILE_PREFIX);
|
||||
newsrcFileName.Append(hostname);
|
||||
newsrcFileName.Append(NEWSRC_FILE_SUFFIX);
|
||||
rv = path->MakeUniqueWithSuggestedName((const char *)newsrcFileName);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = SetNewsrcFilePath(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = SetNewsrcFilePath(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*aNewsrcFilePath = path;
|
||||
NS_ADDREF(*aNewsrcFilePath);
|
||||
*aNewsrcFilePath = path;
|
||||
NS_ADDREF(*aNewsrcFilePath);
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetNewsrcFilePath(nsIFileSpec *spec)
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv;
|
||||
if (!spec) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PRBool exists;
|
||||
|
||||
rv = spec->Exists(&exists);
|
||||
if (!exists) {
|
||||
rv = spec->Touch();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PRBool exists;
|
||||
|
||||
rv = spec->Exists(&exists);
|
||||
if (!exists) {
|
||||
rv = spec->Touch();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return SetFileValue("newsrc.file", spec);
|
||||
}
|
||||
|
||||
|
@ -470,19 +474,19 @@ nsresult
|
|||
nsNntpIncomingServer::CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
|
||||
nsIMsgWindow *aMsgWindow)
|
||||
{
|
||||
// create a new connection and add it to the connection cache
|
||||
// we may need to flag the protocol connection as busy so we don't get
|
||||
// a race
|
||||
// condition where someone else goes through this code
|
||||
nsNNTPProtocol * protocolInstance = new nsNNTPProtocol(url, aMsgWindow);
|
||||
// create a new connection and add it to the connection cache
|
||||
// we may need to flag the protocol connection as busy so we don't get
|
||||
// a race
|
||||
// condition where someone else goes through this code
|
||||
nsNNTPProtocol * protocolInstance = new nsNNTPProtocol(url, aMsgWindow);
|
||||
if (!protocolInstance)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = protocolInstance->QueryInterface(NS_GET_IID(nsINNTPProtocol), (void **) aNntpConnection);
|
||||
// take the protocol instance and add it to the connectionCache
|
||||
if (NS_SUCCEEDED(rv) && *aNntpConnection)
|
||||
m_connectionCache->AppendElement(*aNntpConnection);
|
||||
return rv;
|
||||
// take the protocol instance and add it to the connectionCache
|
||||
if (NS_SUCCEEDED(rv) && *aNntpConnection)
|
||||
m_connectionCache->AppendElement(*aNntpConnection);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* By default, allow the user to open at most this many connections to one news host */
|
||||
|
@ -492,9 +496,9 @@ NS_IMETHODIMP
|
|||
nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
|
||||
nsINNTPProtocol ** aNntpConnection)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsINNTPProtocol> connection;
|
||||
nsCOMPtr<nsINNTPProtocol> freeConnection;
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsINNTPProtocol> connection;
|
||||
nsCOMPtr<nsINNTPProtocol> freeConnection;
|
||||
PRBool isBusy = PR_TRUE;
|
||||
|
||||
|
||||
|
@ -512,8 +516,8 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
|
|||
}
|
||||
|
||||
*aNntpConnection = nsnull;
|
||||
// iterate through the connection cache for a connection that can handle this url.
|
||||
PRUint32 cnt;
|
||||
// iterate through the connection cache for a connection that can handle this url.
|
||||
PRUint32 cnt;
|
||||
nsCOMPtr<nsISupports> aSupport;
|
||||
|
||||
rv = m_connectionCache->Count(&cnt);
|
||||
|
@ -522,11 +526,11 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
|
|||
printf("XXX there are %d nntp connections in the conn cache.\n", (int)cnt);
|
||||
#endif
|
||||
for (PRUint32 i = 0; i < cnt && isBusy; i++)
|
||||
{
|
||||
{
|
||||
aSupport = getter_AddRefs(m_connectionCache->ElementAt(i));
|
||||
connection = do_QueryInterface(aSupport);
|
||||
if (connection)
|
||||
rv = connection->GetIsBusy(&isBusy);
|
||||
if (connection)
|
||||
rv = connection->GetIsBusy(&isBusy);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
connection = nsnull;
|
||||
|
@ -536,22 +540,22 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
|
|||
{
|
||||
freeConnection = connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ConnectionTimeOut(freeConnection))
|
||||
freeConnection = nsnull;
|
||||
|
||||
// if we got here and we have a connection, then we should return it!
|
||||
if (!isBusy && freeConnection)
|
||||
{
|
||||
*aNntpConnection = freeConnection;
|
||||
// if we got here and we have a connection, then we should return it!
|
||||
if (!isBusy && freeConnection)
|
||||
{
|
||||
*aNntpConnection = freeConnection;
|
||||
freeConnection->SetIsCachedConnection(PR_TRUE);
|
||||
NS_IF_ADDREF(*aNntpConnection);
|
||||
}
|
||||
else // have no queueing mechanism - just create the protocol instance.
|
||||
{
|
||||
rv = CreateProtocolInstance(aNntpConnection, aUri, aMsgWindow);
|
||||
}
|
||||
NS_IF_ADDREF(*aNntpConnection);
|
||||
}
|
||||
else // have no queueing mechanism - just create the protocol instance.
|
||||
{
|
||||
rv = CreateProtocolInstance(aNntpConnection, aUri, aMsgWindow);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -569,14 +573,14 @@ NS_IMETHODIMP nsNntpIncomingServer::RemoveConnection(nsINNTPProtocol *aNntpConne
|
|||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::PerformExpand(nsIMsgWindow *aMsgWindow)
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
|
||||
nsCOMPtr<nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = nntpService->UpdateCounts(this, aMsgWindow);
|
||||
rv = nntpService->UpdateCounts(this, aMsgWindow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// remove this when news supports filters
|
||||
|
@ -589,7 +593,7 @@ nsNntpIncomingServer::GetFilterList(nsIMsgFilterList **aResult)
|
|||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetNumGroupsNeedingCounts(PRInt32 *aNumGroupsNeedingCounts)
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIEnumerator> subFolders;
|
||||
nsCOMPtr<nsIFolder> rootFolder;
|
||||
|
@ -597,23 +601,23 @@ nsNntpIncomingServer::GetNumGroupsNeedingCounts(PRInt32 *aNumGroupsNeedingCounts
|
|||
rv = GetRootFolder(getter_AddRefs(rootFolder));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRBool hasSubFolders = PR_FALSE;
|
||||
rv = rootFolder->GetHasSubFolders(&hasSubFolders);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!hasSubFolders) {
|
||||
*aNumGroupsNeedingCounts = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = rootFolder->GetSubFolders(getter_AddRefs(subFolders));
|
||||
PRBool hasSubFolders = PR_FALSE;
|
||||
rv = rootFolder->GetHasSubFolders(&hasSubFolders);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mGroupsEnumerator) {
|
||||
delete mGroupsEnumerator;
|
||||
mGroupsEnumerator = nsnull;
|
||||
}
|
||||
mGroupsEnumerator = new nsAdapterEnumerator(subFolders);
|
||||
if (!hasSubFolders) {
|
||||
*aNumGroupsNeedingCounts = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = rootFolder->GetSubFolders(getter_AddRefs(subFolders));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mGroupsEnumerator) {
|
||||
delete mGroupsEnumerator;
|
||||
mGroupsEnumerator = nsnull;
|
||||
}
|
||||
mGroupsEnumerator = new nsAdapterEnumerator(subFolders);
|
||||
if (mGroupsEnumerator == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PRUint32 count = 0;
|
||||
|
@ -718,7 +722,7 @@ checkIfSubscribedFunction(nsCString &aElement, void *aData)
|
|||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::ContainsNewsgroup(const char *name, PRBool *containsGroup)
|
||||
{
|
||||
NS_ASSERTION(name && PL_strlen(name),"no name");
|
||||
NS_ASSERTION(name && nsCRT::strlen(name),"no name");
|
||||
if (!name || !containsGroup) return NS_ERROR_NULL_POINTER;
|
||||
if (!nsCRT::strlen(name)) return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -731,7 +735,7 @@ nsNntpIncomingServer::SubscribeToNewsgroup(const char *name)
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(name && PL_strlen(name),"no name");
|
||||
NS_ASSERTION(name && nsCRT::strlen(name),"no name");
|
||||
if (!name) return NS_ERROR_NULL_POINTER;
|
||||
if (!nsCRT::strlen(name)) return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -1045,32 +1049,33 @@ nsNntpIncomingServer::SetDelimiter(char aDelimiter)
|
|||
{
|
||||
nsresult rv = EnsureInner();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
return mInner->SetDelimiter(aDelimiter);
|
||||
return mInner->SetDelimiter(aDelimiter);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetAsSubscribed(const char *path)
|
||||
{
|
||||
mTempSubscribed.AppendCString(nsCAutoString(path));
|
||||
|
||||
nsresult rv = EnsureInner();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
return mInner->SetAsSubscribed(path);
|
||||
return mInner->SetAsSubscribed(path);
|
||||
}
|
||||
|
||||
PRBool
|
||||
setAsSubscribedFunction(nsCString &aElement, void *aData)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsresult rv = NS_OK;
|
||||
nsNntpIncomingServer *server;
|
||||
server = (nsNntpIncomingServer *)aData;
|
||||
NS_ASSERTION(server, "no server");
|
||||
if (!server) {
|
||||
// todo is this correct?
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv = server->SetAsSubscribed((const char *)aElement);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),"SetAsSubscribed failed");
|
||||
return PR_TRUE;
|
||||
rv = server->SetAsSubscribed((const char *)aElement);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),"SetAsSubscribed failed");
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1078,6 +1083,7 @@ nsNntpIncomingServer::UpdateSubscribed()
|
|||
{
|
||||
nsresult rv = EnsureInner();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
mTempSubscribed.Clear();
|
||||
mSubscribedNewsgroups.EnumerateForwards((nsCStringArrayEnumFunc)setAsSubscribedFunction, (void *)this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1088,20 +1094,20 @@ nsNntpIncomingServer::AddTo(const char *aName, PRBool addAsSubscribed, PRBool ch
|
|||
nsresult rv = EnsureInner();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsAutoString newsgroupName;
|
||||
newsgroupName.AssignWithConversion(aName);
|
||||
nsAutoString newsgroupName;
|
||||
newsgroupName.AssignWithConversion(aName);
|
||||
|
||||
char *escapedName = nsEscape(NS_ConvertUCS2toUTF8(newsgroupName.get()).get(), url_Path);
|
||||
if (!escapedName) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = AddGroupOnServer(escapedName);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddGroupOnServer(escapedName);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = mInner->AddTo(escapedName,addAsSubscribed,changeIfExists);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
PR_FREEIF(escapedName);
|
||||
return rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1263,7 +1269,15 @@ nsNntpIncomingServer::SetState(const char *path, PRBool state, PRBool *stateChan
|
|||
{
|
||||
nsresult rv = EnsureInner();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
return mInner->SetState(path, state, stateChanged);
|
||||
|
||||
rv = mInner->SetState(path, state, stateChanged);
|
||||
if (*stateChanged) {
|
||||
if (state)
|
||||
mTempSubscribed.AppendCString(nsCAutoString(path));
|
||||
else
|
||||
mTempSubscribed.RemoveCString(nsCAutoString(path));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1566,6 +1580,252 @@ nsNntpIncomingServer::GetOfflineSupportLevel(PRInt32 *aSupportLevel)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
buildSubscribeSearchResult(nsCString &aElement, void *aData)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsNntpIncomingServer *server;
|
||||
server = (nsNntpIncomingServer *)aData;
|
||||
NS_ASSERTION(server, "no server");
|
||||
if (!server) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv = server->AppendIfSearchMatch(aElement.get());
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),"AddSubscribeSearchResult failed");
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNntpIncomingServer::AppendIfSearchMatch(const char *newsgroupName)
|
||||
{
|
||||
// we've converted mSearchValue to lower case
|
||||
// do the same to the newsgroup name before we do our strstr()
|
||||
// this way searches will be case independant
|
||||
nsCAutoString lowerCaseName(newsgroupName);
|
||||
lowerCaseName.ToLowerCase();
|
||||
|
||||
if (PL_strstr(lowerCaseName.get(), mSearchValue.get())) {
|
||||
mSubscribeSearchResult.AppendCString(nsCAutoString(newsgroupName));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetSearchValue(const char *searchValue)
|
||||
{
|
||||
mSearchValue = searchValue;
|
||||
// force the search string to be lower case
|
||||
// so that we can do case insensitive searching
|
||||
mSearchValue.ToLowerCase();
|
||||
|
||||
mSubscribeSearchResult.Clear();
|
||||
mGroupsOnServer.EnumerateForwards((nsCStringArrayEnumFunc)buildSubscribeSearchResult, (void *)this);
|
||||
|
||||
if (mOutliner) mOutliner->Invalidate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetSupportsSubscribeSearch(PRBool *retVal)
|
||||
{
|
||||
*retVal = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetRowCount(PRInt32 *aRowCount)
|
||||
{
|
||||
*aRowCount = mSubscribeSearchResult.Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetSelection(nsIOutlinerSelection * *aSelection)
|
||||
{
|
||||
*aSelection = mOutlinerSelection;
|
||||
NS_IF_ADDREF(*aSelection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetSelection(nsIOutlinerSelection * aSelection)
|
||||
{
|
||||
mOutlinerSelection = aSelection;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetCellProperties(PRInt32 row, const PRUnichar *colID, nsISupportsArray *properties)
|
||||
{
|
||||
if (colID[0] == 's') {
|
||||
// if <name> is in our temporary list of subscribed groups
|
||||
// add the "subscribed" property so the check mark shows up
|
||||
// in the "subscribedCol"
|
||||
nsCString name;
|
||||
mSubscribeSearchResult.CStringAt(row, name);
|
||||
if (mTempSubscribed.IndexOf(name) != -1) {
|
||||
properties->AppendElement(mSubscribedAtom);
|
||||
}
|
||||
}
|
||||
else if (colID[0] == 'n') {
|
||||
// add the "nntp" property to the "nameCol"
|
||||
// so we get the news folder icon in the search view
|
||||
properties->AppendElement(mNntpAtom);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetColumnProperties(const PRUnichar *colID, nsIDOMElement *colElt, nsISupportsArray *properties)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::IsContainer(PRInt32 index, PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::IsContainerOpen(PRInt32 index, PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::IsContainerEmpty(PRInt32 index, PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::IsSorted(PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::CanDropOn(PRInt32 index, PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::CanDropBeforeAfter(PRInt32 index, PRBool before, PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::Drop(PRInt32 row, PRInt32 orientation)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, PRBool *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetLevel(PRInt32 index, PRInt32 *_retval)
|
||||
{
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetCellText(PRInt32 row, const PRUnichar *colID, PRUnichar **_retval)
|
||||
{
|
||||
if (colID[0] == 'n') {
|
||||
nsCString str;
|
||||
mSubscribeSearchResult.CStringAt(row, str);
|
||||
// some servers have newsgroup names that are non ASCII. we store those as escaped
|
||||
// unescape here so the UI is consistent
|
||||
nsresult rv = NS_MsgDecodeUnescapeURLPath(str.get(), _retval);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetOutliner(nsIOutlinerBoxObject *outliner)
|
||||
{
|
||||
mOutliner = outliner;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::ToggleOpenState(PRInt32 index)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::CycleHeader(const PRUnichar *colID, nsIDOMElement *elt)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SelectionChanged()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::CycleCell(PRInt32 row, const PRUnichar *colID)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::IsEditable(PRInt32 row, const PRUnichar *colID, PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::SetCellText(PRInt32 row, const PRUnichar *colID, const PRUnichar *value)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::PerformAction(const PRUnichar *action)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::PerformActionOnCell(const PRUnichar *action, PRInt32 row, const PRUnichar *colID)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNntpIncomingServer::GetDefaultCopiesAndFoldersPrefsToServer(PRBool *aCopiesAndFoldersOnServer)
|
||||
{
|
||||
|
|
|
@ -41,78 +41,97 @@
|
|||
#include "nsITimer.h"
|
||||
#include "nsFileStream.h"
|
||||
|
||||
#include "nsIOutlinerView.h"
|
||||
#include "nsIOutlinerSelection.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
class nsINntpUrl;
|
||||
class nsIMsgMailNewsUrl;
|
||||
|
||||
/* get some implementation from nsMsgIncomingServer */
|
||||
class nsNntpIncomingServer : public nsMsgIncomingServer,
|
||||
public nsINntpIncomingServer,
|
||||
public nsIUrlListener,
|
||||
public nsISubscribableServer,
|
||||
public nsMsgLineBuffer
|
||||
|
||||
public nsIUrlListener,
|
||||
public nsISubscribableServer,
|
||||
public nsMsgLineBuffer,
|
||||
public nsIOutlinerView
|
||||
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSINNTPINCOMINGSERVER
|
||||
NS_DECL_NSIURLLISTENER
|
||||
NS_DECL_NSISUBSCRIBABLESERVER
|
||||
NS_DECL_NSIOUTLINERVIEW
|
||||
|
||||
nsNntpIncomingServer();
|
||||
virtual ~nsNntpIncomingServer();
|
||||
|
||||
NS_IMETHOD GetLocalStoreType(char * *type);
|
||||
NS_IMETHOD CloseCachedConnections();
|
||||
NS_IMETHOD PerformBiff();
|
||||
NS_IMETHOD PerformBiff();
|
||||
NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow);
|
||||
NS_IMETHOD GetFilterList(nsIMsgFilterList **aResult);
|
||||
|
||||
// for nsMsgLineBuffer
|
||||
virtual PRInt32 HandleLine(char *line, PRUint32 line_size);
|
||||
// for nsMsgLineBuffer
|
||||
virtual PRInt32 HandleLine(char *line, PRUint32 line_size);
|
||||
|
||||
// override to clear all passwords associated with server
|
||||
NS_IMETHODIMP ForgetPassword();
|
||||
NS_IMETHOD GetCanSearchMessages(PRBool *canSearchMessages);
|
||||
NS_IMETHOD GetOfflineSupportLevel(PRInt32 *aSupportLevel);
|
||||
NS_IMETHOD GetDefaultCopiesAndFoldersPrefsToServer(PRBool *aCopiesAndFoldersOnServer);
|
||||
nsresult AppendIfSearchMatch(const char *newsgroupName);
|
||||
|
||||
protected:
|
||||
nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
|
||||
nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
|
||||
nsIMsgWindow *window);
|
||||
PRBool ConnectionTimeOut(nsINNTPProtocol* aNntpConnection);
|
||||
nsCOMPtr<nsISupportsArray> m_connectionCache;
|
||||
NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval);
|
||||
nsByteArray mHostInfoInputStream;
|
||||
NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval);
|
||||
nsByteArray mHostInfoInputStream;
|
||||
nsresult SetupNewsrcSaveTimer();
|
||||
static void OnNewsrcSaveTimer(nsITimer *timer, void *voidIncomingServer);
|
||||
|
||||
private:
|
||||
nsCStringArray mSubscribedNewsgroups;
|
||||
nsCStringArray mGroupsOnServer;
|
||||
nsCStringArray mSubscribedNewsgroups;
|
||||
nsCStringArray mGroupsOnServer;
|
||||
nsCStringArray mSubscribeSearchResult;
|
||||
// the list of of subscribed newsgroups within a given
|
||||
// subscribed dialog session.
|
||||
// we need to keep track of them so we know what to show as "checked"
|
||||
// in the search view
|
||||
nsCStringArray mTempSubscribed;
|
||||
nsCOMPtr<nsIAtom> mSubscribedAtom;
|
||||
nsCOMPtr<nsIAtom> mNntpAtom;
|
||||
|
||||
PRBool mHasSeenBeginGroups;
|
||||
nsresult WriteHostInfoFile();
|
||||
nsresult LoadHostInfoFile();
|
||||
nsCString mSearchValue;
|
||||
nsCOMPtr<nsIOutlinerBoxObject> mOutliner;
|
||||
nsCOMPtr<nsIOutlinerSelection> mOutlinerSelection;
|
||||
|
||||
PRBool mHasSeenBeginGroups;
|
||||
nsresult WriteHostInfoFile();
|
||||
nsresult LoadHostInfoFile();
|
||||
nsresult AddGroupOnServer(const char *name);
|
||||
|
||||
PRBool mNewsrcHasChanged;
|
||||
nsAdapterEnumerator *mGroupsEnumerator;
|
||||
PRBool mHostInfoLoaded;
|
||||
PRBool mHostInfoHasChanged;
|
||||
nsCOMPtr <nsIFileSpec> mHostInfoFile;
|
||||
|
||||
PRUint32 mLastGroupDate;
|
||||
PRTime mFirstNewDate;
|
||||
PRInt32 mUniqueId;
|
||||
PRBool mPushAuth;
|
||||
nsAdapterEnumerator *mGroupsEnumerator;
|
||||
PRBool mHostInfoLoaded;
|
||||
PRBool mHostInfoHasChanged;
|
||||
nsCOMPtr <nsIFileSpec> mHostInfoFile;
|
||||
|
||||
PRUint32 mLastGroupDate;
|
||||
PRTime mFirstNewDate;
|
||||
PRInt32 mUniqueId;
|
||||
PRBool mPushAuth;
|
||||
PRUint32 mLastUpdatedTime;
|
||||
PRInt32 mVersion;
|
||||
PRInt32 mVersion;
|
||||
PRBool mPostingAllowed;
|
||||
|
||||
nsCOMPtr<nsITimer> mNewsrcSaveTimer;
|
||||
nsCOMPtr <nsIMsgWindow> mMsgWindow;
|
||||
nsCOMPtr <nsIMsgWindow> mMsgWindow;
|
||||
|
||||
nsCOMPtr <nsISubscribableServer> mInner;
|
||||
nsCOMPtr <nsISubscribableServer> mInner;
|
||||
nsresult EnsureInner();
|
||||
nsresult ClearInner();
|
||||
|
||||
|
|
|
@ -59,3 +59,17 @@
|
|||
#subscribetree {
|
||||
margin: 0px 0px 0px 0px !important;
|
||||
}
|
||||
|
||||
/* for search */
|
||||
|
||||
outlinerbody:-moz-outliner-image(nameCol, nntp) {
|
||||
list-style-image: url("chrome://messenger/skin/folder-newsgroup.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol) {
|
||||
list-style-image: url("chrome://messenger/skin/dot.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
|
||||
list-style-image: url("chrome://messenger/skin/check.gif");
|
||||
}
|
||||
|
|
|
@ -59,3 +59,18 @@
|
|||
#subscribetree {
|
||||
margin: 0px 0px 0px 0px !important;
|
||||
}
|
||||
|
||||
/* for search */
|
||||
|
||||
outlinerbody:-moz-outliner-image(nameCol, nntp) {
|
||||
list-style-image: url("chrome://messenger/skin/folder-newsgroup.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol) {
|
||||
list-style-image: url("chrome://messenger/skin/dot.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
|
||||
list-style-image: url("chrome://messenger/skin/check.gif");
|
||||
}
|
||||
|
||||
|
|
|
@ -68,3 +68,19 @@
|
|||
#subscribetree {
|
||||
margin: 0px 0px 0px 0px !important;
|
||||
}
|
||||
|
||||
|
||||
/* for search */
|
||||
|
||||
outlinerbody:-moz-outliner-image(nameCol, nntp) {
|
||||
list-style-image: url("chrome://messenger/skin/icons/folder-newsgroup.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol) {
|
||||
list-style-image: url("chrome://messenger/skin/icons/dot.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
|
||||
list-style-image: url("chrome://messenger/skin/icons/check.gif");
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче