From b4e142b8f122bc26330a38e97b4d79cc3ff985d6 Mon Sep 17 00:00:00 2001 From: "sspitzer%netscape.com" Date: Tue, 20 Apr 1999 19:08:10 +0000 Subject: [PATCH] changes to get news in the folder pane --- mailnews/base/public/msgCore.h | 1 + mailnews/base/public/nsIMsgFolder.h | 18 + mailnews/base/public/nsIMsgFolder.idl | 4 + mailnews/base/util/nsMsgFolder.cpp | 26 +- mailnews/db/msgdb/src/nsNewsDatabase.cpp | 4 +- mailnews/local/build/nsMsgLocalCID.h | 2 +- mailnews/local/build/nsMsgLocalFactory.cpp | 10 +- mailnews/local/src/nsLocalMailFolder.h | 2 +- mailnews/local/src/nsMailboxUrl.cpp | 1 + mailnews/news/build/MANIFEST | 18 + mailnews/news/build/Makefile.in | 1 + mailnews/news/build/nsMsgNewsCID.h | 34 + mailnews/news/build/nsMsgNewsFactory.cpp | 93 +- mailnews/news/public/nsINntpUrl.h | 6 +- mailnews/news/src/Makefile.in | 2 + mailnews/news/src/nsNewsFolder.cpp | 957 ++++++++++++++++++ mailnews/news/src/nsNewsFolder.h | 133 +++ mailnews/news/src/nsNntpService.h | 9 +- mailnews/news/src/nsNntpUrl.cpp | 25 + mailnews/news/src/nsNntpUrl.h | 27 +- .../ui/messenger/resources/commandglue.js | 4 +- .../ui/messenger/resources/folderPane.xul | 10 +- 22 files changed, 1334 insertions(+), 53 deletions(-) create mode 100644 mailnews/news/build/MANIFEST create mode 100644 mailnews/news/build/nsMsgNewsCID.h create mode 100644 mailnews/news/src/nsNewsFolder.cpp create mode 100644 mailnews/news/src/nsNewsFolder.h diff --git a/mailnews/base/public/msgCore.h b/mailnews/base/public/msgCore.h index 30c4c38ad563..756d9828ea08 100644 --- a/mailnews/base/public/msgCore.h +++ b/mailnews/base/public/msgCore.h @@ -133,6 +133,7 @@ static const char kMailboxMessageRootURI[] = "mailbox_message:/"; static const char kNewsRootURI[] = "news:/"; static const char kNewsMessageRootURI[] = "news_message:/"; + static const char kImapMessageRootURI[] = "imap_message:/"; extern nsresult diff --git a/mailnews/base/public/nsIMsgFolder.h b/mailnews/base/public/nsIMsgFolder.h index 13de28e1c32d..76284174ecd2 100644 --- a/mailnews/base/public/nsIMsgFolder.h +++ b/mailnews/base/public/nsIMsgFolder.h @@ -231,6 +231,24 @@ class nsIMsgLocalMailFolder : public nsISupports { #endif }; +/* starting interface: nsIMsgNewsFolder */ + +/* {3716abe4-f6d4-11d2-86d5-004005263078} */ +#define NS_IMSGNEWSFOLDER_IID_STR "3716abe4-f6d4-11d2-86d5-004005263078" +#define NS_IMSGNEWSFOLDER_IID \ + {0x3716abe4, 0xf6d4, 0x11d2, \ + { 0x86, 0xd5, 0x00, 0x40, 0x05, 0x26, 0x30, 0x78 }} + +class nsIMsgNewsFolder : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IMSGNEWSFOLDER_IID) + +#ifdef XPIDL_JS_STUBS + static NS_EXPORT_(JSObject *) InitJSClass(JSContext *cx); + static NS_EXPORT_(JSObject *) GetJSObject(JSContext *cx, nsIMsgNewsFolder *priv); +#endif +}; + /* starting interface: nsIMsgImapMailFolder */ /* {FBFEBE79-C1DD-11d2-8A40-0060B0FC04D2} */ diff --git a/mailnews/base/public/nsIMsgFolder.idl b/mailnews/base/public/nsIMsgFolder.idl index c69b5584aa79..3347d1e6da8c 100644 --- a/mailnews/base/public/nsIMsgFolder.idl +++ b/mailnews/base/public/nsIMsgFolder.idl @@ -129,6 +129,10 @@ interface nsIMsgLocalMailFolder : nsISupports { }; +[uuid(3716abe4-f6d4-11d2-86d5-004005263078)] +interface nsIMsgNewsFolder : nsISupports { + +}; [uuid(FBFEBE79-C1DD-11d2-8A40-0060B0FC04D2)] interface nsIMsgImapMailFolder : nsISupports { diff --git a/mailnews/base/util/nsMsgFolder.cpp b/mailnews/base/util/nsMsgFolder.cpp index c47cde9b4e28..638c2cd3bc1c 100644 --- a/mailnews/base/util/nsMsgFolder.cpp +++ b/mailnews/base/util/nsMsgFolder.cpp @@ -1527,10 +1527,11 @@ nsURI2Path(const char* rootURI, const char* uriStr, nsFileSpec& pathResult) { nsresult rv; -#ifdef DEBUG_sspitzer_ +#ifdef DEBUG_sspitzer /* examples: */ /* nsURI2Path(mailbox:/, mailbox:/, ??)->/home/sspitzer/mozillamail */ /* nsURI2Path(mailbox:/, mailbox://Drafts, ??)->/home/sspitzer/mozillamail/Drafts */ + /* nsURI2Path(news:/, news:/, ??)->/home/sspitzer/mozillanews */ printf("nsURI2Path(%s, %s, ??)", rootURI, uriStr); #endif @@ -1546,14 +1547,24 @@ nsURI2Path(const char* rootURI, const char* uriStr, nsFileSpec& pathResult) if (uri.Find(rootURI) != 0) // if doesn't start with rootURI return NS_ERROR_FAILURE; - if (strcmp(rootURI, kNewsMessageRootURI) == 0) { + /* sspitzer: yes, this is inefficent. it may be going away + * if not, I'll make it more efficient later. */ + if ((strcmp(rootURI, kMailboxRootURI) == 0) || + (strcmp(rootURI, kMailboxMessageRootURI) == 0)) { + // local mail case + rv = nsGetMailboxRoot(pathResult); + } + else if ((strcmp(rootURI, kNewsMessageRootURI) == 0) || + (strcmp(rootURI, kNewsRootURI) == 0)) { + // news case rv = nsGetNewsRoot(pathResult); } else if (strcmp(rootURI, kImapMessageRootURI) == 0) { + // imap case rv = nsGetImapRoot(pathResult); } else { - rv = nsGetMailboxRoot(pathResult); + rv = NS_ERROR_FAILURE; } if (NS_FAILED(rv)) { @@ -1606,7 +1617,7 @@ nsURI2Path(const char* rootURI, const char* uriStr, nsFileSpec& pathResult) if(path.Length() > 0) pathResult +=path; -#ifdef DEBUG_sspitzer_ +#ifdef DEBUG_sspitzer printf("->%s\n", (const char *)pathResult); #endif return NS_OK; @@ -1617,7 +1628,7 @@ nsPath2URI(const char* rootURI, const nsFileSpec& spec, char **uri) { nsresult rv; -#ifdef DEBUG_sspitzer_ +#ifdef DEBUG_sspitzer /* examples: */ /* nsPath2URI(mailbox_message:/, /home/sspitzer/mozillamail/Drafts, ??)->mailbox_message://Drafts */ /* nsPath2URI(news_message:/, /tmp/mozillanews/news.mozilla.org/netscape.public.mozilla.unix, ??)->news_message://news.mozilla.org/netscape.public.mozilla.unix */ @@ -1638,7 +1649,8 @@ nsPath2URI(const char* rootURI, const nsFileSpec& spec, char **uri) else if (strcmp(rootURI, kImapMessageRootURI) == 0) { rv = nsGetImapRoot(root); } - else { + else { + // local mail case rv = nsGetMailboxRoot(root); } if (NS_FAILED(rv)) return rv; @@ -1687,7 +1699,7 @@ nsPath2URI(const char* rootURI, const nsFileSpec& spec, char **uri) uriStr += folderName; } *uri = uriStr.ToNewCString(); -#ifdef DEBUG_sspitzer_ +#ifdef DEBUG_sspitzer printf("->%s\n", *uri); #endif return NS_OK; diff --git a/mailnews/db/msgdb/src/nsNewsDatabase.cpp b/mailnews/db/msgdb/src/nsNewsDatabase.cpp index 1c2c75677e23..4b66eedc842f 100644 --- a/mailnews/db/msgdb/src/nsNewsDatabase.cpp +++ b/mailnews/db/msgdb/src/nsNewsDatabase.cpp @@ -265,12 +265,12 @@ nsNewsDatabase::CreateMsgHdr(nsIMdbRow* hdrRow, nsFileSpec& path, nsMsgKey key, char* msgURI; - //Need to remove ".nsf". + //Need to remove ".msf". (msf = message summary file) nsFileSpec folderPath = path; char* leafName = folderPath.GetLeafName(); nsString folderName(leafName); PL_strfree(leafName); - if(folderName.Find(".nsf") != -1) + if(folderName.Find(".msf") != -1) { nsString realFolderName; folderName.Left(realFolderName, folderName.Length() - 4); diff --git a/mailnews/local/build/nsMsgLocalCID.h b/mailnews/local/build/nsMsgLocalCID.h index 0a769ca99402..47523584650b 100644 --- a/mailnews/local/build/nsMsgLocalCID.h +++ b/mailnews/local/build/nsMsgLocalCID.h @@ -23,7 +23,7 @@ #include "nsIFactory.h" #include "nsIComponentManager.h" -#define NS_MAILNEWSRESOURCE_CID \ +#define NS_LOCALMAILFOLDERRESOURCE_CID \ { /* e490d22c-cd67-11d2-8cca-0060b0fc14a3 */ \ 0xe490d22c, \ 0xcd67, \ diff --git a/mailnews/local/build/nsMsgLocalFactory.cpp b/mailnews/local/build/nsMsgLocalFactory.cpp index 1221482e5773..272bce56ee3e 100644 --- a/mailnews/local/build/nsMsgLocalFactory.cpp +++ b/mailnews/local/build/nsMsgLocalFactory.cpp @@ -37,7 +37,7 @@ static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_CID(kMailboxUrlCID, NS_MAILBOXURL_CID); static NS_DEFINE_CID(kMailboxParserCID, NS_MAILBOXPARSER_CID); static NS_DEFINE_CID(kMailboxServiceCID, NS_MAILBOXSERVICE_CID); -static NS_DEFINE_CID(kMailNewsLocalResourceCID, NS_MAILNEWSRESOURCE_CID); +static NS_DEFINE_CID(kLocalMailFolderResourceCID, NS_LOCALMAILFOLDERRESOURCE_CID); static NS_DEFINE_CID(kPop3ServiceCID, NS_POP3SERVICE_CID); static NS_DEFINE_CID(kPop3UrlCID, NS_POP3URL_CID); static NS_DEFINE_CID(kPop3IncomingServerCID, NS_POP3INCOMINGSERVER_CID); @@ -173,7 +173,7 @@ nsresult nsMsgLocalFactory::CreateInstance(nsISupports *aOuter, const nsIID &aII if (NS_FAILED(rv) && popService) delete popService; } - else if (mClassID.Equals(kMailNewsLocalResourceCID)) + else if (mClassID.Equals(kLocalMailFolderResourceCID)) { nsMsgLocalMailFolder * localFolder = new nsMsgLocalMailFolder(); if (localFolder) @@ -263,8 +263,8 @@ NSRegisterSelf(nsISupports* aServMgr, const char* path) if (NS_FAILED(rv)) goto done; // register our RDF resource factories: - rv = compMgr->RegisterComponent(kMailNewsLocalResourceCID, - "Mail/News Local Resource Factory", + rv = compMgr->RegisterComponent(kLocalMailFolderResourceCID, + "Local Mail Folder Resource Factory", NS_RDF_RESOURCE_FACTORY_PROGID_PREFIX "mailbox", path, PR_TRUE, PR_TRUE); if (NS_FAILED(rv)) goto done; @@ -310,7 +310,7 @@ NSUnregisterSelf(nsISupports* aServMgr, const char* path) rv = compMgr->UnregisterFactory(kMailboxParserCID, path); if (NS_FAILED(rv)) goto done; - rv = compMgr->UnregisterComponent(kMailNewsLocalResourceCID, path); + rv = compMgr->UnregisterComponent(kLocalMailFolderResourceCID, path); if (NS_FAILED(rv)) goto done; rv = compMgr->UnregisterComponent(kPop3IncomingServerCID, path); diff --git a/mailnews/local/src/nsLocalMailFolder.h b/mailnews/local/src/nsLocalMailFolder.h index 6e44ef91b1f3..0b5445b7ac56 100644 --- a/mailnews/local/src/nsLocalMailFolder.h +++ b/mailnews/local/src/nsLocalMailFolder.h @@ -18,7 +18,7 @@ /******************************************************************************************************** - Interface for representing Messenger folders. + Interface for representing Local Mail folders. *********************************************************************************************************/ diff --git a/mailnews/local/src/nsMailboxUrl.cpp b/mailnews/local/src/nsMailboxUrl.cpp index d3d5abc5b8f4..ff9b1df52515 100644 --- a/mailnews/local/src/nsMailboxUrl.cpp +++ b/mailnews/local/src/nsMailboxUrl.cpp @@ -304,6 +304,7 @@ nsresult nsMailboxUrl::SetUrlState(PRBool aRunningUrl, nsresult aExitCode) return NS_OK; } +// from nsIMsgUriUrl NS_IMETHODIMP nsMailboxUrl::GetURI(char ** aURI) { // function not implemented yet.... diff --git a/mailnews/news/build/MANIFEST b/mailnews/news/build/MANIFEST new file mode 100644 index 000000000000..a40ce6815230 --- /dev/null +++ b/mailnews/news/build/MANIFEST @@ -0,0 +1,18 @@ +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. +# + +nsMsgNewsCID.h + diff --git a/mailnews/news/build/Makefile.in b/mailnews/news/build/Makefile.in index bae36b92ba26..3217d80a0843 100644 --- a/mailnews/news/build/Makefile.in +++ b/mailnews/news/build/Makefile.in @@ -32,6 +32,7 @@ CPPSRCS= \ $(NULL) EXPORTS = \ + nsMsgNewsCID.h \ $(NULL) SHARED_LIBRARY_LIBS = \ diff --git a/mailnews/news/build/nsMsgNewsCID.h b/mailnews/news/build/nsMsgNewsCID.h new file mode 100644 index 000000000000..159d1d56597a --- /dev/null +++ b/mailnews/news/build/nsMsgNewsCID.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsMsgNewsCID_h__ +#define nsMsgNewsCID_h__ + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsIComponentManager.h" + +#define NS_NEWSFOLDERRESOURCE_CID \ +{ /* 4ace448a-f6d4-11d2-880d-004005263078 */ \ + 0x4ace448a, \ + 0xf6d4, \ + 0x11d2, \ + {0x88, 0x0d, 0x00, 0x40, 0x05, 0x26, 0x30, 0x78} \ +} + +#endif // nsMsgNews_h__ diff --git a/mailnews/news/build/nsMsgNewsFactory.cpp b/mailnews/news/build/nsMsgNewsFactory.cpp index 09868b7237c1..0e4af921732e 100644 --- a/mailnews/news/build/nsMsgNewsFactory.cpp +++ b/mailnews/news/build/nsMsgNewsFactory.cpp @@ -26,6 +26,8 @@ #include "nsCRT.h" #include "nsCOMPtr.h" +#include "nsNewsFolder.h" +#include "nsMsgNewsCID.h" /* Include all of the interfaces our factory can generate components for */ #include "nsNntpUrl.h" @@ -34,6 +36,10 @@ static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_CID(kNntpUrlCID, NS_NNTPURL_CID); static NS_DEFINE_CID(kNntpServiceCID, NS_NNTPSERVICE_CID); +static NS_DEFINE_CID(kNewsFolderResourceCID, NS_NEWSFOLDERRESOURCE_CID); +#if 0 +static NS_DEFINE_CID(kNntpIncomingServerCID, NS_NNTPINCOMINGSERVER_CID); +#endif static PRInt32 g_InstanceCount = 0; static PRInt32 g_LockCount = 0; @@ -72,7 +78,10 @@ nsMsgNewsFactory::nsMsgNewsFactory(const nsCID &aClass, { NS_INIT_REFCNT(); - // store a copy of the +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFactory::nsMsgNewsFactory()\n"); +#endif + compMgrSupports->QueryInterface(nsIServiceManager::GetIID(), (void **)&mServiceManager); } @@ -113,35 +122,61 @@ nsresult nsMsgNewsFactory::CreateInstance(nsISupports *aOuter, const nsIID &aIID, void **aResult) { - nsresult res = NS_OK; +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFactory::CreateInstance()\n"); +#endif + nsresult rv = NS_OK; - if (aResult == NULL) + if (aResult == nsnull) return NS_ERROR_NULL_POINTER; - *aResult = NULL; + *aResult = nsnull; - nsISupports *inst = nsnull; - // ClassID check happens here // Whenever you add a new class that supports an interface, plug it in here!!! - + + // do they want a news datasource ? if (mClassID.Equals(kNntpUrlCID)) - { - inst = NS_STATIC_CAST(nsINntpUrl*, new nsNntpUrl(nsnull, nsnull)); + { + nsNntpUrl * nntpUrl = new nsNntpUrl(nsnull, nsnull); + if (nntpUrl) + rv = nntpUrl->QueryInterface(aIID, aResult); + else + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv) && nntpUrl) + delete nntpUrl; } else if (mClassID.Equals(kNntpServiceCID)) { - inst = NS_STATIC_CAST(nsINntpService *, new nsNntpService()); + nsNntpService *nntpService = new nsNntpService(); + if (nntpService) + rv = nntpService->QueryInterface(aIID, aResult); + else + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv) && nntpService) + delete nntpService; } + else if (mClassID.Equals(kNewsFolderResourceCID)) + { + nsMsgNewsFolder *newsFolder = new nsMsgNewsFolder(); + if (newsFolder) + rv = newsFolder->QueryInterface(aIID, aResult); + else + rv = NS_ERROR_OUT_OF_MEMORY; + if (NS_FAILED(rv) && newsFolder) + delete newsFolder; + } +#if 0 + else if (mClassID.Equals(kNntpIncomingServerCID)) + rv = NS_NewNntpIncomingServer(nsISupports::GetIID(), aResult); +#endif + else + rv = NS_NOINTERFACE; - if (inst == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - res = inst->QueryInterface(aIID, aResult); - if (NS_FAILED(res)) - delete inst; - return res; + return rv; } nsresult nsMsgNewsFactory::LockFactory(PRBool aLock) @@ -194,17 +229,30 @@ NSRegisterSelf(nsISupports* aServMgr, const char* path) (nsISupports**)&compMgr); if (NS_FAILED(rv)) return rv; - // register the message folder factory rv = compMgr->RegisterComponent(kNntpUrlCID, nsnull, nsnull, path, PR_TRUE, PR_TRUE); if (NS_FAILED(rv)) goto done; rv = compMgr->RegisterComponent(kNntpServiceCID, nsnull, nsnull, path, PR_TRUE, PR_TRUE); if (NS_FAILED(rv)) goto done; + rv = compMgr->RegisterComponent(kNewsFolderResourceCID, + "News Folder Resource Factory", + NS_RDF_RESOURCE_FACTORY_PROGID_PREFIX "news", + path, PR_TRUE, PR_TRUE); + if (NS_FAILED(rv)) goto done; #ifdef NS_DEBUG printf("news registering from %s\n",path); #endif +#if 0 + rv = compMgr->RegisterComponent(kNntpIncomingServerCID, + "Nntp Incoming Server", + "component://netscape/messenger/server&type=nntp", + path, PR_TRUE, PR_TRUE); + + if (NS_FAILED(rv)) goto done; +#endif + done: (void)servMgr->ReleaseService(kComponentManagerCID, compMgr); return rv; @@ -228,6 +276,15 @@ NSUnregisterSelf(nsISupports* aServMgr, const char* path) rv = compMgr->UnregisterComponent(kNntpServiceCID, path); if (NS_FAILED(rv)) goto done; + rv = compMgr->UnregisterComponent(kNewsFolderResourceCID, path); + if (NS_FAILED(rv)) goto done; + +#if 0 + rv = compMgr->UnregisterComponent(kNntpIncomingServerCID, path); + if (NS_FAILED(rv)) goto done; +#endif + + done: (void)servMgr->ReleaseService(kComponentManagerCID, compMgr); return rv; diff --git a/mailnews/news/public/nsINntpUrl.h b/mailnews/news/public/nsINntpUrl.h index 1c06e3342108..9025e7ffe63a 100644 --- a/mailnews/news/public/nsINntpUrl.h +++ b/mailnews/news/public/nsINntpUrl.h @@ -24,6 +24,7 @@ #include "nsIMsgMailNewsUrl.h" #include "nsISupports.h" +#include "nsFileSpec.h" /* include all of our event sink interfaces */ #include "nsINNTPNewsgroupList.h" @@ -47,7 +48,10 @@ class nsINntpUrl : public nsIMsgMailNewsUrl { public: - static const nsIID& GetIID() { static nsIID iid = NS_INNTPURL_IID; return iid; } + static const nsIID& GetIID() { + static nsIID iid = NS_INNTPURL_IID; + return iid; + } /////////////////////////////////////////////////////////////////////////////// // Getters and Setters for the news specific event sinks to bind to to your url diff --git a/mailnews/news/src/Makefile.in b/mailnews/news/src/Makefile.in index 22d60d4d9c94..bc4f01f42bd5 100644 --- a/mailnews/news/src/Makefile.in +++ b/mailnews/news/src/Makefile.in @@ -34,6 +34,7 @@ EXPORTS = \ nsNNTPNewsgroupPost.h \ nntpCore.h \ nsNntpService.h \ + nsNewsFolder.h \ $(NULL) CPPSRCS = \ @@ -45,6 +46,7 @@ CPPSRCS = \ nsNntpUrl.cpp \ nsNNTPHost.cpp \ nsNntpService.cpp \ + nsNewsFolder.cpp \ $(NULL) EXTRA_DSO_LDOPTS = \ diff --git a/mailnews/news/src/nsNewsFolder.cpp b/mailnews/news/src/nsNewsFolder.cpp new file mode 100644 index 000000000000..1011baee621b --- /dev/null +++ b/mailnews/news/src/nsNewsFolder.cpp @@ -0,0 +1,957 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#define NS_IMPL_IDS +#include "nsIPref.h" + +#include "msgCore.h" // precompiled header... + +#include "nsNewsFolder.h" +#include "nsMsgFolderFlags.h" +#include "prprf.h" +#include "nsISupportsArray.h" +#include "nsIServiceManager.h" +#include "nsIEnumerator.h" +#include "nsINntpService.h" +#include "nsIFolderListener.h" +#include "nsCOMPtr.h" +#include "nsIRDFService.h" +#include "nsIRDFDataSource.h" +#include "nsRDFCID.h" +#include "nsFileStream.h" +#include "nsMsgDBCID.h" + +// we need this because of an egcs 1.0 (and possibly gcc) compiler bug +// that doesn't allow you to call ::nsISupports::GetIID() inside of a class +// that multiply inherits from nsISupports +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); +static NS_DEFINE_CID(kNntpServiceCID, NS_NNTPSERVICE_CID); +static NS_DEFINE_CID(kCNewsDB, NS_NEWSDB_CID); + +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// + +nsMsgNewsFolder::nsMsgNewsFolder(void) + : nsMsgFolder(), mPath(""), mExpungedBytes(0), + mHaveReadNameFromDB(PR_FALSE), mGettingNews(PR_FALSE), + mInitialized(PR_FALSE), mNewsDatabase(nsnull) +{ + +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::nsMsgNewsFolder\n"); +#endif + + //XXXX This is a hack for the moment. I'm assuming the only listener is our rdf:mailnews datasource. + //In reality anyone should be able to listen to folder changes. + + nsIRDFService* rdfService = nsnull; + nsIRDFDataSource* datasource = nsnull; + + nsresult rv = nsServiceManager::GetService(kRDFServiceCID, + nsIRDFService::GetIID(), + (nsISupports**) &rdfService); + if(NS_SUCCEEDED(rv)) + { + if(NS_SUCCEEDED(rv = rdfService->GetDataSource("rdf:mailnewsfolders", &datasource))) + { + nsIFolderListener *folderListener; + if(NS_SUCCEEDED(datasource->QueryInterface(nsIFolderListener::GetIID(), (void**)&folderListener))) + { + AddFolderListener(folderListener); + NS_RELEASE(folderListener); + } + NS_RELEASE(datasource); + } + nsServiceManager::ReleaseService(kRDFServiceCID, rdfService); + } + +// NS_INIT_REFCNT(); done by superclass +} + +nsMsgNewsFolder::~nsMsgNewsFolder(void) +{ + if(mNewsDatabase) + //Close releases db; + mNewsDatabase->Close(PR_TRUE); +} + +NS_IMPL_ADDREF_INHERITED(nsMsgNewsFolder, nsMsgFolder) +NS_IMPL_RELEASE_INHERITED(nsMsgNewsFolder, nsMsgFolder) + +NS_IMETHODIMP nsMsgNewsFolder::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::QueryInterface()\n"); +#endif + if (!aInstancePtr) return NS_ERROR_NULL_POINTER; + *aInstancePtr = nsnull; + if (aIID.Equals(nsIMsgNewsFolder::GetIID())) + { +#ifdef DEBUG_sspitzer + printf("aIID is for nsIMsgNewsFolder\n"); +#endif + *aInstancePtr = NS_STATIC_CAST(nsIMsgNewsFolder*, this); + } + else if (aIID.Equals(nsIDBChangeListener::GetIID())) + { + *aInstancePtr = NS_STATIC_CAST(nsIDBChangeListener*, this); + } + + if(*aInstancePtr) + { + AddRef(); + return NS_OK; + } + + return nsMsgFolder::QueryInterface(aIID, aInstancePtr); +} + +//////////////////////////////////////////////////////////////////////////////// + +static PRBool +nsShouldIgnoreFile(nsString& name) +{ + if (name[0] == '.' || name[0] == '#' || name[name.Length() - 1] == '~') + return PR_TRUE; + + if (name.EqualsIgnoreCase("rules.dat")) + return PR_TRUE; + + PRInt32 len = name.Length(); + + // don't add summary files to the list of folders; + // don't add popstate files to the list either, or rules (sort.dat). + if ((len > 4 && name.RFind(".snm", PR_TRUE) == len - 4) || + name.EqualsIgnoreCase("popstate.dat") || + name.EqualsIgnoreCase("sort.dat") || + name.EqualsIgnoreCase("newsfilt.log") || + name.EqualsIgnoreCase("filters.js") || + name.RFind(".toc", PR_TRUE) == len - 4) + return PR_TRUE; + + if ((len > 4 && name.RFind(".sbd", PR_TRUE) == len - 4) || + (len > 4 && name.RFind(".msf", PR_TRUE) == len - 4)) + return PR_TRUE; + return PR_FALSE; +} + +nsresult +nsMsgNewsFolder::CreateSubFolders(nsFileSpec &path) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::CreateSubFolder()\n"); +#endif + + nsAutoString currentFolderNameStr("netscape.public.mozilla.unix"); + nsIMsgFolder *child; + AddSubfolder(currentFolderNameStr,&child); + NS_IF_RELEASE(child); + + return NS_OK; +#if 0 + nsresult rv = NS_OK; + nsAutoString currentFolderNameStr; + nsIMsgFolder *child; + char *folderName; + for (nsDirectoryIterator dir(path); dir.Exists(); dir++) { + nsFileSpec currentFolderPath = (nsFileSpec&)dir; + + folderName = currentFolderPath.GetLeafName(); + currentFolderNameStr = folderName; + if (nsShouldIgnoreFile(currentFolderNameStr)) + { + PL_strfree(folderName); + continue; + } + + AddSubfolder(currentFolderNameStr, &child); + NS_IF_RELEASE(child); + PL_strfree(folderName); + } + return rv; +#endif +} + +nsresult nsMsgNewsFolder::AddSubfolder(nsAutoString name, nsIMsgFolder **child) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::AddSubfolder()\n"); +#endif + if(!child) + return NS_ERROR_NULL_POINTER; + + nsresult rv = NS_OK; + nsIRDFService* rdf; + rv = nsServiceManager::GetService(kRDFServiceCID, + nsIRDFService::GetIID(), + (nsISupports**)&rdf); + + if(NS_FAILED(rv)) + return rv; + + nsAutoString uri; + uri.Append(mURI); + uri.Append('/'); + + uri.Append(name); + char* uriStr = uri.ToNewCString(); + if (uriStr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsIRDFResource* res; + rv = rdf->GetResource(uriStr, &res); + if (NS_FAILED(rv)) + return rv; + nsCOMPtr folder(do_QueryInterface(res, &rv)); + if (NS_FAILED(rv)) + return rv; + delete[] uriStr; + + folder->SetFlag(MSG_FOLDER_FLAG_NEWSGROUP); + + mSubFolders->AppendElement(folder); + *child = folder; + NS_ADDREF(*child); + (void)nsServiceManager::ReleaseService(kRDFServiceCID, rdf); + + return rv; +} + + +nsresult nsMsgNewsFolder::ParseFolder(nsFileSpec& path) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMsgNewsFolder::Enumerate(nsIEnumerator **result) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::Enumerate()\n"); +#endif +#if 0 + nsresult rv; + + // for now, news folders contain both messages and folders + // server is a folder, and it contains folders + // newsgroup is a folder, and it contains messages + // + // eventually the top level server will not be a folder + // and news folders will only contain messages + nsIEnumerator* folders; + // nsIEnumerator* messages; + rv = GetSubFolders(&folders); + if (NS_FAILED(rv)) return rv; + // rv = GetMessages(&messages); + // if (NS_FAILED(rv)) return rv; + return NS_NewConjoiningEnumerator(folders, messages, + (nsIBidirectionalEnumerator**)result); +#endif +} + +nsresult +nsMsgNewsFolder::AddDirectorySeparator(nsFileSpec &path) +{ + nsresult rv = NS_OK; + if (nsCRT::strcmp(mURI, kNewsRootURI) == 0) { + // don't concat the full separator with .sbd + } + else { + nsAutoString sep; +#if 0 + rv = nsGetNewsFolderSeparator(sep); +#else + rv = NS_OK; +#endif + if (NS_FAILED(rv)) return rv; + + // see if there's a dir with the same name ending with .sbd + // unfortunately we can't just say: + // path += sep; + // here because of the way nsFileSpec concatenates + nsAutoString str((nsFilePath)path); + str += sep; + path = nsFilePath(str); + } + + return rv; +} + +NS_IMETHODIMP +nsMsgNewsFolder::GetSubFolders(nsIEnumerator* *result) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetSubFolders()\n"); +#endif + if (!mInitialized) { + nsFileSpec path; + nsresult rv = GetPath(path); + if (NS_FAILED(rv)) return rv; + + rv = CreateSubFolders(path); + if (NS_FAILED(rv)) return rv; + + mInitialized = PR_TRUE; // XXX do this on failure too? + } + return mSubFolders->Enumerate(result); +} + +NS_IMETHODIMP +nsMsgNewsFolder::AddUnique(nsISupports* element) +{ + PR_ASSERT(0); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsMsgNewsFolder::ReplaceElement(nsISupports* element, nsISupports* newElement) +{ + PR_ASSERT(0); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//Makes sure the database is open and exists. If the database is valid then +//returns NS_OK. Otherwise returns a failure error value. +nsresult nsMsgNewsFolder::GetDatabase() +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetDatabase()\n"); +#endif +#if 0 + if (mNewsDatabase == nsnull) + { + nsNativeFileSpec path; + nsresult rv = GetPath(path); + if (NS_FAILED(rv)) return rv; + + nsresult folderOpen = NS_OK; + nsIMsgDatabase * newsDBFactory = nsnull; + + rv = nsComponentManager::CreateInstance(kCNewsDB, nsnull, nsIMsgDatabase::GetIID(), (void **) &newsDBFactory); + if (NS_SUCCEEDED(rv) && newsDBFactory) + { + folderOpen = newsDBFactory->Open(path, PR_TRUE, (nsIMsgDatabase **) &mNewsDatabase, PR_FALSE); + if(!NS_SUCCEEDED(folderOpen) && + folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE || folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING ) + { + // if it's out of date then reopen with upgrade. + if(!NS_SUCCEEDED(rv = newsDBFactory->Open(path, PR_TRUE, &mNewsDatabase, PR_TRUE))) + { + NS_RELEASE(newsDBFactory); + return rv; + } + } + + NS_RELEASE(newsDBFactory); + } + + if(mNewsDatabase) + { + + mNewsDatabase->AddListener(this); + + // if we have to regenerate the folder, run the parser url. + if(folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING || folderOpen == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE) + { + if(NS_FAILED(rv = ParseFolder(path))) + return rv; + else + return NS_ERROR_NOT_INITIALIZED; + } + else + { + //Otherwise we have a valid database so lets extract necessary info. + UpdateSummaryTotals(); + } + } + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsMsgNewsFolder::GetMessages(nsIEnumerator* *result) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetMessages()\n"); +#endif +#if 0 + nsresult rv = GetDatabase(); + + if(NS_SUCCEEDED(rv)) + return mNewsDatabase->EnumerateMessages(result); + else + return rv; +#endif + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetThreads(nsIEnumerator** threadEnumerator) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetThreads()\n"); +#endif +#if 0 + nsresult rv = GetDatabase(); + + if(NS_SUCCEEDED(rv)) + return mNewsDatabase->EnumerateThreads(threadEnumerator); + else + return rv; +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsMsgNewsFolder::GetThreadForMessage(nsIMessage *message, nsIMsgThread **thread) +{ + nsresult rv = GetDatabase(); + if(NS_SUCCEEDED(rv)) + return mNewsDatabase->GetThreadContainingMsgHdr(message, thread); + else + return rv; + +} + +NS_IMETHODIMP nsMsgNewsFolder::BuildFolderURL(char **url) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::BuildFolderURL()\n"); +#endif + const char *urlScheme = "news:"; + + if(!url) + return NS_ERROR_NULL_POINTER; + + nsFileSpec path; + nsresult rv = GetPath(path); + if (NS_FAILED(rv)) return rv; +#if defined(XP_MAC) + nsAutoString tmpPath((nsFilePath)path); //ducarroz: please don't cast a nsFilePath to char* on Mac + const char *pathName = tmpPath.ToNewCString(); + *url = PR_smprintf("%s%s", urlScheme, pathName); + delete [] pathName; +#else + const char *pathName = path; + *url = PR_smprintf("%s%s", urlScheme, pathName); +#endif + return NS_OK; + +} + +/* Finds the directory associated with this folder. That is if the path is + c:\Inbox, it will return c:\Inbox.sbd if it succeeds. If that path doesn't + currently exist then it will create it + */ +nsresult nsMsgNewsFolder::CreateDirectoryForFolder(nsFileSpec &path) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::CreateDirectoryForFolder()\n"); +#endif + nsresult rv = NS_OK; + + rv = GetPath(path); + if(NS_FAILED(rv)) + return rv; + + if(!path.IsDirectory()) + { + //If the current path isn't a directory, add directory separator + //and test it out. + rv = AddDirectorySeparator(path); + if(NS_FAILED(rv)) + return rv; + + //If that doesn't exist, then we have to create this directory + if(!path.IsDirectory()) + { + //If for some reason there's a file with the directory separator + //then we are going to fail. + if(path.Exists()) + { + return NS_MSG_COULD_NOT_CREATE_DIRECTORY; + } + //otherwise we need to create a new directory. + else + { + path.CreateDirectory(); + //Above doesn't return an error value so let's see if + //it was created. + if(!path.IsDirectory()) + return NS_MSG_COULD_NOT_CREATE_DIRECTORY; + } + } + } + + return rv; +} + +NS_IMETHODIMP nsMsgNewsFolder::CreateSubfolder(const char *folderName) +{ +#if 0 + nsresult rv = NS_OK; + + nsFileSpec path; + nsIMsgFolder *child = nsnull; + //Get a directory based on our current path. + rv = CreateDirectoryForFolder(path); + if(NS_FAILED(rv)) + return rv; + + + //Now we have a valid directory or we have returned. + //Make sure the new folder name is valid + path += folderName; + path.MakeUnique(); + + nsOutputFileStream outputStream(path); + + // Create an empty database for this news folder, set its name from the user + nsIMsgDatabase * newsDBFactory = nsnull; + + rv = nsComponentManager::CreateInstance(kCNewsDB, nsnull, nsIMsgDatabase::GetIID(), (void **) &newsDBFactory); + if (NS_SUCCEEDED(rv) && newsDBFactory) + { + nsIMsgDatabase *unusedDB = NULL; + rv = newsDBFactory->Open(path, PR_TRUE, (nsIMsgDatabase **) &unusedDB, PR_TRUE); + + if (NS_SUCCEEDED(rv) && unusedDB) + { + //need to set the folder name + nsIDBFolderInfo *folderInfo; + rv = unusedDB->GetDBFolderInfo(&folderInfo); + if(NS_SUCCEEDED(rv)) + { + //folderInfo->SetNewsgroupName(leafNameFromUser); + NS_IF_RELEASE(folderInfo); + } + + //Now let's create the actual new folder + nsAutoString folderNameStr(folderName); + rv = AddSubfolder(folderName, &child); + unusedDB->SetSummaryValid(PR_TRUE); + unusedDB->Close(PR_TRUE); + } + else + { + path.Delete(PR_FALSE); + rv = NS_MSG_CANT_CREATE_FOLDER; + } + NS_IF_RELEASE(newsDBFactory); + } + if(rv == NS_OK && child) + { + nsISupports *folderSupports; + + rv = child->QueryInterface(kISupportsIID, (void**)&folderSupports); + if(NS_SUCCEEDED(rv)) + { + NotifyItemAdded(folderSupports); + NS_IF_RELEASE(folderSupports); + } + } + NS_IF_RELEASE(child); + return rv; +#endif +} + +NS_IMETHODIMP nsMsgNewsFolder::RemoveSubFolder(nsIMsgFolder *which) +{ +#if 0 + // Let the base class do list management + nsMsgFolder::RemoveSubFolder(which); +#endif + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::Delete() +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::Rename(const char *newName) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::Adopt(nsIMsgFolder *srcFolder, PRUint32 *outPos) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMsgNewsFolder::GetChildNamed(nsString& name, nsISupports ** aChild) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetChildNamed()\n"); +#endif + NS_ASSERTION(aChild, "NULL child"); + + // will return nsnull if we can't find it + *aChild = nsnull; + + nsIMsgFolder *folder = nsnull; + + PRUint32 count = mSubFolders->Count(); + + for (PRUint32 i = 0; i < count; i++) + { + nsISupports *supports; + supports = mSubFolders->ElementAt(i); + if(folder) + NS_RELEASE(folder); + if(NS_SUCCEEDED(supports->QueryInterface(kISupportsIID, (void**)&folder))) { + char *folderName; + + folder->GetName(&folderName); + // case-insensitive compare is probably LCD across OS filesystems + if (folderName && !name.EqualsIgnoreCase(folderName)) { + *aChild = folder; + PR_FREEIF(folderName); + return NS_OK; + } + PR_FREEIF(folderName); + } + NS_RELEASE(supports); + } + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetName(char **name) +{ + if(!name) + return NS_ERROR_NULL_POINTER; + + if (!mHaveReadNameFromDB) + { + if (mDepth == 1) + { + SetName("News.Mozilla.Org"); + mHaveReadNameFromDB = TRUE; + *name = mName.ToNewCString(); + return NS_OK; + } + else + { + //Need to read the name from the database + } + } + nsAutoString folderName; + nsURI2Name(kNewsRootURI, mURI, folderName); + *name = folderName.ToNewCString(); + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetPrettyName(nsString& prettyName) +{ + if (mDepth == 1) { + // Depth == 1 means we are on the news server level + // override the name here to say "News.Mozilla.Org" + prettyName = PL_strdup("News.Mozilla.Org"); + } + else { + nsresult rv = NS_ERROR_NULL_POINTER; + char *pName = prettyName.ToNewCString(); + if (pName) + rv = nsMsgFolder::GetPrettyName(&pName); + delete[] pName; + return rv; + } + + return NS_OK; +} + +nsresult nsMsgNewsFolder::GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db) +{ + nsresult openErr=NS_ERROR_UNEXPECTED; + if(!db || !folderInfo) + return NS_ERROR_NULL_POINTER; + + nsIMsgDatabase *newsDBFactory = nsnull; + nsIMsgDatabase *newsDB; + + nsresult rv = nsComponentManager::CreateInstance(kCNewsDB, nsnull, nsIMsgDatabase::GetIID(), (void **) &newsDBFactory); + if (NS_SUCCEEDED(rv) && newsDBFactory) + { + openErr = newsDBFactory->Open(mPath, PR_FALSE, (nsIMsgDatabase **) &newsDB, PR_FALSE); + newsDBFactory->Release(); + } + + *db = newsDB; + if (NS_SUCCEEDED(openErr)&& *db) + openErr = (*db)->GetDBFolderInfo(folderInfo); + return openErr; +} + +NS_IMETHODIMP nsMsgNewsFolder::UpdateSummaryTotals() +{ + PRUint32 oldUnreadMessages = mNumUnreadMessages; + PRUint32 oldTotalMessages = mNumTotalMessages; + //We need to read this info from the database + ReadDBFolderInfo(PR_TRUE); + + // If we asked, but didn't get any, stop asking + if (mNumUnreadMessages == -1) + mNumUnreadMessages = -2; + + //Need to notify listeners that total count changed. + if(oldTotalMessages != mNumTotalMessages) + { + char *oldTotalMessagesStr = PR_smprintf("%d", oldTotalMessages); + char *totalMessagesStr = PR_smprintf("%d",mNumTotalMessages); + NotifyPropertyChanged("TotalMessages", oldTotalMessagesStr, totalMessagesStr); + PR_smprintf_free(totalMessagesStr); + PR_smprintf_free(oldTotalMessagesStr); + } + + if(oldUnreadMessages != mNumUnreadMessages) + { + char *oldUnreadMessagesStr = PR_smprintf("%d", oldUnreadMessages); + char *totalUnreadMessages = PR_smprintf("%d",mNumUnreadMessages); + NotifyPropertyChanged("TotalUnreadMessages", oldUnreadMessagesStr, totalUnreadMessages); + PR_smprintf_free(totalUnreadMessages); + PR_smprintf_free(oldUnreadMessagesStr); + } + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetExpungedBytesCount(PRUint32 *count) +{ + if(!count) + return NS_ERROR_NULL_POINTER; + + *count = mExpungedBytes; + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetDeletable(PRBool *deletable) +{ + if(!deletable) + return NS_ERROR_NULL_POINTER; + + // These are specified in the "Mail/News Windows" UI spec + + if (mFlags & MSG_FOLDER_FLAG_TRASH) + { + PRBool moveToTrash; + GetDeleteIsMoveToTrash(&moveToTrash); + if(moveToTrash) + *deletable = PR_TRUE; // allow delete of trash if we don't use trash + } + else if (mDepth == 1) + *deletable = PR_FALSE; + else if (mFlags & MSG_FOLDER_FLAG_INBOX || + mFlags & MSG_FOLDER_FLAG_DRAFTS || + mFlags & MSG_FOLDER_FLAG_TRASH || + mFlags & MSG_FOLDER_FLAG_TEMPLATES) + *deletable = PR_FALSE; + else *deletable = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetCanCreateChildren(PRBool *canCreateChildren) +{ + if(!canCreateChildren) + return NS_ERROR_NULL_POINTER; + + *canCreateChildren = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetCanBeRenamed(PRBool *canBeRenamed) +{ + if(!canBeRenamed) + return NS_ERROR_NULL_POINTER; + + // The root mail folder can't be renamed + if (mDepth < 2) + *canBeRenamed = PR_FALSE; + + // Here's a weird case necessitated because we don't have a separate + // preference for any folder name except the FCC folder (Sent). Others + // are known by name, and as such, can't be renamed. I guess. + else if (mFlags & MSG_FOLDER_FLAG_TRASH || + mFlags & MSG_FOLDER_FLAG_DRAFTS || + mFlags & MSG_FOLDER_FLAG_QUEUE || + mFlags & MSG_FOLDER_FLAG_INBOX || + mFlags & MSG_FOLDER_FLAG_TEMPLATES) + *canBeRenamed = PR_FALSE; + else + *canBeRenamed = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetRequiresCleanup(PRBool *requiresCleanup) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetSizeOnDisk(PRUint32 size) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetUsersName(char** userName) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetHostName(char** hostName) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::UserNeedsToAuthenticateForFolder(PRBool displayOnly, PRBool *authenticate) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::RememberPassword(char *password) +{ +#ifdef HAVE_DB + NewsDB *newsDb = NULL; + NewsDB::Open(m_pathName, TRUE, &newsDb); + if (newsDb) + { + newsDb->SetCachedPassword(password); + newsDb->Close(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetRememberedPassword(char ** password) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::GetPath(nsFileSpec& aPathName) +{ +#ifdef DEBUG_sspitzer + printf("nsMsgNewsFolder::GetPath()\n"); +#endif + nsFileSpec nopath(""); + if (mPath == nopath) { + nsresult rv = nsURI2Path(kNewsRootURI, mURI, mPath); + if (NS_FAILED(rv)) return rv; + } + aPathName = mPath; + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::DeleteMessage(nsIMessage *message) +{ + if(mNewsDatabase) + return(mNewsDatabase->DeleteHeader(message, nsnull, PR_TRUE, PR_TRUE)); + + return NS_OK; +} + +nsresult nsMsgNewsFolder::NotifyPropertyChanged(char *property, char *oldValue, char* newValue) +{ + nsISupports *supports; + if(NS_SUCCEEDED(QueryInterface(kISupportsIID, (void**)&supports))) + { + PRUint32 i; + for(i = 0; i < mListeners->Count(); i++) + { + nsIFolderListener *listener = (nsIFolderListener*)mListeners->ElementAt(i); + listener->OnItemPropertyChanged(supports, property, oldValue, newValue); + NS_RELEASE(listener); + } + NS_RELEASE(supports); + } + + return NS_OK; + +} + +nsresult nsMsgNewsFolder::NotifyItemAdded(nsISupports *item) +{ + + PRUint32 i; + for(i = 0; i < mListeners->Count(); i++) + { + nsIFolderListener *listener = (nsIFolderListener*)mListeners->ElementAt(i); + listener->OnItemAdded(this, item); + NS_RELEASE(listener); + } + + return NS_OK; + +} + +NS_IMETHODIMP nsMsgNewsFolder::OnKeyChange(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator) +{ + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::OnKeyDeleted(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator) +{ + nsIMessage *pMessage; + mNewsDatabase->GetMsgHdrForKey(aKeyChanged, &pMessage); + nsString author, subject; + nsISupports *msgSupports; + if(NS_SUCCEEDED(pMessage->QueryInterface(kISupportsIID, (void**)&msgSupports))) + { + PRUint32 i; + for(i = 0; i < mListeners->Count(); i++) + { + nsIFolderListener *listener = (nsIFolderListener*)mListeners->ElementAt(i); + listener->OnItemRemoved(this, msgSupports); + NS_RELEASE(listener); + } + } + UpdateSummaryTotals(); + NS_RELEASE(msgSupports); + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::OnKeyAdded(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator) +{ + nsIMessage *pMessage; + mNewsDatabase->GetMsgHdrForKey(aKeyChanged, &pMessage); + nsString author, subject; + nsISupports *msgSupports; + if(pMessage && NS_SUCCEEDED(pMessage->QueryInterface(kISupportsIID, (void**)&msgSupports))) + { + NotifyItemAdded(msgSupports); + } + UpdateSummaryTotals(); + NS_RELEASE(msgSupports); + + return NS_OK; +} + +NS_IMETHODIMP nsMsgNewsFolder::OnAnnouncerGoingAway(nsIDBChangeAnnouncer * instigator) +{ + return NS_OK; +} diff --git a/mailnews/news/src/nsNewsFolder.h b/mailnews/news/src/nsNewsFolder.h new file mode 100644 index 000000000000..543161dc12c9 --- /dev/null +++ b/mailnews/news/src/nsNewsFolder.h @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/******************************************************************************************************** + + Interface for representing News folders. + +*********************************************************************************************************/ + +#ifndef nsMsgNewsFolder_h__ +#define nsMsgNewsFolder_h__ + +#include "nsMsgFolder.h" /* include the interface we are going to support */ +#include "nsFileSpec.h" +#include "nsIDBChangeListener.h" +#include "nsFileStream.h" + +class nsMsgNewsFolder : public nsMsgFolder, public nsIMsgNewsFolder, public nsIDBChangeListener +{ +public: + nsMsgNewsFolder(void); + virtual ~nsMsgNewsFolder(void); + + NS_DECL_ISUPPORTS_INHERITED +#if 0 + static nsresult GetRoot(nsIMsgFolder* *result); +#endif + // nsICollection methods: + NS_IMETHOD Enumerate(nsIEnumerator* *result); + + // nsIFolder methods: + NS_IMETHOD GetSubFolders(nsIEnumerator* *result); + + // nsIMsgFolder methods: + NS_IMETHOD AddUnique(nsISupports* element); + NS_IMETHOD ReplaceElement(nsISupports* element, nsISupports* newElement); + NS_IMETHOD GetMessages(nsIEnumerator* *result); + NS_IMETHOD GetThreads(nsIEnumerator** threadEnumerator); + NS_IMETHOD GetThreadForMessage(nsIMessage *message, nsIMsgThread **thread); + + + NS_IMETHOD CreateSubfolder(const char *folderName); + + NS_IMETHOD RemoveSubFolder (nsIMsgFolder *which); + NS_IMETHOD Delete (); + NS_IMETHOD Rename (const char *newName); + NS_IMETHOD Adopt(nsIMsgFolder *srcFolder, PRUint32 *outPos); + + NS_IMETHOD GetChildNamed(nsString& name, nsISupports ** aChild); + + // this override pulls the value from the db + NS_IMETHOD GetName(char ** name); // Name of this folder (as presented to user). + NS_IMETHOD GetPrettyName(nsString& prettyName); // Override of the base, for top-level news folder + + NS_IMETHOD BuildFolderURL(char **url); + + NS_IMETHOD UpdateSummaryTotals() ; + + NS_IMETHOD GetExpungedBytesCount(PRUint32 *count); + NS_IMETHOD GetDeletable (PRBool *deletable); + NS_IMETHOD GetCanCreateChildren (PRBool *canCreateChildren) ; + NS_IMETHOD GetCanBeRenamed (PRBool *canBeRenamed); + NS_IMETHOD GetRequiresCleanup(PRBool *requiresCleanup); + + NS_IMETHOD GetSizeOnDisk(PRUint32 size); + + NS_IMETHOD GetUsersName(char** userName); + NS_IMETHOD GetHostName(char** hostName); + NS_IMETHOD UserNeedsToAuthenticateForFolder(PRBool displayOnly, PRBool *authenticate); + NS_IMETHOD RememberPassword(char *password); + NS_IMETHOD GetRememberedPassword(char ** password); + + virtual nsresult GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db); + + NS_IMETHOD DeleteMessage(nsIMessage *message); + + // nsIMsgNewsFolder + NS_IMETHOD GetPath(nsNativeFileSpec& aPathName); + + //nsIDBChangeListener + NS_IMETHOD OnKeyChange(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator); + NS_IMETHOD OnKeyDeleted(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator); + NS_IMETHOD OnKeyAdded(nsMsgKey aKeyChanged, int32 aFlags, + nsIDBChangeListener * aInstigator); + NS_IMETHOD OnAnnouncerGoingAway(nsIDBChangeAnnouncer * instigator); + +protected: + nsresult ParseFolder(nsFileSpec& path); + nsresult CreateSubFolders(nsFileSpec &path); + nsresult AddDirectorySeparator(nsFileSpec &path); + nsresult GetDatabase(); + nsresult NotifyPropertyChanged(char *property, char* oldValue, char* newValue); + nsresult NotifyItemAdded(nsISupports *item); + + /* Finds the directory associated with this folder. That is if the path is + c:\Inbox, it will return c:\Inbox.sbd if it succeeds. If that path doesn't + currently exist then it will create it + */ + nsresult CreateDirectoryForFolder(nsFileSpec &path); + + //Creates a subfolder with the name 'name' and adds it to the list of children. + //Returns the child as well. + nsresult AddSubfolder(nsAutoString name, nsIMsgFolder **child); + + +protected: + nsNativeFileSpec mPath; + PRUint32 mExpungedBytes; + PRBool mHaveReadNameFromDB; + PRBool mGettingNews; + PRBool mInitialized; + nsISupportsArray *mMessages; + nsIMsgDatabase* mNewsDatabase; +}; + +#endif // nsMsgNewsFolder_h__ diff --git a/mailnews/news/src/nsNntpService.h b/mailnews/news/src/nsNntpService.h index 768a6c78a00b..57a5caff2674 100644 --- a/mailnews/news/src/nsNntpService.h +++ b/mailnews/news/src/nsNntpService.h @@ -27,13 +27,14 @@ class nsIUrlListener; class nsNntpService : public nsINntpService { public: - NS_DECL_ISUPPORTS nsNntpService(); + virtual ~nsNntpService(); + + NS_DECL_ISUPPORTS NS_IMETHOD RunNewsUrl (const nsString& urlString, nsISupports * aConsumer, nsIUrlListener * aUrlListener, nsIURL ** aURL); -protected: - virtual ~nsNntpService(); }; -#endif /* nsNntpService_h___ */ \ No newline at end of file +#endif /* nsNntpService_h___ */ + diff --git a/mailnews/news/src/nsNntpUrl.cpp b/mailnews/news/src/nsNntpUrl.cpp index b56b458b2fc7..ee634b6a3925 100644 --- a/mailnews/news/src/nsNntpUrl.cpp +++ b/mailnews/news/src/nsNntpUrl.cpp @@ -338,7 +338,32 @@ nsresult nsNntpUrl::GetErrorMessage (char ** errorMessage) const return NS_OK; } +// from nsIMsgUriUrl +NS_IMETHODIMP nsNntpUrl::GetURI(char ** aURI) +{ +#ifdef DEBUG_sspitzer + printf("nsNntpUrl::GetURI()\n"); +#endif + if (aURI) + { + const nsFileSpec * filePath = nsnull; +#if 0 + GetFilePath(&filePath); +#endif + if (filePath) + { + char * uri = nsnull; + nsFileSpec folder = *filePath; + nsBuildNewsMessageURI(folder, nsnull, &uri); + *aURI = uri; + } + else + *aURI = nsnull; + } + + return NS_OK; +} //////////////////////////////////////////////////////////////////////////////////// // End nsINntpUrl specific support //////////////////////////////////////////////////////////////////////////////////// diff --git a/mailnews/news/src/nsNntpUrl.h b/mailnews/news/src/nsNntpUrl.h index 62a51cb98f7c..b4f526c2a0eb 100644 --- a/mailnews/news/src/nsNntpUrl.h +++ b/mailnews/news/src/nsNntpUrl.h @@ -23,19 +23,11 @@ #include "nsIUrlListenerManager.h" #include "nsINetlibURL.h" /* this should be temporary until Network N2 project lands */ #include "nsINNTPNewsgroupPost.h" +#include "nsFileSpec.h" -class nsNntpUrl : public nsINntpUrl, public nsINetlibURL +class nsNntpUrl : public nsINntpUrl, public nsINetlibURL, public nsIMsgUriUrl { public: - // nsIMsgMailNewsUrl interface - NS_IMETHOD SetUrlState(PRBool aRunningUrl, nsresult aExitCode); - NS_IMETHOD GetUrlState(PRBool * aRunningUrl); - - NS_IMETHOD SetErrorMessage (char * errorMessage); - NS_IMETHOD GetErrorMessage (char ** errorMessage) const; // caller must free using PR_Free - NS_IMETHOD RegisterListener (nsIUrlListener * aUrlListener); - NS_IMETHOD UnRegisterListener (nsIUrlListener * aUrlListener); - // nsIURL NS_IMETHOD_(PRBool) Equals(const nsIURL *aURL) const; NS_IMETHOD GetSpec(const char* *result) const; @@ -88,8 +80,22 @@ public: NS_IMETHOD SetMessageToPost(nsINNTPNewsgroupPost *post); NS_IMETHOD GetMessageToPost(nsINNTPNewsgroupPost **post); + // from nsIMsgMailNewsUrl: + NS_IMETHOD SetUrlState(PRBool aRunningUrl, nsresult aExitCode); + NS_IMETHOD GetUrlState(PRBool * aRunningUrl); + + NS_IMETHOD SetErrorMessage (char * errorMessage); + // caller must free using PR_FREE + NS_IMETHOD GetErrorMessage (char ** errorMessage) const; + NS_IMETHOD RegisterListener (nsIUrlListener * aUrlListener); + NS_IMETHOD UnRegisterListener (nsIUrlListener * aUrlListener); + + // from nsIMsgUriUrl + NS_IMETHOD GetURI(char ** aURI); + // nsNntpUrl nsNntpUrl(nsISupports* aContainer, nsIURLGroup* aGroup); + virtual ~nsNntpUrl(); NS_DECL_ISUPPORTS @@ -97,7 +103,6 @@ public: nsresult ParseURL(const nsString& aSpec, const nsIURL* aURL = nsnull); protected: - virtual ~nsNntpUrl(); /* Here's our link to the netlib world.... */ URL_Struct *m_URL_s; diff --git a/mailnews/ui/messenger/resources/commandglue.js b/mailnews/ui/messenger/resources/commandglue.js index f2466f4f96dc..b6593d033050 100644 --- a/mailnews/ui/messenger/resources/commandglue.js +++ b/mailnews/ui/messenger/resources/commandglue.js @@ -71,7 +71,7 @@ function LoadMessage(messageNode) function ChangeFolderByDOMNode(folderNode) { var uri = folderNode.getAttribute('id'); - dump(uri); + dump(uri + "\n"); ChangeFolderByURI(uri); } @@ -131,4 +131,4 @@ function SortThreadPane(column, sortKey) return(true); -} \ No newline at end of file +} diff --git a/mailnews/ui/messenger/resources/folderPane.xul b/mailnews/ui/messenger/resources/folderPane.xul index 7188cca8f9ac..fc03e19889f8 100644 --- a/mailnews/ui/messenger/resources/folderPane.xul +++ b/mailnews/ui/messenger/resources/folderPane.xul @@ -8,6 +8,8 @@ + + ]> &localMailHost.label; - + + + + + + &newsHost.label; +