Back to index

lightning-sunbird  0.9+nobinonly
nsNewsFolder.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *   Håkan Waara  <hwaara@chello.se>
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 
00042 #include "nsIPrefBranch.h"
00043 #include "nsIPrefService.h"
00044 #include "prlog.h"
00045 
00046 #include "msgCore.h"    // precompiled header...
00047 #include "nntpCore.h"
00048 
00049 #include "nsNewsFolder.h"    
00050 #include "nsMsgFolderFlags.h"
00051 #include "prprf.h"
00052 #include "prsystem.h"
00053 #include "nsISupportsArray.h"
00054 #include "nsIServiceManager.h"
00055 #include "nsIEnumerator.h"
00056 #include "nsINntpService.h"
00057 #include "nsIFolderListener.h"
00058 #include "nsCOMPtr.h"
00059 #include "nsIRDFService.h"
00060 #include "nsIRDFDataSource.h"
00061 #include "nsRDFCID.h"
00062 #include "nsFileStream.h"
00063 #include "nsMsgDBCID.h"
00064 #include "nsMsgNewsCID.h"
00065 #include "nsMsgUtils.h"
00066 #include "nsNewsUtils.h"
00067 
00068 #include "nsCOMPtr.h"
00069 #include "nsIMsgMailSession.h"
00070 #include "nsIMsgIncomingServer.h"
00071 #include "nsINntpIncomingServer.h"
00072 #include "nsINewsDatabase.h"
00073 #include "nsMsgBaseCID.h"
00074 
00075 #include "nsIMsgWindow.h"
00076 #include "nsIDocShell.h"
00077 #include "nsIPrompt.h"
00078 #include "nsIWindowWatcher.h"
00079 
00080 #include "nsXPIDLString.h"
00081 
00082 #include "nsIObserverService.h"
00083 #include "nsNetUtil.h"
00084 #include "nsIAuthPrompt.h"
00085 #include "nsIURL.h"
00086 #include "nsNetCID.h"
00087 #include "nsINntpUrl.h"
00088 #include "nsNewsSummarySpec.h"
00089 
00090 #include "nsIInterfaceRequestor.h"
00091 #include "nsIInterfaceRequestorUtils.h"
00092 
00093 #include "nsReadableUtils.h"
00094 #include "nsNewsDownloader.h"
00095 #include "nsIStringBundle.h"
00096 #include "nsEscape.h"
00097 #include "nsMsgI18N.h"
00098 #include "nsNativeCharsetUtils.h"
00099 #include "nsIMsgAccountManager.h"
00100 
00101 // we need this because of an egcs 1.0 (and possibly gcc) compiler bug
00102 // that doesn't allow you to call ::nsISupports::GetIID() inside of a class
00103 // that multiply inherits from nsISupports
00104 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00105 static NS_DEFINE_CID(kCNewsDB, NS_NEWSDB_CID);
00106 
00107 // ###tw  This really ought to be the most
00108 // efficient file reading size for the current
00109 // operating system.
00110 #define NEWSRC_FILE_BUFFER_SIZE 1024
00111 
00112 #define NEWS_SCHEME "news:"
00113 #define SNEWS_SCHEME "snews:"
00114 
00116 
00117 
00119 
00120 nsMsgNewsFolder::nsMsgNewsFolder(void) : nsMsgLineBuffer(nsnull, PR_FALSE),
00121      mExpungedBytes(0), mGettingNews(PR_FALSE),
00122     mInitialized(PR_FALSE), mOptionLines(""), mUnsubscribedNewsgroupLines(""), 
00123     m_downloadMessageForOfflineUse(PR_FALSE), m_downloadingMultipleMessages(PR_FALSE), 
00124     mReadSet(nsnull), mGroupUsername(nsnull), mGroupPassword(nsnull)
00125 {
00126   MOZ_COUNT_CTOR(nsNewsFolder); // double count these for now.
00127   /* we're parsing the newsrc file, and the line breaks are platform specific.
00128    * if MSG_LINEBREAK != CRLF, then we aren't looking for CRLF 
00129    */
00130   if (PL_strcmp(MSG_LINEBREAK, CRLF))
00131     SetLookingForCRLF(PR_FALSE);
00132 }
00133 
00134 nsMsgNewsFolder::~nsMsgNewsFolder(void)
00135 {
00136   MOZ_COUNT_DTOR(nsNewsFolder);
00137   delete mReadSet;
00138   PR_Free(mGroupUsername);
00139   PR_Free(mGroupPassword);
00140 }
00141 
00142 NS_IMPL_ADDREF_INHERITED(nsMsgNewsFolder, nsMsgDBFolder)
00143 NS_IMPL_RELEASE_INHERITED(nsMsgNewsFolder, nsMsgDBFolder)
00144 
00145 NS_IMETHODIMP nsMsgNewsFolder::QueryInterface(REFNSIID aIID, void** aInstancePtr)
00146 {
00147   if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
00148   *aInstancePtr = nsnull;
00149   if (aIID.Equals(NS_GET_IID(nsIMsgNewsFolder)))
00150   {
00151     *aInstancePtr = NS_STATIC_CAST(nsIMsgNewsFolder*, this);
00152   }              
00153   
00154   if(*aInstancePtr)
00155   {
00156     AddRef();
00157     return NS_OK;
00158   }
00159   
00160   return nsMsgDBFolder::QueryInterface(aIID, aInstancePtr);
00161 }
00162 
00164 
00165 nsresult
00166 nsMsgNewsFolder::CreateSubFolders(nsFileSpec &path)
00167 {
00168   nsresult rv = NS_OK;
00169 
00170   PRBool isNewsServer = PR_FALSE;
00171   rv = GetIsServer(&isNewsServer);
00172   if (NS_FAILED(rv)) return rv;
00173 
00174   if (isNewsServer) 
00175   {  
00176     nsCOMPtr<nsINntpIncomingServer> nntpServer;
00177     rv = GetNntpServer(getter_AddRefs(nntpServer));
00178     if (NS_FAILED(rv)) return rv;
00179   
00180     rv = nntpServer->GetNewsrcFilePath(getter_AddRefs(mNewsrcFilePath));
00181     if (NS_FAILED(rv)) return rv;
00182       
00183     rv = LoadNewsrcFileAndCreateNewsgroups();
00184     if (NS_FAILED(rv)) return rv;
00185   }
00186   else 
00187   {
00188     // is not a host, so it has no newsgroups.  (what about categories??)
00189     rv = NS_OK;
00190   }
00191   
00192   return rv;
00193 }
00194 
00195 NS_IMETHODIMP
00196 nsMsgNewsFolder::AddNewsgroup(const nsACString &name, const char *setStr,
00197                               nsIMsgFolder **child)
00198 {
00199   nsresult rv = NS_OK;
00200   
00201   NS_ENSURE_ARG_POINTER(child);
00202   NS_ENSURE_ARG_POINTER(setStr);
00203   
00204   nsCOMPtr <nsIRDFService> rdf = do_GetService(kRDFServiceCID, &rv); 
00205   if (NS_FAILED(rv)) return rv;
00206   if (!rdf) return NS_ERROR_FAILURE;
00207   
00208   nsCOMPtr <nsINntpIncomingServer> nntpServer;
00209   rv = GetNntpServer(getter_AddRefs(nntpServer));
00210   if (NS_FAILED(rv)) return rv;
00211   
00212   nsCAutoString uri(mURI);
00213   uri.Append('/');
00214   // URI should use UTF-8
00215   // (see RFC2396 Uniform Resource Identifiers (URI): Generic Syntax)
00216   
00217   // we are handling newsgroup names in UTF-8
00218   NS_ConvertUTF8toUTF16 nameUtf16(name);
00219   
00220   nsCAutoString escapedName;
00221   rv = NS_MsgEscapeEncodeURLPath(nameUtf16, escapedName);
00222   if (NS_FAILED(rv)) return rv;
00223   
00224   rv = nntpServer->AddNewsgroup(nameUtf16);
00225   if (NS_FAILED(rv)) return rv;
00226   
00227   uri.Append(escapedName);
00228   
00229   nsCOMPtr<nsIRDFResource> res;
00230   rv = rdf->GetResource(uri, getter_AddRefs(res));
00231   if (NS_FAILED(rv)) return rv;
00232   
00233   nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(res, &rv));
00234   if (NS_FAILED(rv)) return rv;
00235   
00236   nsCOMPtr<nsIMsgNewsFolder> newsFolder(do_QueryInterface(res, &rv));
00237   if (NS_FAILED(rv)) return rv;        
00238   
00239   // cache this for when we open the db
00240   rv = newsFolder->SetReadSetFromStr(setStr);
00241 
00242   rv = folder->SetParent(this);
00243   NS_ENSURE_SUCCESS(rv,rv);
00244   
00245   // this what shows up in the UI
00246   rv = folder->SetName(nameUtf16.get());
00247   NS_ENSURE_SUCCESS(rv,rv);
00248   
00249   rv = folder->SetFlag(MSG_FOLDER_FLAG_NEWSGROUP);
00250   if (NS_FAILED(rv)) return rv;          
00251   
00252   PRUint32 numExistingGroups;
00253   rv = Count(&numExistingGroups);
00254   NS_ENSURE_SUCCESS(rv,rv);
00255 
00256   // add 9000 to prevent this problem:  1,10,11,2,3,4,5
00257   // We use 9000 instead of 1000 so newsgroups will sort to bottom of flat folder views
00258   rv = folder->SetSortOrder(numExistingGroups + 9000);
00259   NS_ENSURE_SUCCESS(rv,rv);
00260   
00261   //convert to an nsISupports before appending
00262   nsCOMPtr<nsISupports> folderSupports(do_QueryInterface(folder));
00263   if(folderSupports)
00264        mSubFolders->AppendElement(folderSupports);
00265   *child = folder;
00266   folder->SetParent(this);
00267   NS_ADDREF(*child);
00268 
00269   return rv;
00270 }
00271 
00272 
00273 nsresult nsMsgNewsFolder::ParseFolder(nsFileSpec& path)
00274 {
00275   NS_ASSERTION(0,"ParseFolder not implemented");
00276        return NS_ERROR_NOT_IMPLEMENTED;
00277 }
00278 
00279 NS_IMETHODIMP
00280 nsMsgNewsFolder::Enumerate(nsIEnumerator **result)
00281 {
00282 #if 0
00283   nsresult rv = NS_OK;
00284   // for now, news folders contain both messages and folders
00285   // server is a folder, and it contains folders
00286   // newsgroup is a folder, and it contains messages
00287   //
00288   // eventually the top level server will not be a folder
00289   // and news folders will only contain messages
00290   nsIEnumerator* folders;
00291   nsIEnumerator* messages;
00292   rv = GetSubFolders(&folders);
00293   if (NS_FAILED(rv)) return rv;
00294   rv = GetMessages(nsnull, &messages);
00295   if (NS_FAILED(rv)) return rv;
00296   return NS_NewConjoiningEnumerator(folders, messages, 
00297                                     (nsIBidirectionalEnumerator**)result);
00298 #endif
00299   NS_ASSERTION(PR_FALSE, "obsolete, right?");
00300   return NS_ERROR_FAILURE;
00301 }
00302 
00303 nsresult
00304 nsMsgNewsFolder::AddDirectorySeparator(nsFileSpec &path)
00305 {
00306     nsresult rv = NS_OK;
00307     if (mURI.Equals(kNewsRootURI)) 
00308     {
00309     // don't concat the full separator with .sbd
00310     }
00311     else 
00312     {
00313       // see if there's a dir with the same name ending with .sbd
00314       // unfortunately we can't just say:
00315       //          path += sep;
00316       // here because of the way nsFileSpec concatenates
00317       nsAutoString str;
00318       str.AssignWithConversion(nsFilePath(path));
00319 #if 0
00320       nsAutoString sep;
00321       rv = nsGetNewsFolderSeparator(sep);
00322       if (NS_FAILED(rv)) return rv;
00323       str += sep;
00324 #endif
00325 
00326       path = nsFilePath(str);
00327     }
00328 
00329     return rv;
00330 }
00331 
00332 NS_IMETHODIMP
00333 nsMsgNewsFolder::GetSubFolders(nsIEnumerator* *result)
00334 {
00335   nsresult rv;
00336   
00337   if (!mInitialized) 
00338   {
00339     // do this first, so we make sure to do it, even on failure.
00340     // see bug #70494
00341     mInitialized = PR_TRUE;
00342     
00343     nsCOMPtr<nsIFileSpec> pathSpec;
00344     rv = GetPath(getter_AddRefs(pathSpec));
00345     if (NS_FAILED(rv)) return rv;
00346     
00347     nsFileSpec path;
00348     rv = pathSpec->GetFileSpec(&path);
00349     if (NS_FAILED(rv)) return rv;
00350     
00351     nsFileSpec tempPath(path.GetNativePathCString(), PR_TRUE);
00352     
00353     rv = CreateSubFolders(path);
00354     if (NS_FAILED(rv)) return rv;
00355 
00356     // force ourselves to get initialized from cache
00357     // Don't care if it fails.  this will fail the first time after 
00358     // migration, but we continue on.  see #66018
00359     (void)UpdateSummaryTotals(PR_FALSE);
00360   }
00361 
00362   rv = mSubFolders->Enumerate(result);
00363   return rv;
00364 }
00365 
00366 //Makes sure the database is open and exists.  If the database is valid then
00367 //returns NS_OK.  Otherwise returns a failure error value.
00368 nsresult nsMsgNewsFolder::GetDatabase(nsIMsgWindow *aMsgWindow)
00369 {
00370   nsresult rv;
00371   if (!mDatabase)
00372   {
00373     nsCOMPtr<nsIFileSpec> pathSpec;
00374     rv = GetPath(getter_AddRefs(pathSpec));
00375     if (NS_FAILED(rv)) return rv;
00376     
00377     nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
00378     NS_ENSURE_SUCCESS(rv,rv);
00379 
00380     nsresult folderOpen = msgDBService->OpenFolderDB(this, PR_TRUE, PR_FALSE, getter_AddRefs(mDatabase));
00381     
00382     if (NS_FAILED(folderOpen) && folderOpen != NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00383       folderOpen = msgDBService->OpenFolderDB(this, PR_TRUE, PR_TRUE, getter_AddRefs(mDatabase));
00384 
00385     if (NS_FAILED(folderOpen) && folderOpen != NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
00386       return folderOpen;
00387 
00388     if(mAddListener)
00389       rv = mDatabase->AddListener(this);
00390       
00391     nsCOMPtr<nsINewsDatabase> db = do_QueryInterface(mDatabase, &rv);
00392     if (NS_FAILED(rv)) 
00393       return rv;        
00394       
00395     rv = db->SetReadSet(mReadSet);
00396     if (NS_FAILED(rv)) 
00397       return rv;        
00398 
00399     rv = UpdateSummaryTotals(PR_TRUE);
00400     if (NS_FAILED(rv)) 
00401       return rv;
00402   }
00403   return NS_OK;
00404 }
00405 
00406 NS_IMETHODIMP
00407 nsMsgNewsFolder::UpdateFolder(nsIMsgWindow *aWindow)
00408 {
00409   // Get news.get_messages_on_select pref
00410   nsresult rv;
00411   PRBool getMessagesOnSelect = PR_TRUE;
00412   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00413   if NS_SUCCEEDED(rv)
00414     prefBranch->GetBoolPref("news.get_messages_on_select", &getMessagesOnSelect);
00415   
00416   // Only if news.get_messages_on_select is true do we get new messages automatically
00417   if (getMessagesOnSelect) 
00418   { 
00419     rv = GetDatabase(aWindow);     // want this cached...
00420     if (NS_SUCCEEDED(rv))
00421     { 
00422       if (mDatabase)
00423       {
00424         nsCOMPtr<nsIMsgRetentionSettings> retentionSettings;
00425         nsresult rv = GetRetentionSettings(getter_AddRefs(retentionSettings));
00426         if (NS_SUCCEEDED(rv))
00427           rv = mDatabase->ApplyRetentionSettings(retentionSettings, PR_FALSE);
00428       }
00429       rv = AutoCompact(aWindow);
00430       NS_ENSURE_SUCCESS(rv,rv);
00431       // GetNewMessages has to be the last rv set before we get to the next check, so
00432       // that we'll have rv set to NS_MSG_ERROR_OFFLINE when offline and send
00433       // a folder loaded notification to the front end.
00434       rv = GetNewMessages(aWindow, nsnull);
00435     } 
00436     if (rv != NS_MSG_ERROR_OFFLINE)
00437       return rv;
00438   } 
00439   // We're not getting messages because either get_messages_on_select is
00440   // false or we're offline. Send an immediate folder loaded notification.
00441   NotifyFolderEvent(mFolderLoadedAtom);
00442   return NS_OK;
00443 }
00444 
00445 NS_IMETHODIMP
00446 nsMsgNewsFolder::GetCanSubscribe(PRBool *aResult)
00447 {
00448   NS_ENSURE_ARG_POINTER(aResult);
00449   *aResult = PR_FALSE;
00450 
00451   PRBool isNewsServer = PR_FALSE;
00452   nsresult rv = GetIsServer(&isNewsServer);
00453   if (NS_FAILED(rv)) return rv;
00454  
00455   // you can only subscribe to news servers, not news groups
00456   *aResult = isNewsServer;
00457   return NS_OK;
00458 }
00459 
00460 NS_IMETHODIMP
00461 nsMsgNewsFolder::GetCanFileMessages(PRBool *aResult)
00462 {
00463   NS_ENSURE_ARG_POINTER(aResult);
00464   // you can't file messages into a news server or news group
00465   *aResult = PR_FALSE;
00466   return NS_OK;
00467 }
00468 
00469 NS_IMETHODIMP
00470 nsMsgNewsFolder::GetCanDeleteMessages(PRBool *aCanDeleteMessages)
00471 {
00472   NS_ENSURE_ARG_POINTER(aCanDeleteMessages);
00473   *aCanDeleteMessages = PR_FALSE;
00474   return NS_OK;
00475 }
00476 
00477 NS_IMETHODIMP
00478 nsMsgNewsFolder::GetCanCreateSubfolders(PRBool *aResult)
00479 {
00480   NS_ENSURE_ARG_POINTER(aResult);
00481   *aResult = PR_FALSE;
00482   // you can't create subfolders on a news server or a news group
00483   return NS_OK;
00484 }
00485 
00486 NS_IMETHODIMP
00487 nsMsgNewsFolder::GetCanRename(PRBool *aResult)
00488 {
00489   NS_ENSURE_ARG_POINTER(aResult);
00490   *aResult = PR_FALSE;
00491   // you can't rename a news server or a news group
00492   return NS_OK;
00493 }
00494 
00495 NS_IMETHODIMP
00496 nsMsgNewsFolder::GetCanCompact(PRBool *aResult)
00497 {
00498   NS_ENSURE_ARG_POINTER(aResult);
00499   *aResult = PR_FALSE;
00500   // you can't compact a news server or a news group
00501   return NS_OK;
00502 }
00503 
00504 NS_IMETHODIMP
00505 nsMsgNewsFolder::GetMessages(nsIMsgWindow *aMsgWindow, nsISimpleEnumerator* *result)
00506 {
00507   nsresult rv = GetDatabase(aMsgWindow);
00508   *result = nsnull;
00509     
00510   if(NS_SUCCEEDED(rv))
00511     rv = mDatabase->EnumerateMessages(result);
00512 
00513   return rv;
00514 }
00515 
00516 NS_IMETHODIMP nsMsgNewsFolder::GetFolderURL(char **url)
00517 {
00518   NS_ENSURE_ARG_POINTER(url);
00519 
00520   nsXPIDLCString hostName;
00521   nsresult rv = GetHostname(getter_Copies(hostName));
00522   nsXPIDLString groupName;
00523   rv = GetName(getter_Copies(groupName));
00524   NS_ENSURE_SUCCESS(rv, rv);
00525 
00526   nsCOMPtr<nsIMsgIncomingServer> server;
00527   rv = GetServer(getter_AddRefs(server));
00528   NS_ENSURE_SUCCESS(rv, rv);
00529 
00530   PRInt32 port;
00531   PRBool isSecure = PR_FALSE;
00532   rv = server->GetIsSecure(&isSecure);
00533   NS_ENSURE_SUCCESS(rv, rv);
00534   rv = server->GetPort(&port);
00535   NS_ENSURE_SUCCESS(rv, rv);
00536   const char *newsScheme = (isSecure) ? SNEWS_SCHEME : NEWS_SCHEME;
00537   nsXPIDLCString escapedName;
00538   rv = NS_MsgEscapeEncodeURLPath(groupName, escapedName);
00539   NS_ENSURE_SUCCESS(rv, rv);
00540   *url = PR_smprintf("%s//%s:%ld/%s", newsScheme, hostName.get(), port,
00541                      escapedName.get());
00542   return NS_OK;
00543 
00544 }
00545 
00546 NS_IMETHODIMP nsMsgNewsFolder::SetNewsrcHasChanged(PRBool newsrcHasChanged)
00547 {
00548     nsresult rv;
00549 
00550     nsCOMPtr<nsINntpIncomingServer> nntpServer;
00551     rv = GetNntpServer(getter_AddRefs(nntpServer));
00552     if (NS_FAILED(rv)) return rv;
00553 
00554     return nntpServer->SetNewsrcHasChanged(newsrcHasChanged);
00555 }
00556 
00557 NS_IMETHODIMP nsMsgNewsFolder::CreateSubfolder(const PRUnichar *newsgroupName, 
00558                                                nsIMsgWindow *msgWindow)
00559 {
00560   nsresult rv = NS_OK;
00561   
00562   NS_ENSURE_ARG_POINTER(newsgroupName);
00563   if (!*newsgroupName) return NS_ERROR_FAILURE;
00564   
00565   nsCOMPtr<nsIMsgFolder> child;
00566   
00567   // Create an empty database for this mail folder, set its name from the user  
00568   nsCOMPtr<nsIMsgDatabase> newsDBFactory;
00569   nsCOMPtr <nsIMsgDatabase> newsDB;
00570   
00571   //Now let's create the actual new folder
00572   rv = AddNewsgroup(NS_ConvertUTF16toUTF8(newsgroupName), "",
00573                     getter_AddRefs(child));
00574   
00575   if (NS_SUCCEEDED(rv))
00576     SetNewsrcHasChanged(PR_TRUE); // subscribe UI does this - but maybe we got here through auto-subscribe
00577 
00578   if(NS_SUCCEEDED(rv) && child){
00579     nsCOMPtr <nsINntpIncomingServer> nntpServer;
00580     rv = GetNntpServer(getter_AddRefs(nntpServer));
00581     if (NS_FAILED(rv)) return rv;
00582     
00583     nsCAutoString dataCharset;
00584     rv = nntpServer->GetCharset(dataCharset);
00585     if (NS_FAILED(rv)) return rv;
00586 
00587     child->SetCharset(dataCharset.get());
00588     NotifyItemAdded(child);
00589   }
00590   return rv;
00591 }
00592 
00593 NS_IMETHODIMP nsMsgNewsFolder::Delete()
00594 {
00595   nsresult rv = GetDatabase(nsnull);
00596   
00597   if(NS_SUCCEEDED(rv)) 
00598   {
00599     mDatabase->ForceClosed();
00600     mDatabase = nsnull;
00601   }
00602   
00603   nsCOMPtr<nsIFileSpec> pathSpec;
00604   rv = GetPath(getter_AddRefs(pathSpec));
00605   if (NS_FAILED(rv)) return rv;
00606   
00607   nsFileSpec path;
00608   rv = pathSpec->GetFileSpec(&path);
00609   if (NS_FAILED(rv)) return rv;
00610   
00611   // delete local store, if it exists
00612   if (path.Exists())
00613     path.Delete(PR_FALSE);
00614   // Remove summary file.   
00615   nsNewsSummarySpec summarySpec(path);
00616   summarySpec.Delete(PR_FALSE);
00617  
00618   nsCOMPtr <nsINntpIncomingServer> nntpServer;
00619   rv = GetNntpServer(getter_AddRefs(nntpServer));
00620   if (NS_FAILED(rv)) return rv;
00621   
00622   nsAutoString name;
00623   rv = GetUnicodeName(name);
00624   NS_ENSURE_SUCCESS(rv,rv);
00625   
00626   rv = nntpServer->RemoveNewsgroup(name);
00627   NS_ENSURE_SUCCESS(rv,rv);
00628   
00629   rv = SetNewsrcHasChanged(PR_TRUE);
00630   NS_ENSURE_SUCCESS(rv,rv);
00631   return rv;
00632 }
00633 
00634 NS_IMETHODIMP nsMsgNewsFolder::Rename(const PRUnichar *newName, nsIMsgWindow *msgWindow)
00635 {
00636   NS_ASSERTION(0,"Rename not implemented");
00637   return NS_ERROR_NOT_IMPLEMENTED;
00638 }
00639 
00640 NS_IMETHODIMP nsMsgNewsFolder::GetAbbreviatedName(PRUnichar * *aAbbreviatedName)
00641 {
00642   nsresult rv = NS_OK;
00643 
00644   if (!aAbbreviatedName)
00645     return NS_ERROR_NULL_POINTER;
00646 
00647   rv = nsMsgDBFolder::GetPrettyName(aAbbreviatedName);
00648   if(NS_FAILED(rv)) return rv;
00649 
00650   // only do this for newsgroup names, not for newsgroup hosts.
00651   PRBool isNewsServer = PR_FALSE;
00652   rv = GetIsServer(&isNewsServer);
00653   if (NS_FAILED(rv)) return rv;
00654   
00655   if (!isNewsServer) {  
00656     nsCOMPtr<nsINntpIncomingServer> nntpServer;
00657     rv = GetNntpServer(getter_AddRefs(nntpServer));
00658     if (NS_FAILED(rv)) return rv;
00659     
00660     PRBool abbreviate = PR_TRUE;
00661     rv = nntpServer->GetAbbreviate(&abbreviate);
00662     if (NS_FAILED(rv)) return rv;
00663     
00664     if (abbreviate) {
00665       rv = AbbreviatePrettyName(aAbbreviatedName, 1 /* hardcoded for now */);
00666     }
00667   }
00668 
00669   return rv;
00670 }
00671 
00672 
00673 // original code from Oleg Rekutin
00674 // rekusha@asan.com
00675 // Public domain, created by Oleg Rekutin
00676 //
00677 // takes a newsgroup name, number of words from the end to leave unabberviated
00678 // the newsgroup name, will get reset to the following format:
00679 // x.x.x, where x is the first letter of each word and with the
00680 // exception of last 'fullwords' words, which are left intact.
00681 // If a word has a dash in it, it is abbreviated as a-b, where
00682 // 'a' is the first letter of the part of the word before the
00683 // dash and 'b' is the first letter of the part of the word after
00684 // the dash
00685 nsresult nsMsgNewsFolder::AbbreviatePrettyName(PRUnichar ** prettyName, PRInt32 fullwords)
00686 {
00687   if (!prettyName)
00688     return NS_ERROR_NULL_POINTER;
00689   
00690   nsAutoString name(*prettyName);
00691   PRInt32 totalwords = 0; // total no. of words
00692   
00693   // get the total no. of words
00694   PRInt32 pos = 0;
00695   while(1)
00696   {
00697     pos = name.FindChar('.', pos);
00698     if(pos == -1)
00699     {
00700       totalwords++;
00701       break;
00702     }
00703     else
00704     {
00705       totalwords++;
00706       pos++;
00707     }
00708   }
00709   
00710   // get the no. of words to abbreviate
00711   PRInt32 abbrevnum = totalwords - fullwords;
00712   if (abbrevnum < 1)
00713     return NS_OK; // nothing to abbreviate
00714   
00715   // build the ellipsis
00716   nsAutoString out;
00717   
00718   out += name[0];
00719   
00720   PRInt32    length = name.Length();
00721   PRInt32    newword = 0;     // == 2 if done with all abbreviated words
00722   
00723   fullwords = 0;
00724   PRUnichar currentChar;
00725   for (PRInt32 i = 1; i < length; i++) {
00726     // this temporary assignment is needed to fix an intel mac compiler bug.
00727     // See Bug #327037 for details.
00728     currentChar = name[i]; 
00729     if (newword < 2) {
00730       switch (currentChar) {
00731       case '.':
00732         fullwords++;
00733         // check if done with all abbreviated words...
00734         if (fullwords == abbrevnum)
00735           newword = 2;
00736         else
00737           newword = 1;
00738         break;
00739       case '-':
00740         newword = 1;
00741         break;
00742       default:
00743         if (newword)
00744           newword = 0;
00745         else
00746           continue;
00747       }
00748     }
00749     out += currentChar;
00750   }
00751 
00752   if (!prettyName)
00753     return NS_ERROR_NULL_POINTER;
00754   // we are going to set *prettyName to something else, so free what was there
00755   
00756   PR_Free(*prettyName);
00757   *prettyName = ToNewUnicode(out);
00758   
00759   return (*prettyName) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00760 }
00761 
00762 
00763 NS_IMETHODIMP
00764 nsMsgNewsFolder::GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db)
00765 {
00766 
00767   nsresult openErr;
00768   if(!db || !folderInfo)
00769     return NS_ERROR_NULL_POINTER; 
00770 
00771   openErr = GetDatabase(nsnull);
00772   *db = mDatabase;
00773   if (mDatabase) {
00774     NS_ADDREF(*db);
00775     if (NS_SUCCEEDED(openErr))
00776       openErr = (*db)->GetDBFolderInfo(folderInfo);
00777   }
00778 
00779   return openErr;
00780 }
00781 
00782 /* this used to be MSG_FolderInfoNews::UpdateSummaryFromNNTPInfo() */
00783 NS_IMETHODIMP 
00784 nsMsgNewsFolder::UpdateSummaryFromNNTPInfo(PRInt32 oldest, PRInt32 youngest, PRInt32 total)
00785 {
00786   nsresult rv = NS_OK;
00787   PRBool newsrcHasChanged = PR_FALSE;
00788   PRInt32 oldUnreadMessages = mNumUnreadMessages;
00789   PRInt32 oldTotalMessages = mNumTotalMessages;
00790   
00791   /* First, mark all of the articles now known to be expired as read. */
00792   if (oldest > 1) 
00793   { 
00794     nsXPIDLCString oldSet;
00795     nsXPIDLCString newSet;
00796     mReadSet->Output(getter_Copies(oldSet));
00797     mReadSet->AddRange(1, oldest - 1);
00798     rv = mReadSet->Output(getter_Copies(newSet));
00799     if (!oldSet.Equals(newSet))
00800       newsrcHasChanged = PR_TRUE;
00801   }
00802   
00803   /* Now search the newsrc line and figure out how many of these messages are marked as unread. */
00804   
00805   /* make sure youngest is a least 1. MSNews seems to return a youngest of 0. */
00806   if (youngest == 0) 
00807     youngest = 1;
00808   
00809   PRInt32 unread = mReadSet->CountMissingInRange(oldest, youngest);
00810   NS_ASSERTION(unread >= 0,"CountMissingInRange reported unread < 0");
00811   if (unread < 0)
00812     // servers can send us stuff like "211 0 41 40 nz.netstatus"
00813     // we should handle it gracefully.
00814     unread = 0;
00815   
00816   if (unread > total) 
00817   {
00818     /* This can happen when the newsrc file shows more unread than exist in the group (total is not necessarily `end - start'.) */
00819     unread = total;
00820     PRInt32 deltaInDB = mNumTotalMessages - mNumUnreadMessages;
00821     //PRint32 deltaInDB = m_totalInDB - m_unreadInDB;
00822     /* if we know there are read messages in the db, subtract that from the unread total */
00823     if (deltaInDB > 0)
00824       unread -= deltaInDB;
00825   }
00826   
00827   PRInt32 pendingUnreadDelta = unread - mNumUnreadMessages - mNumPendingUnreadMessages;
00828   PRInt32 pendingTotalDelta = total - mNumTotalMessages - mNumPendingTotalMessages;
00829   ChangeNumPendingUnread(pendingUnreadDelta);
00830   ChangeNumPendingTotalMessages(pendingTotalDelta);
00831 
00832 #if 0
00833   m_nntpHighwater = youngest;
00834   m_nntpTotalArticles = total;
00835 #endif
00836   
00837   return rv;
00838 }
00839 
00840 NS_IMETHODIMP nsMsgNewsFolder::UpdateSummaryTotals(PRBool force)
00841 {
00842   if (!mNotifyCountChanges)
00843     return NS_OK;
00844   
00845   PRInt32 oldUnreadMessages = mNumUnreadMessages;
00846   PRInt32 oldTotalMessages = mNumTotalMessages;
00847   //We need to read this info from the database
00848   nsresult ret = ReadDBFolderInfo(force);
00849   
00850   if (NS_SUCCEEDED(ret))
00851   {
00852     //Need to notify listeners that total count changed.
00853     if(oldTotalMessages != mNumTotalMessages) 
00854       NotifyIntPropertyChanged(kTotalMessagesAtom, oldTotalMessages, mNumTotalMessages);
00855     
00856     if(oldUnreadMessages != mNumUnreadMessages) 
00857       NotifyIntPropertyChanged(kTotalUnreadMessagesAtom, oldUnreadMessages, mNumUnreadMessages);
00858     
00859     FlushToFolderCache();
00860   }
00861   return ret;
00862 }
00863 
00864 NS_IMETHODIMP nsMsgNewsFolder::GetExpungedBytesCount(PRUint32 *count)
00865 {
00866   if(!count)
00867     return NS_ERROR_NULL_POINTER;
00868 
00869   *count = mExpungedBytes;
00870 
00871   return NS_OK;
00872 }
00873 
00874 NS_IMETHODIMP nsMsgNewsFolder::GetDeletable(PRBool *deletable)
00875 {
00876 //  NS_ASSERTION(0,"GetDeletable() not implemented");
00877   return NS_ERROR_NOT_IMPLEMENTED;
00878 }
00879  
00880 NS_IMETHODIMP nsMsgNewsFolder::GetRequiresCleanup(PRBool *requiresCleanup)
00881 {
00882 //  NS_ASSERTION(0,"GetRequiresCleanup not implemented");
00883   return NS_ERROR_NOT_IMPLEMENTED;
00884 }
00885 
00886 NS_IMETHODIMP nsMsgNewsFolder::GetSizeOnDisk(PRUint32 *size)
00887 {
00888 //  NS_ASSERTION(0, "GetSizeOnDisk not implemented");
00889   return NS_ERROR_NOT_IMPLEMENTED;
00890 }
00891 
00892 /* this is news, so remember that DeleteMessage is really CANCEL. */
00893 NS_IMETHODIMP 
00894 nsMsgNewsFolder::DeleteMessages(nsISupportsArray *messages, nsIMsgWindow *aMsgWindow, 
00895                                 PRBool deleteStorage, PRBool isMove,
00896                                 nsIMsgCopyServiceListener* listener, PRBool allowUndo)
00897 {
00898   nsresult rv = NS_OK;
00899  
00900   NS_ENSURE_ARG_POINTER(messages);
00901   NS_ENSURE_ARG_POINTER(aMsgWindow);
00902  
00903   PRUint32 count = 0;
00904   rv = messages->Count(&count);
00905   NS_ENSURE_SUCCESS(rv,rv);
00906   
00907   if (count != 1) 
00908   {
00909     nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00910     NS_ENSURE_SUCCESS(rv, rv);
00911 
00912     nsCOMPtr<nsIStringBundle> bundle;
00913     rv = bundleService->CreateBundle(NEWS_MSGS_URL, getter_AddRefs(bundle));
00914     NS_ENSURE_SUCCESS(rv, rv);
00915 
00916     nsXPIDLString alertText;
00917     rv = bundle->GetStringFromName(NS_LITERAL_STRING("onlyCancelOneMessage").get(), getter_Copies(alertText));
00918     NS_ENSURE_SUCCESS(rv, rv);
00919 
00920     nsCOMPtr<nsIPrompt> dialog;
00921     rv = aMsgWindow->GetPromptDialog(getter_AddRefs(dialog));
00922     NS_ENSURE_SUCCESS(rv,rv);
00923 
00924     if (dialog) 
00925     {
00926       rv = dialog->Alert(nsnull, (const PRUnichar *) alertText);
00927       NS_ENSURE_SUCCESS(rv,rv);
00928     }
00929     // return failure, since the cancel failed
00930     return NS_ERROR_FAILURE;
00931   }
00932   
00933   nsCOMPtr <nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
00934   NS_ENSURE_SUCCESS(rv,rv);
00935 
00936   nsCOMPtr<nsIMsgDBHdr> msgHdr(do_QueryElementAt(messages, 0));
00937 
00938   // for cancel, we need to
00939   // turn "newsmessage://sspitzer@news.mozilla.org/netscape.test#5428"
00940   // into "news://sspitzer@news.mozilla.org/23423@netscape.com"
00941 
00942   nsCOMPtr <nsIMsgIncomingServer> server;
00943   rv = GetServer(getter_AddRefs(server));
00944   NS_ENSURE_SUCCESS(rv,rv);
00945 
00946   nsXPIDLCString serverURI;
00947   rv = server->GetServerURI(getter_Copies(serverURI));
00948   NS_ENSURE_SUCCESS(rv,rv);
00949 
00950   nsXPIDLCString messageID;
00951   rv = msgHdr->GetMessageId(getter_Copies(messageID));
00952   NS_ENSURE_SUCCESS(rv,rv);
00953   
00954   // we need to escape the message ID, 
00955   // it might contain characters which will mess us up later, like #
00956   // see bug #120502
00957   char *escapedMessageID = nsEscape(messageID.get(), url_Path);
00958   if (!escapedMessageID)
00959     return NS_ERROR_OUT_OF_MEMORY;
00960 
00961   nsCAutoString cancelURL((const char *)serverURI);
00962   cancelURL += '/';
00963   cancelURL += escapedMessageID;
00964   cancelURL += "?cancel";
00965 
00966   PR_Free(escapedMessageID);
00967 
00968   nsXPIDLCString messageURI;
00969   rv = GetUriForMsg(msgHdr, getter_Copies(messageURI));
00970   NS_ENSURE_SUCCESS(rv,rv);
00971 
00972   rv = nntpService->CancelMessage(cancelURL.get(), messageURI, nsnull /* consumer */, nsnull, aMsgWindow, nsnull);
00973   NS_ENSURE_SUCCESS(rv,rv);
00974   
00975   return rv;
00976 }
00977 
00978 NS_IMETHODIMP nsMsgNewsFolder::GetNewMessages(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener)
00979 {
00980   return GetNewsMessages(aMsgWindow, PR_FALSE, aListener);
00981 }
00982 
00983 NS_IMETHODIMP nsMsgNewsFolder::GetNextNMessages(nsIMsgWindow *aMsgWindow)
00984 {
00985   return GetNewsMessages(aMsgWindow, PR_TRUE, nsnull);
00986 }
00987 
00988 nsresult nsMsgNewsFolder::GetNewsMessages(nsIMsgWindow *aMsgWindow, PRBool aGetOld, nsIUrlListener *aUrlListener)
00989 {
00990   nsresult rv = NS_OK;
00991 
00992   PRBool isNewsServer = PR_FALSE;
00993   rv = GetIsServer(&isNewsServer);
00994   if (NS_FAILED(rv)) return rv;
00995   
00996   if (isNewsServer) 
00997     // get new messages only works on a newsgroup, not a news server
00998     return NS_OK;
00999 
01000   nsCOMPtr <nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
01001   NS_ENSURE_SUCCESS(rv,rv);
01002   
01003   nsCOMPtr<nsINntpIncomingServer> nntpServer;
01004   rv = GetNntpServer(getter_AddRefs(nntpServer));
01005   if (NS_FAILED(rv)) return rv;
01006   
01007   nsCOMPtr <nsIURI> resultUri;
01008   rv = nntpService->GetNewNews(nntpServer, mURI.get(), aGetOld, this,
01009                                aMsgWindow, getter_AddRefs(resultUri));
01010   if (aUrlListener && NS_SUCCEEDED(rv) && resultUri)
01011   {
01012     nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(resultUri));
01013     if (msgUrl)
01014       msgUrl->RegisterListener(aUrlListener);
01015   }
01016   return rv;
01017 }
01018 
01019 nsresult 
01020 nsMsgNewsFolder::LoadNewsrcFileAndCreateNewsgroups()
01021 {
01022   nsresult rv = NS_OK;
01023   if (!mNewsrcFilePath) return NS_ERROR_FAILURE;
01024 
01025   PRBool exists = PR_FALSE;
01026 
01027   rv = mNewsrcFilePath->Exists(&exists);
01028   if (NS_FAILED(rv)) return rv;
01029 
01030   if (!exists)
01031        // it is ok for the newsrc file to not exist yet
01032        return NS_OK;
01033 
01034   char *buffer = nsnull;
01035   rv = mNewsrcFilePath->OpenStreamForReading();
01036   NS_ENSURE_SUCCESS(rv,rv);
01037 
01038   PRInt32 numread = 0;
01039 
01040   if (NS_FAILED(m_newsrcInputStream.GrowBuffer(NEWSRC_FILE_BUFFER_SIZE))) 
01041     return NS_ERROR_FAILURE;
01042 
01043        
01044   while (1) 
01045   {
01046     buffer = m_newsrcInputStream.GetBuffer();
01047     rv = mNewsrcFilePath->Read(&buffer, NEWSRC_FILE_BUFFER_SIZE, &numread);
01048     NS_ENSURE_SUCCESS(rv,rv);
01049     if (numread == 0) {
01050       break;
01051     }
01052     else {
01053       rv = BufferInput(m_newsrcInputStream.GetBuffer(), numread);
01054       if (NS_FAILED(rv)) {
01055         break;
01056       }
01057     }
01058   }
01059 
01060   mNewsrcFilePath->CloseStream();
01061   
01062   return rv;
01063 }
01064 
01065 
01066 PRInt32
01067 nsMsgNewsFolder::HandleLine(char* line, PRUint32 line_size)
01068 {
01069        return HandleNewsrcLine(line, line_size);
01070 }
01071 
01072 PRInt32
01073 nsMsgNewsFolder::HandleNewsrcLine(char* line, PRUint32 line_size)
01074 {
01075   nsresult rv;
01076   
01077   /* guard against blank line lossage */
01078   if (line[0] == '#' || line[0] == nsCRT::CR || line[0] == nsCRT::LF) return 0;
01079   
01080   line[line_size] = 0;
01081   
01082   if ((line[0] == 'o' || line[0] == 'O') &&
01083     !PL_strncasecmp (line, "options", 7)) 
01084     return RememberLine(line);
01085   
01086   char *s = nsnull;
01087   char *setStr = nsnull;
01088   char *end = line + line_size;
01089   
01090   for (s = line; s < end; s++)
01091     if ((*s == ':') || (*s == '!'))
01092       break;
01093     
01094     if (*s == 0)
01095       /* What is this?? Well, don't just throw it away... */
01096       return RememberLine(line);
01097     
01098     PRBool subscribed = (*s == ':');
01099     setStr = s+1;
01100     *s = '\0';
01101     
01102     if (*line == '\0') 
01103       return 0;
01104     
01105   // previous versions of Communicator poluted the
01106   // newsrc files with articles
01107   // (this would happen when you clicked on a link like
01108   // news://news.mozilla.org/3746EF3F.6080309@netscape.com)
01109   //
01110   // legal newsgroup names can't contain @ or %
01111   // 
01112   // News group names are structured into parts separated by dots, 
01113   // for example "netscape.public.mozilla.mail-news". 
01114   // Each part may be up to 14 characters long, and should consist 
01115   // only of letters, digits, "+" and "-", with at least one letter
01116   //
01117   // @ indicates an article and %40 is @ escaped.
01118   // previous versions of Communicator also dumped
01119   // the escaped version into the newsrc file
01120   //
01121   // So lines like this in a newsrc file should be ignored:
01122   // 3746EF3F.6080309@netscape.com:
01123   // 3746EF3F.6080309%40netscape.com:
01124   if (PL_strstr(line,"@") || PL_strstr(line,"%40")) 
01125     // skipping, it contains @ or %40
01126     subscribed = PR_FALSE;
01127 
01128   if (subscribed) 
01129   {
01130     // we're subscribed, so add it
01131     nsCOMPtr <nsIMsgFolder> child;
01132     
01133     rv = AddNewsgroup(nsDependentCString(line), setStr, getter_AddRefs(child));
01134     
01135     if (NS_FAILED(rv)) return -1;
01136   }
01137   else {
01138     rv = RememberUnsubscribedGroup(line, setStr);
01139     if (NS_FAILED(rv)) return -1;
01140   }
01141 
01142   return 0;
01143 }
01144 
01145 
01146 nsresult
01147 nsMsgNewsFolder::RememberUnsubscribedGroup(const char *newsgroup, const char *setStr)
01148 {
01149   if (newsgroup) 
01150   {
01151     mUnsubscribedNewsgroupLines += newsgroup;
01152     mUnsubscribedNewsgroupLines += "! ";
01153     if (setStr) 
01154       mUnsubscribedNewsgroupLines += setStr;
01155     else
01156       mUnsubscribedNewsgroupLines += MSG_LINEBREAK;
01157   }
01158   return NS_OK;
01159 }
01160 
01161 PRInt32
01162 nsMsgNewsFolder::RememberLine(const char* line)
01163 {
01164   mOptionLines = line;
01165   mOptionLines += MSG_LINEBREAK;
01166   
01167   return 0;
01168 }
01169 
01170 nsresult nsMsgNewsFolder::ForgetLine()
01171 {
01172   mOptionLines = "";
01173   return NS_OK;
01174 }
01175 
01176 NS_IMETHODIMP nsMsgNewsFolder::GetGroupUsername(char **aGroupUsername)
01177 {
01178   NS_ENSURE_ARG_POINTER(aGroupUsername);
01179   nsresult rv;
01180   
01181   if (mGroupUsername) 
01182   {
01183     *aGroupUsername = nsCRT::strdup(mGroupUsername);
01184     rv = NS_OK;
01185   }
01186   else 
01187   {
01188     rv = NS_ERROR_FAILURE;
01189   }
01190   
01191   return rv;
01192 }
01193 
01194 NS_IMETHODIMP nsMsgNewsFolder::SetGroupUsername(const char *aGroupUsername)
01195 {
01196   PR_FREEIF(mGroupUsername);
01197   
01198   if (aGroupUsername) 
01199     mGroupUsername = nsCRT::strdup(aGroupUsername);
01200   
01201   return NS_OK;
01202 }
01203 
01204 NS_IMETHODIMP nsMsgNewsFolder::GetGroupPassword(char **aGroupPassword)
01205 {
01206     NS_ENSURE_ARG_POINTER(aGroupPassword);
01207     nsresult rv;
01208 
01209     if (mGroupPassword) 
01210     {
01211         *aGroupPassword = nsCRT::strdup(mGroupPassword);
01212         mPrevPassword = mGroupPassword;
01213         rv = NS_OK;
01214     }
01215     else 
01216     {
01217         rv = NS_ERROR_FAILURE;
01218     }
01219 
01220     return rv;      
01221 }
01222 
01223 NS_IMETHODIMP nsMsgNewsFolder::SetGroupPassword(const char *aGroupPassword)
01224 {
01225   PR_FREEIF(mGroupPassword);
01226   
01227   if (aGroupPassword) 
01228     mGroupPassword = nsCRT::strdup(aGroupPassword);
01229   
01230   return NS_OK;    
01231 }
01232 
01233 nsresult nsMsgNewsFolder::CreateNewsgroupUsernameUrlForSignon(const char *inUriStr, char **result)
01234 {
01235     return CreateNewsgroupUrlForSignon(inUriStr, "username", result);
01236 }
01237 
01238 nsresult nsMsgNewsFolder::CreateNewsgroupPasswordUrlForSignon(const char *inUriStr, char **result)
01239 {
01240     return CreateNewsgroupUrlForSignon(inUriStr, "password", result);
01241 }
01242 
01243 nsresult nsMsgNewsFolder::CreateNewsgroupUrlForSignon(const char *inUriStr, const char *ref, char **result)
01244 {
01245     nsresult rv;
01246     PRInt32 port = 0;
01247 
01248     nsCOMPtr<nsIURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
01249     NS_ENSURE_SUCCESS(rv,rv);
01250 
01251     nsCOMPtr<nsIMsgIncomingServer> server;
01252     rv = GetServer(getter_AddRefs(server));
01253     if (NS_FAILED(rv)) return rv;
01254 
01255     nsCOMPtr<nsINntpIncomingServer> nntpServer;
01256     rv = GetNntpServer(getter_AddRefs(nntpServer));
01257     if (NS_FAILED(rv)) return rv;
01258 
01259     PRBool singleSignon = PR_TRUE;
01260     rv = nntpServer->GetSingleSignon(&singleSignon);
01261 
01262     if (singleSignon)
01263     {
01264 
01265       nsXPIDLCString serverURI;
01266       rv = server->GetServerURI(getter_Copies(serverURI));
01267       if (NS_FAILED(rv)) return rv;
01268 
01269       rv = url->SetSpec(serverURI);
01270       if (NS_FAILED(rv)) return rv;
01271     }
01272     else
01273     {
01274     rv = url->SetSpec(nsDependentCString(inUriStr));
01275     if (NS_FAILED(rv)) return rv;
01276     }
01277 
01278     rv = url->GetPort(&port);
01279     if (NS_FAILED(rv)) return rv;
01280 
01281     if (port <= 0) 
01282     {
01283         nsCOMPtr<nsIMsgIncomingServer> server;
01284         rv = GetServer(getter_AddRefs(server));
01285         if (NS_FAILED(rv)) return rv;
01286 
01287         PRBool isSecure = PR_FALSE;
01288         rv = server->GetIsSecure(&isSecure);
01289         if (NS_FAILED(rv)) return rv;
01290 
01291         rv = url->SetPort((isSecure) ? SECURE_NEWS_PORT: NEWS_PORT);
01292         if (NS_FAILED(rv)) return rv;
01293     }
01294 
01295     rv = url->SetRef(nsDependentCString(ref));
01296     if (NS_FAILED(rv)) return rv;
01297 
01298     nsCAutoString spec;
01299     rv = url->GetSpec(spec);
01300     if (NS_FAILED(rv)) return rv;
01301 
01302     *result = ToNewCString(spec);
01303     return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
01304 }
01305 
01306 NS_IMETHODIMP nsMsgNewsFolder::ForgetGroupUsername()
01307 {
01308     nsresult rv;
01309     nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
01310     NS_ENSURE_SUCCESS(rv,rv);
01311 
01312     rv = SetGroupUsername(nsnull);
01313     if (NS_FAILED(rv)) return rv;
01314 
01315     nsXPIDLCString signonURL;
01316     rv = CreateNewsgroupUsernameUrlForSignon(mURI.get(), getter_Copies(signonURL));
01317     if (NS_FAILED(rv)) return rv;
01318 
01319     nsCOMPtr<nsIURI> uri;
01320     NS_NewURI(getter_AddRefs(uri), signonURL);
01321 
01322     //this is need to make sure wallet service has been created
01323     rv = CreateServicesForPasswordManager();
01324     NS_ENSURE_SUCCESS(rv, rv);
01325 
01326     rv = observerService->NotifyObservers(uri, "login-failed", nsnull);
01327     NS_ENSURE_SUCCESS(rv,rv);
01328     return rv;
01329 }
01330 
01331 NS_IMETHODIMP nsMsgNewsFolder::ForgetGroupPassword()
01332 {
01333     nsresult rv = NS_OK;
01334     nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
01335     NS_ENSURE_SUCCESS(rv,rv);
01336     rv = SetGroupPassword(nsnull);
01337     if (NS_FAILED(rv)) return rv;
01338 
01339     nsXPIDLCString signonURL;
01340     rv = CreateNewsgroupPasswordUrlForSignon(mURI.get(), getter_Copies(signonURL));
01341     if (NS_FAILED(rv)) return rv;
01342 
01343     nsCOMPtr<nsIURI> uri;
01344     NS_NewURI(getter_AddRefs(uri), signonURL);
01345 
01346     //this is need to make sure wallet service has been created
01347     rv = CreateServicesForPasswordManager();
01348     NS_ENSURE_SUCCESS(rv, rv);
01349 
01350     rv = observerService->NotifyObservers(uri, "login-failed", nsnull);
01351     NS_ENSURE_SUCCESS(rv,rv);
01352     return rv;
01353 }
01354 
01355 NS_IMETHODIMP
01356 nsMsgNewsFolder::GetGroupPasswordWithUI(const PRUnichar * aPromptMessage, const
01357                                        PRUnichar *aPromptTitle,
01358                                        nsIMsgWindow* aMsgWindow,
01359                                        char **aGroupPassword)
01360 {
01361   nsresult rv = NS_OK;
01362 
01363   NS_ENSURE_ARG_POINTER(aGroupPassword);
01364 
01365   if (!mGroupPassword) 
01366   {
01367     // prompt the user for the password
01368         
01369     nsCOMPtr<nsIAuthPrompt> dialog;
01370 #ifdef DEBUG_seth
01371     NS_ASSERTION(aMsgWindow,"no msg window");
01372 #endif
01373     if (aMsgWindow) 
01374     {
01375       nsCOMPtr<nsIDocShell> docShell;
01376 
01377       rv = aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
01378       if (NS_FAILED(rv)) return rv;
01379 
01380       dialog = do_GetInterface(docShell, &rv);
01381                      if (NS_FAILED(rv)) return rv;
01382     }
01383     else 
01384     {
01385       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
01386       if (wwatch)
01387         wwatch->GetNewAuthPrompter(0, getter_AddRefs(dialog));
01388 
01389       if (!dialog) return NS_ERROR_FAILURE;
01390     }
01391 
01392     NS_ASSERTION(dialog,"we didn't get a net prompt");
01393     if (dialog) 
01394     {
01395       PRBool okayValue = PR_TRUE;
01396             
01397       nsXPIDLCString signonURL;
01398       rv = CreateNewsgroupPasswordUrlForSignon(mURI.get(), getter_Copies(signonURL));
01399       if (NS_FAILED(rv)) return rv;
01400 
01401       PRUnichar *uniGroupPassword = nsnull;
01402       if (!mPrevPassword.IsEmpty())
01403         uniGroupPassword = ToNewUnicode(NS_ConvertASCIItoUTF16(mPrevPassword));
01404 
01405        rv = dialog->PromptPassword(aPromptTitle, aPromptMessage, NS_ConvertASCIItoUTF16(NS_STATIC_CAST(const char*, signonURL)).get(), nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
01406                                    &uniGroupPassword, &okayValue);
01407       nsAutoString uniPasswordAdopted;
01408       uniPasswordAdopted.Adopt(uniGroupPassword);
01409       if (NS_FAILED(rv)) return rv;
01410 
01411       if (!okayValue) // if the user pressed cancel, just return NULL;
01412       {
01413         *aGroupPassword = nsnull;
01414         return rv;
01415       }
01416 
01417       // we got a password back...so remember it
01418       rv = SetGroupPassword(NS_LossyConvertUTF16toASCII(uniPasswordAdopted).get());
01419       if (NS_FAILED(rv)) return rv;
01420 
01421     } // if we got a prompt dialog
01422   } // if the password is empty
01423 
01424   return GetGroupPassword(aGroupPassword);
01425 }
01426 
01427 NS_IMETHODIMP
01428 nsMsgNewsFolder::GetGroupUsernameWithUI(const PRUnichar * aPromptMessage, const
01429                                        PRUnichar *aPromptTitle,
01430                                        nsIMsgWindow* aMsgWindow,
01431                                        char **aGroupUsername)
01432 {
01433   nsresult rv = NS_ERROR_FAILURE;
01434   
01435   NS_ENSURE_ARG_POINTER(aGroupUsername);
01436   
01437   if (!mGroupUsername) 
01438   {
01439     // prompt the user for the username
01440     
01441     nsCOMPtr<nsIAuthPrompt> dialog;
01442 #ifdef DEBUG_seth
01443     NS_ASSERTION(aMsgWindow,"no msg window");
01444 #endif
01445     if (aMsgWindow) 
01446     {
01447       // prompt the user for the password
01448       nsCOMPtr<nsIDocShell> docShell;
01449       rv = aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
01450       if (NS_FAILED(rv)) return rv;
01451       dialog = do_GetInterface(docShell, &rv);
01452       if (NS_FAILED(rv)) return rv;
01453     }
01454     else 
01455     {
01456       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
01457       if (wwatch)
01458         wwatch->GetNewAuthPrompter(0, getter_AddRefs(dialog));
01459       
01460       if (!dialog) return NS_ERROR_FAILURE;
01461     }
01462     
01463     NS_ASSERTION(dialog,"we didn't get a net prompt");
01464     if (dialog) 
01465     {
01466       nsXPIDLString uniGroupUsername;
01467       
01468       PRBool okayValue = PR_TRUE;
01469       
01470       nsXPIDLCString signonURL;
01471       rv = CreateNewsgroupUsernameUrlForSignon(mURI.get(), getter_Copies(signonURL));
01472       if (NS_FAILED(rv)) return rv;
01473       
01474       rv = dialog->Prompt(aPromptTitle, aPromptMessage, NS_ConvertASCIItoUCS2(signonURL).get(), 
01475         nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, NS_ConvertASCIItoUTF16(mPrevUsername).get(),
01476         getter_Copies(uniGroupUsername), &okayValue);
01477       if (NS_FAILED(rv)) return rv;
01478       
01479       if (!okayValue) // if the user pressed cancel, just return NULL;
01480       {
01481         *aGroupUsername= nsnull;
01482         return rv;
01483       }
01484       
01485       // we got a username back, remember it
01486       rv = SetGroupUsername(NS_LossyConvertUCS2toASCII(uniGroupUsername).get());
01487       if (NS_FAILED(rv)) return rv;
01488       
01489     } // if we got a prompt dialog
01490   } // if the password is empty
01491   
01492   rv = GetGroupUsername(aGroupUsername);
01493   mPrevUsername.Assign(*aGroupUsername);
01494   return rv;
01495 }
01496 
01497 nsresult nsMsgNewsFolder::CreateBaseMessageURI(const char *aURI)
01498 {
01499   nsresult rv;
01500 
01501   rv = nsCreateNewsBaseMessageURI(aURI, &mBaseMessageURI);
01502   return rv;
01503 }
01504 
01505 NS_IMETHODIMP
01506 nsMsgNewsFolder::GetNewsrcLine(char **newsrcLine)
01507 {
01508   nsresult rv;
01509   
01510   if (!newsrcLine) return NS_ERROR_NULL_POINTER;
01511   
01512   nsXPIDLString newsgroupNameUtf16;
01513   rv = GetName(getter_Copies(newsgroupNameUtf16));
01514   if (NS_FAILED(rv)) return rv;
01515   NS_ConvertUTF16toUTF8 newsgroupName(newsgroupNameUtf16);
01516 
01517   nsCAutoString newsrcLineStr;
01518   newsrcLineStr = newsgroupName;
01519   newsrcLineStr += ':';
01520   
01521   if (mReadSet) {
01522     nsXPIDLCString setStr;
01523     mReadSet->Output(getter_Copies(setStr));
01524     if (NS_SUCCEEDED(rv)) 
01525     {
01526       newsrcLineStr += ' ';
01527       newsrcLineStr += setStr;
01528       newsrcLineStr.AppendLiteral(MSG_LINEBREAK);
01529     }
01530   }
01531   
01532   *newsrcLine = ToNewCString(newsrcLineStr);
01533   
01534   if (!*newsrcLine) return NS_ERROR_OUT_OF_MEMORY;
01535   
01536   return NS_OK;
01537 }
01538 
01539 NS_IMETHODIMP nsMsgNewsFolder::SetReadSetFromStr(const char *newsrcLine)
01540 {
01541   if (!newsrcLine) return NS_ERROR_NULL_POINTER;
01542 
01543   delete mReadSet;
01544 
01545   mReadSet = nsMsgKeySet::Create(newsrcLine);
01546 
01547   if (!mReadSet) return NS_ERROR_OUT_OF_MEMORY;
01548 
01549   // Now that mReadSet is recreated, make sure it's stored in the db as well.
01550   nsCOMPtr<nsINewsDatabase> db = do_QueryInterface(mDatabase);
01551   if (db) // it's ok not to have a db here.
01552     db->SetReadSet(mReadSet);
01553 
01554   return NS_OK;
01555 }
01556 
01557 NS_IMETHODIMP
01558 nsMsgNewsFolder::GetUnsubscribedNewsgroupLines(char **aUnsubscribedNewsgroupLines)
01559 {
01560     if (!aUnsubscribedNewsgroupLines) return NS_ERROR_NULL_POINTER;
01561 
01562     if (!mUnsubscribedNewsgroupLines.IsEmpty())
01563         *aUnsubscribedNewsgroupLines= ToNewCString(mUnsubscribedNewsgroupLines);
01564     
01565     return NS_OK;
01566 }
01567 
01568 NS_IMETHODIMP
01569 nsMsgNewsFolder::GetOptionLines(char **optionLines)
01570 {
01571     if (!optionLines) return NS_ERROR_NULL_POINTER;
01572 
01573     if (!mOptionLines.IsEmpty()) 
01574         *optionLines = ToNewCString(mOptionLines);
01575     
01576     return NS_OK;
01577 }
01578 
01579 NS_IMETHODIMP
01580 nsMsgNewsFolder::OnReadChanged(nsIDBChangeListener * aInstigator)
01581 {
01582     return SetNewsrcHasChanged(PR_TRUE);
01583 }
01584 
01585 NS_IMETHODIMP
01586 nsMsgNewsFolder::GetUnicodeName(nsAString & aName)
01587 {
01588   nsXPIDLString newsgroupName;
01589   nsresult rv = GetName(getter_Copies(newsgroupName));
01590   if (NS_SUCCEEDED(rv))
01591     aName = newsgroupName;
01592   return rv;
01593 }
01594 
01595 NS_IMETHODIMP
01596 nsMsgNewsFolder::GetRawName(nsACString & aRawName)
01597 {
01598   nsresult rv;
01599   if (mRawName.IsEmpty()) 
01600   {
01601     nsXPIDLString name;
01602     rv = GetName(getter_Copies(name));
01603     NS_ENSURE_SUCCESS(rv,rv);
01604     
01605     // convert to the server-side encoding 
01606     nsCAutoString tmpStr;
01607     nsCOMPtr <nsINntpIncomingServer> nntpServer;
01608     rv = GetNntpServer(getter_AddRefs(nntpServer));
01609     NS_ENSURE_SUCCESS(rv,rv);
01610     
01611     nsCAutoString dataCharset;
01612     rv = nntpServer->GetCharset(dataCharset);
01613     NS_ENSURE_SUCCESS(rv,rv);
01614     rv = nsMsgI18NConvertFromUnicode(dataCharset.get(), name, tmpStr);
01615 
01616     if (NS_FAILED(rv)) {
01617       LossyCopyUTF16toASCII(name,tmpStr);
01618     }
01619     
01620     mRawName = tmpStr;
01621   }
01622   
01623   aRawName = mRawName;
01624   
01625   return NS_OK;
01626 }
01627 
01628 NS_IMETHODIMP
01629 nsMsgNewsFolder::GetNntpServer(nsINntpIncomingServer **result)
01630 {
01631     nsresult rv;
01632     NS_ENSURE_ARG_POINTER(result);
01633 
01634     nsCOMPtr<nsIMsgIncomingServer> server;
01635     rv = GetServer(getter_AddRefs(server));
01636     if (NS_FAILED(rv)) 
01637       return rv;
01638 
01639     if (!server) 
01640       return NS_ERROR_NULL_POINTER;
01641 
01642     nsCOMPtr<nsINntpIncomingServer> nntpServer;
01643     rv = server->QueryInterface(NS_GET_IID(nsINntpIncomingServer),
01644                                 getter_AddRefs(nntpServer));
01645     if (NS_FAILED(rv)) 
01646       return rv;
01647 
01648     NS_IF_ADDREF(*result = nntpServer);
01649     return NS_OK;
01650 }
01651 
01652 // this gets called after the message actually gets cancelled
01653 // it removes the cancelled message from the db
01654 NS_IMETHODIMP nsMsgNewsFolder::RemoveMessage(nsMsgKey key)
01655 {
01656   nsresult rv = GetDatabase(nsnull);
01657   NS_ENSURE_SUCCESS(rv, rv); // if GetDatabase succeeds, mDatabase will be non-null
01658   return mDatabase->DeleteMessage(key, nsnull, PR_FALSE);
01659 }
01660 
01661 NS_IMETHODIMP nsMsgNewsFolder::CancelComplete()
01662 {
01663   NotifyFolderEvent(mDeleteOrMoveMsgCompletedAtom);
01664   return NS_OK;
01665 }
01666 
01667 NS_IMETHODIMP nsMsgNewsFolder::CancelFailed()
01668 {
01669   NotifyFolderEvent(mDeleteOrMoveMsgFailedAtom);
01670   return NS_OK;
01671 }
01672 
01673 NS_IMETHODIMP nsMsgNewsFolder::GetSaveArticleOffline(PRBool *aBool)
01674 {
01675   NS_ENSURE_ARG(aBool);
01676   *aBool = m_downloadMessageForOfflineUse;
01677   return NS_OK;
01678 }
01679 
01680 NS_IMETHODIMP nsMsgNewsFolder::SetSaveArticleOffline(PRBool aBool)
01681 {
01682   m_downloadMessageForOfflineUse = aBool;
01683   return NS_OK;
01684 }
01685 
01686 NS_IMETHODIMP nsMsgNewsFolder::DownloadAllForOffline(nsIUrlListener *listener, nsIMsgWindow *msgWindow)
01687 {
01688   nsMsgKeyArray srcKeyArray;
01689 
01690   SetSaveArticleOffline(PR_TRUE); 
01691   nsresult rv;
01692 
01693   // build up message keys.
01694   if (mDatabase)
01695   {
01696     nsCOMPtr <nsISimpleEnumerator> enumerator;
01697     rv = mDatabase->EnumerateMessages(getter_AddRefs(enumerator));
01698     if (NS_SUCCEEDED(rv) && enumerator)
01699     {
01700       PRBool hasMore;
01701 
01702       while (NS_SUCCEEDED(rv = enumerator->HasMoreElements(&hasMore)) && hasMore) 
01703       {
01704         nsCOMPtr <nsIMsgDBHdr> pHeader;
01705         rv = enumerator->GetNext(getter_AddRefs(pHeader));
01706         NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
01707         if (pHeader && NS_SUCCEEDED(rv))
01708         {
01709           PRBool shouldStoreMsgOffline = PR_FALSE;
01710           nsMsgKey msgKey;
01711           pHeader->GetMessageKey(&msgKey);
01712           MsgFitsDownloadCriteria(msgKey, &shouldStoreMsgOffline);
01713           if (shouldStoreMsgOffline)
01714             srcKeyArray.Add(msgKey);
01715         }
01716       }
01717     }
01718   }
01719   DownloadNewsArticlesToOfflineStore *downloadState = new DownloadNewsArticlesToOfflineStore(msgWindow, mDatabase, this);
01720   if (!downloadState)
01721     return NS_ERROR_OUT_OF_MEMORY;
01722 
01723   m_downloadingMultipleMessages = PR_TRUE;
01724 
01725   return downloadState->DownloadArticles(msgWindow, this, &srcKeyArray);
01726 }
01727 
01728 NS_IMETHODIMP nsMsgNewsFolder::DownloadMessagesForOffline(nsISupportsArray *messages, nsIMsgWindow *window)
01729 {
01730   nsMsgKeyArray srcKeyArray;
01731 
01732   SetSaveArticleOffline(PR_TRUE); // ### TODO need to clear this when we've finished
01733   PRUint32 count = 0;
01734   PRUint32 i;
01735   nsresult rv = messages->Count(&count);
01736   NS_ENSURE_SUCCESS(rv, rv);
01737 
01738   // build up message keys.
01739   for (i = 0; i < count; i++)
01740   {
01741     nsMsgKey key;
01742     nsCOMPtr <nsIMsgDBHdr> msgDBHdr = do_QueryElementAt(messages, i, &rv);
01743     if (msgDBHdr)
01744       rv = msgDBHdr->GetMessageKey(&key);
01745     if (NS_SUCCEEDED(rv))
01746       srcKeyArray.Add(key);
01747   }
01748   DownloadNewsArticlesToOfflineStore *downloadState = new DownloadNewsArticlesToOfflineStore(window, mDatabase, this);
01749   if (!downloadState)
01750     return NS_ERROR_OUT_OF_MEMORY;
01751 
01752   m_downloadingMultipleMessages = PR_TRUE;
01753 
01754   return downloadState->DownloadArticles(window, this, &srcKeyArray);
01755 }
01756 
01757 // line does not have a line terminator (e.g., CR or CRLF)
01758 NS_IMETHODIMP nsMsgNewsFolder::NotifyDownloadedLine(const char *line, nsMsgKey keyOfArticle)
01759 {
01760   nsresult rv = NS_OK;
01761   if (m_downloadMessageForOfflineUse && !m_offlineHeader)
01762   {
01763     GetMessageHeader(keyOfArticle, getter_AddRefs(m_offlineHeader));
01764     rv = StartNewOfflineMessage();
01765   }
01766 
01767   m_numOfflineMsgLines++;
01768 
01769   if (m_tempMessageStream)
01770   {
01771     // line now contains the linebreak.
01772     if (line[0] == '.' && line[MSG_LINEBREAK_LEN + 1] == 0)
01773     {
01774       // end of article.
01775       if (m_offlineHeader)
01776         EndNewOfflineMessage();
01777 
01778       if (m_tempMessageStream && !m_downloadingMultipleMessages)
01779       {
01780         m_tempMessageStream->Close();
01781         m_tempMessageStream = nsnull;
01782       }
01783     }
01784     else
01785     {
01786       PRUint32 count = 0;
01787       rv = m_tempMessageStream->Write(line, 
01788            strlen(line), &count);
01789       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to write to stream");
01790     }
01791   }
01792                                                                                 
01793   return rv;
01794 }
01795 
01796 NS_IMETHODIMP nsMsgNewsFolder::NotifyFinishedDownloadinghdrs()
01797 {
01798   ChangeNumPendingTotalMessages(-GetNumPendingTotalMessages());
01799   ChangeNumPendingUnread(-GetNumPendingUnread());
01800   return NS_OK;  
01801 }
01802 
01803 NS_IMETHODIMP nsMsgNewsFolder::Compact(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow)
01804 {
01805   nsresult rv;
01806 
01807   rv = GetDatabase(nsnull);
01808   if (mDatabase)
01809     ApplyRetentionSettings();
01810   return rv;
01811 }
01812 
01813 NS_IMETHODIMP
01814 nsMsgNewsFolder::ApplyRetentionSettings()
01815 {
01816   return nsMsgDBFolder::ApplyRetentionSettings(PR_FALSE);
01817 }
01818 
01819 
01820 NS_IMETHODIMP nsMsgNewsFolder::GetMessageIdForKey(nsMsgKey key, char **result)
01821 {
01822   nsresult rv = GetDatabase(nsnull);
01823 
01824   if (!mDatabase) return rv;
01825 
01826   nsCOMPtr <nsIMsgDBHdr> hdr;
01827   rv = mDatabase->GetMsgHdrForKey(key, getter_AddRefs(hdr));
01828   NS_ENSURE_SUCCESS(rv,rv);
01829   if (!hdr) return NS_ERROR_INVALID_ARG;
01830 
01831   return hdr->GetMessageId(result);
01832 }
01833 
01834 NS_IMETHODIMP nsMsgNewsFolder::SetSortOrder(PRInt32 order)
01835 {
01836   mSortOrder = order;
01837   return NS_OK;
01838 }
01839 
01840 NS_IMETHODIMP nsMsgNewsFolder::GetSortOrder(PRInt32 *order)
01841 {
01842   NS_ENSURE_ARG_POINTER(order);
01843   *order = mSortOrder;
01844   return NS_OK;
01845 }
01846 
01847 NS_IMETHODIMP nsMsgNewsFolder::GetPersistElided(PRBool *aPersistElided)
01848 {
01849   nsresult rv;
01850 
01851   PRBool isNewsServer = PR_FALSE;
01852   rv = GetIsServer(&isNewsServer);
01853   NS_ENSURE_SUCCESS(rv,rv);
01854  
01855   // persist the open / closed state, if not a server
01856   // this doesn't matter right now, but it will if we ever add categories
01857   if (!isNewsServer) 
01858   {
01859     *aPersistElided = PR_TRUE;
01860     return NS_OK;
01861   }
01862 
01863   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01864   NS_ENSURE_SUCCESS(rv,rv);
01865 
01866   rv = prefBranch->GetBoolPref("news.persist_server_open_state_in_folderpane", aPersistElided);
01867   NS_ENSURE_SUCCESS(rv,rv);
01868   return rv;
01869 }
01870 
01871 NS_IMETHODIMP nsMsgNewsFolder::Shutdown(PRBool shutdownChildren)
01872 {
01873   if (mFilterList) 
01874   {
01875     // close the filter log stream
01876     nsresult rv = mFilterList->SetLogStream(nsnull);
01877     NS_ENSURE_SUCCESS(rv,rv);
01878     mFilterList = nsnull;
01879   }
01880 
01881   mInitialized = PR_FALSE;
01882   if (mReadSet) {
01883     // the nsINewsDatabase holds a weak ref to the readset,
01884     // and we outlive the db, so it's safe to delete it here.
01885     nsCOMPtr<nsINewsDatabase> db = do_QueryInterface(mDatabase);
01886     if (db)
01887       db->SetReadSet(nsnull);
01888     delete mReadSet;
01889     mReadSet = nsnull;
01890   }
01891 
01892   return nsMsgDBFolder::Shutdown(shutdownChildren);
01893 }
01894 
01895 NS_IMETHODIMP
01896 nsMsgNewsFolder::SetFilterList(nsIMsgFilterList *aFilterList)
01897 {
01898   if (mIsServer)
01899   {
01900     nsCOMPtr<nsIMsgIncomingServer> server;
01901     nsresult rv = GetServer(getter_AddRefs(server));
01902     NS_ENSURE_SUCCESS(rv,rv);
01903     return server->SetFilterList(aFilterList);
01904   }
01905 
01906   mFilterList = aFilterList;
01907   return NS_OK;
01908 }
01909 
01910 NS_IMETHODIMP
01911 nsMsgNewsFolder::GetFilterList(nsIMsgWindow *aMsgWindow, nsIMsgFilterList **aResult)
01912 {
01913   if (mIsServer)
01914   {
01915     nsCOMPtr<nsIMsgIncomingServer> server;
01916     nsresult rv = GetServer(getter_AddRefs(server));
01917     NS_ENSURE_SUCCESS(rv,rv);
01918     return server->GetFilterList(aMsgWindow, aResult);
01919   }
01920 
01921   if (!mFilterList) 
01922   {
01923     nsCOMPtr<nsIFileSpec> thisFolder;
01924     nsresult rv = GetPath(getter_AddRefs(thisFolder));
01925     NS_ENSURE_SUCCESS(rv, rv);
01926     
01927     mFilterFile = do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
01928     NS_ENSURE_SUCCESS(rv, rv);
01929     
01930     // in 4.x, the news filter file was
01931     // C:\Program Files\Netscape\Users\meer\News\host-news.mcom.com\mcom.test.dat
01932     // where the summary file was 
01933     // C:\Program Files\Netscape\Users\meer\News\host-news.mcom.com\mcom.test.snm
01934     // we make the rules file ".dat" in mozilla, so that migration works.
01935     rv = mFilterFile->FromFileSpec(thisFolder);
01936     NS_ENSURE_SUCCESS(rv, rv);
01937     
01938     // NOTE:
01939     // we don't we need to call NS_MsgHashIfNecessary()
01940     // it's already been hashed, if necessary
01941     nsXPIDLCString filterFileName;
01942     rv = mFilterFile->GetLeafName(getter_Copies(filterFileName));
01943     NS_ENSURE_SUCCESS(rv,rv);
01944     
01945     filterFileName.Append(".dat");
01946     
01947     rv = mFilterFile->SetLeafName(filterFileName.get());
01948     NS_ENSURE_SUCCESS(rv,rv);
01949     
01950     nsCOMPtr<nsIMsgFilterService> filterService =
01951       do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
01952     NS_ENSURE_SUCCESS(rv, rv);
01953     
01954     rv = filterService->OpenFilterList(mFilterFile, this, aMsgWindow, getter_AddRefs(mFilterList));
01955     NS_ENSURE_SUCCESS(rv, rv);
01956   }
01957   
01958   NS_IF_ADDREF(*aResult = mFilterList);
01959   return NS_OK;
01960 }
01961 
01962 NS_IMETHODIMP
01963 nsMsgNewsFolder::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
01964 {
01965  if (m_tempMessageStream)
01966   {
01967     m_tempMessageStream->Close();
01968     m_tempMessageStream = nsnull;
01969   }
01970   m_downloadingMultipleMessages = PR_FALSE;
01971   return nsMsgDBFolder::OnStopRunningUrl(aUrl, aExitCode);
01972 }