Back to index

lightning-sunbird  0.9+nobinonly
nsNntpService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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  *   Scott MacGregor <mscott@netscape.com>
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *   Håkan Waara <hwaara@chello.se>
00027  *   David Bienvenu <bienvenu@nventure.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include "msgCore.h"    // precompiled header...
00044 #include "nntpCore.h"
00045 #include "nsISupportsObsolete.h"
00046 #include "nsMsgNewsCID.h"
00047 #include "nsINntpUrl.h"
00048 #include "nsNNTPProtocol.h"
00049 #include "nsNNTPNewsgroupPost.h"
00050 #include "nsIMsgMailSession.h"
00051 #include "nsIMsgIdentity.h"
00052 #include "nsString.h"
00053 #include "nsReadableUtils.h"
00054 #include "nsNewsUtils.h"
00055 #include "nsNewsDatabase.h"
00056 #include "nsMsgDBCID.h"
00057 #include "nsMsgBaseCID.h"
00058 #include "nsIPrefBranch.h"
00059 #include "nsIPrefService.h"
00060 #include "nsCRT.h"  // for nsCRT::strtok
00061 #include "nsNntpService.h"
00062 #include "nsIChannel.h"
00063 #include "nsILoadGroup.h"
00064 #include "nsCOMPtr.h"
00065 #include "nsIDirectoryService.h"
00066 #include "nsIMsgAccountManager.h"
00067 #include "nsIMessengerMigrator.h"
00068 #include "nsINntpIncomingServer.h"
00069 #include "nsICategoryManager.h"
00070 #include "nsIDocShell.h"
00071 #include "nsIDocShellLoadInfo.h"
00072 #include "nsIMessengerWindowService.h"
00073 #include "nsIWindowMediator.h"
00074 #include "nsIDOMWindowInternal.h"
00075 #include "nsIMsgSearchSession.h"
00076 #include "nsAppDirectoryServiceDefs.h"
00077 #include "nsIWebNavigation.h"
00078 #include "nsIIOService.h"
00079 #include "nsNetCID.h"
00080 #include "nsIPrompt.h"
00081 #include "nsIRDFService.h"
00082 #include "nsNewsDownloader.h"
00083 #include "prprf.h"
00084 #include "nsICacheService.h"
00085 #include "nsMsgUtils.h"
00086 #include "nsEscape.h"
00087 #include "nsNetUtil.h"
00088 #include "nsIWindowWatcher.h"
00089 
00090 #ifdef MOZ_XUL_APP
00091 #include "nsICommandLine.h"
00092 #endif
00093 
00094 #undef GetPort  // XXX Windows!
00095 #undef SetPort  // XXX Windows!
00096 
00097 #define PREF_NETWORK_HOSTS_NNTP_SERVER    "network.hosts.nntp_server"
00098 #define PREF_MAIL_ROOT_NNTP        "mail.root.nntp"        // old - for backward compatibility only
00099 #define PREF_MAIL_ROOT_NNTP_REL    "mail.root.nntp-rel"
00100 
00101 static NS_DEFINE_CID(kMessengerMigratorCID, NS_MESSENGERMIGRATOR_CID);
00102 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00103 static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
00104                     
00105 nsNntpService::nsNntpService()
00106 {
00107   mPrintingOperation = PR_FALSE;
00108   mOpenAttachmentOperation = PR_FALSE;
00109 }
00110 
00111 nsNntpService::~nsNntpService()
00112 {
00113   // do nothing
00114 }
00115 
00116 NS_IMPL_THREADSAFE_ADDREF(nsNntpService)
00117 NS_IMPL_THREADSAFE_RELEASE(nsNntpService)
00118 
00119 NS_IMPL_QUERY_INTERFACE7(nsNntpService,
00120                          nsINntpService,
00121                          nsIMsgMessageService,
00122                          nsIProtocolHandler,
00123                          nsIMsgProtocolInfo,
00124                          ICOMMANDLINEHANDLER,
00125                          nsIMsgMessageFetchPartService,
00126                          nsIContentHandler)
00127 
00129 // nsIMsgMessageService support
00131 
00132 NS_IMETHODIMP 
00133 nsNntpService::SaveMessageToDisk(const char *aMessageURI, 
00134                                  nsIFileSpec *aFile, 
00135                                  PRBool aAddDummyEnvelope, 
00136                                  nsIUrlListener *aUrlListener, 
00137                                  nsIURI **aURL,
00138                                  PRBool canonicalLineEnding,
00139                                  nsIMsgWindow *aMsgWindow)
00140 {
00141     nsresult rv = NS_OK;
00142     NS_ENSURE_ARG_POINTER(aMessageURI);
00143  
00144     // double check it is a news-message:/ uri   
00145     if (PL_strncmp(aMessageURI, kNewsMessageRootURI, kNewsMessageRootURILen)) 
00146     {
00147         rv = NS_ERROR_UNEXPECTED;
00148         NS_ENSURE_SUCCESS(rv,rv);
00149     }
00150 
00151     nsCOMPtr <nsIMsgFolder> folder;
00152     nsMsgKey key = nsMsgKey_None;
00153     rv = DecomposeNewsMessageURI(aMessageURI, getter_AddRefs(folder), &key);
00154     NS_ENSURE_SUCCESS(rv,rv);
00155     
00156     nsXPIDLCString messageIdURL;
00157     rv = CreateMessageIDURL(folder, key, getter_Copies(messageIdURL));
00158     NS_ENSURE_SUCCESS(rv,rv);
00159 
00160     nsCOMPtr<nsIURI> url;
00161     rv = ConstructNntpUrl(messageIdURL.get(), aUrlListener, aMsgWindow, aMessageURI, nsINntpUrl::ActionSaveMessageToDisk, getter_AddRefs(url));
00162     NS_ENSURE_SUCCESS(rv,rv);
00163 
00164     nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(url);
00165     if (msgUrl) {
00166 //        msgUrl->SetMessageFile(aFile);
00167         msgUrl->SetAddDummyEnvelope(aAddDummyEnvelope);
00168         msgUrl->SetCanonicalLineEnding(canonicalLineEnding);
00169     }   
00170     
00171     PRBool hasMsgOffline = PR_FALSE;
00172 
00173     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(url);
00174     if (folder)
00175     {
00176       nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(folder);
00177       if (newsFolder)
00178       {
00179         if (mailNewsUrl)
00180         {
00181           folder->HasMsgOffline(key, &hasMsgOffline);
00182           mailNewsUrl->SetMsgIsInLocalCache(hasMsgOffline);
00183         }
00184       }
00185     }
00186 
00187     if (mailNewsUrl)
00188     {
00189       nsCOMPtr <nsIStreamListener> saveAsListener;
00190       mailNewsUrl->GetSaveAsListener(aAddDummyEnvelope, aFile, getter_AddRefs(saveAsListener));
00191     
00192       rv = DisplayMessage(aMessageURI, saveAsListener, /* nsIMsgWindow *aMsgWindow */nsnull, aUrlListener, nsnull /*aCharsetOverride */, aURL);
00193     }
00194     return rv;
00195 }
00196 
00197 
00198 nsresult
00199 nsNntpService::CreateMessageIDURL(nsIMsgFolder *folder, nsMsgKey key, char **url)
00200 {
00201     NS_ENSURE_ARG_POINTER(folder);
00202     NS_ENSURE_ARG_POINTER(url);
00203     if (key == nsMsgKey_None) return NS_ERROR_INVALID_ARG;
00204     
00205     nsresult rv;
00206     nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(folder, &rv);
00207     NS_ENSURE_SUCCESS(rv,rv);
00208 
00209     nsXPIDLCString messageID;
00210     rv = newsFolder->GetMessageIdForKey(key, getter_Copies(messageID));
00211     NS_ENSURE_SUCCESS(rv,rv);
00212 
00213     // we need to escape the message ID, 
00214     // it might contain characters which will mess us up later, like #
00215     // see bug #120502
00216     char *escapedMessageID = nsEscape(messageID.get(), url_Path);
00217     if (!escapedMessageID)
00218       return NS_ERROR_OUT_OF_MEMORY;
00219 
00220     nsCOMPtr <nsIMsgFolder> rootFolder;
00221     rv = folder->GetRootFolder(getter_AddRefs(rootFolder));
00222     NS_ENSURE_SUCCESS(rv,rv);
00223     
00224     nsXPIDLCString rootFolderURI;
00225     rv = rootFolder->GetURI(getter_Copies(rootFolderURI));
00226     NS_ENSURE_SUCCESS(rv,rv);
00227 
00228     nsCAutoString uri;
00229     uri = rootFolderURI.get();
00230     uri += '/';
00231     uri += escapedMessageID;
00232     *url = nsCRT::strdup(uri.get());
00233     
00234     PR_FREEIF(escapedMessageID);
00235 
00236     if (!*url) 
00237       return NS_ERROR_OUT_OF_MEMORY;
00238     
00239     return NS_OK;
00240 }
00241 
00242 NS_IMETHODIMP 
00243 nsNntpService::DisplayMessage(const char* aMessageURI, nsISupports * aDisplayConsumer, 
00244                                        nsIMsgWindow *aMsgWindow, nsIUrlListener * aUrlListener, const char * aCharsetOverride, nsIURI ** aURL)
00245 {
00246   nsresult rv = NS_OK;
00247   NS_ENSURE_ARG_POINTER(aMessageURI);
00248   
00249   nsCOMPtr <nsIMsgFolder> folder;
00250   nsMsgKey key = nsMsgKey_None;
00251   rv = DecomposeNewsMessageURI(aMessageURI, getter_AddRefs(folder), &key);
00252   NS_ENSURE_SUCCESS(rv,rv);
00253   
00254   nsCAutoString urlStr;
00255   // if we are displaying (or printing), we want the news://host/message-id url
00256   // we keep the original uri around, for cancelling and so we can get to the
00257   // articles by doing GROUP and then ARTICLE <n>.
00258   //
00259   // using news://host/message-id has an extra benefit.
00260   // we'll use that to look up in the cache, so if 
00261   // you are reading a message that you've already read, you
00262   // (from a cross post) it would be in your cache.
00263   nsXPIDLCString messageIdURL;
00264   rv = CreateMessageIDURL(folder, key, getter_Copies(messageIdURL));
00265   NS_ENSURE_SUCCESS(rv,rv);
00266   
00267   urlStr = messageIdURL.get();
00268   
00269   // rhp: If we are displaying this message for the purposes of printing, append
00270   // the magic operand.
00271   if (mPrintingOperation)
00272     urlStr.Append("?header=print");
00273   
00274   nsNewsAction action = nsINntpUrl::ActionFetchArticle;
00275   if (mOpenAttachmentOperation)
00276     action = nsINntpUrl::ActionFetchPart;
00277   
00278   nsCOMPtr<nsIURI> url;
00279   rv = ConstructNntpUrl(urlStr.get(), aUrlListener, aMsgWindow, aMessageURI, action, getter_AddRefs(url));
00280   NS_ENSURE_SUCCESS(rv,rv);
00281   
00282   if (NS_SUCCEEDED(rv))
00283   {
00284     nsCOMPtr <nsIMsgMailNewsUrl> msgUrl = do_QueryInterface(url,&rv);
00285     NS_ENSURE_SUCCESS(rv,rv);
00286     
00287     nsCOMPtr<nsIMsgI18NUrl> i18nurl = do_QueryInterface(msgUrl,&rv);
00288     NS_ENSURE_SUCCESS(rv,rv);
00289     
00290     i18nurl->SetCharsetOverRide(aCharsetOverride);
00291     
00292     PRBool shouldStoreMsgOffline = PR_FALSE;
00293     PRBool hasMsgOffline = PR_FALSE;
00294     
00295     if (folder)
00296     {
00297       nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(folder);
00298       if (newsFolder)
00299       {
00300         folder->ShouldStoreMsgOffline(key, &shouldStoreMsgOffline);
00301         folder->HasMsgOffline(key, &hasMsgOffline);
00302         msgUrl->SetMsgIsInLocalCache(hasMsgOffline);
00303         if (WeAreOffline())
00304         {
00305           if (!hasMsgOffline)
00306           {
00307             nsCOMPtr<nsIMsgIncomingServer> server;
00308             
00309             rv = folder->GetServer(getter_AddRefs(server));
00310             if (server)
00311               return server->DisplayOfflineMsg(aMsgWindow);
00312           }
00313         }
00314         newsFolder->SetSaveArticleOffline(shouldStoreMsgOffline);
00315       }
00316     }
00317     
00318     // now is where our behavior differs....if the consumer is the docshell then we want to 
00319     // run the url in the webshell in order to display it. If it isn't a docshell then just
00320     // run the news url like we would any other news url. 
00321     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
00322     if (NS_SUCCEEDED(rv) && docShell) 
00323     {
00324       nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
00325       // DIRTY LITTLE HACK --> if we are opening an attachment we want the docshell to
00326       // treat this load as if it were a user click event. Then the dispatching stuff will be much
00327       // happier.
00328       if (mOpenAttachmentOperation) 
00329       {
00330         docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
00331         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink);
00332       }
00333       
00334       rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
00335     }
00336     else 
00337     {
00338       nsCOMPtr<nsIStreamListener> aStreamListener = do_QueryInterface(aDisplayConsumer, &rv);
00339       if (NS_SUCCEEDED(rv) && aStreamListener)
00340       {
00341         nsCOMPtr<nsIChannel> aChannel;
00342         nsCOMPtr<nsILoadGroup> aLoadGroup;
00343         nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(url, &rv);
00344         if (NS_SUCCEEDED(rv) && mailnewsUrl)
00345         {
00346           if (aMsgWindow)
00347             mailnewsUrl->SetMsgWindow(aMsgWindow);
00348           mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup));
00349         }
00350         rv = NewChannel(url, getter_AddRefs(aChannel));
00351         if (NS_FAILED(rv)) return rv;
00352         
00353         rv = aChannel->SetLoadGroup(aLoadGroup);
00354         if (NS_FAILED(rv)) return rv;
00355         
00356         nsCOMPtr<nsISupports> aCtxt = do_QueryInterface(url);
00357         //  now try to open the channel passing in our display consumer as the listener 
00358         rv = aChannel->AsyncOpen(aStreamListener, aCtxt);
00359       }
00360       else
00361         rv = RunNewsUrl(url, aMsgWindow, aDisplayConsumer);
00362     }
00363   }
00364   
00365   if (aURL) 
00366   {
00367     *aURL = url;
00368     NS_IF_ADDREF(*aURL);
00369   }
00370   return rv;
00371 }
00372 
00373 NS_IMETHODIMP 
00374 nsNntpService::FetchMessage(nsIMsgFolder *folder, nsMsgKey key, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer, nsIUrlListener * aUrlListener, nsIURI ** aURL)
00375 {
00376   nsresult rv = NS_OK;
00377   NS_ENSURE_ARG_POINTER(folder);
00378 
00379   nsCOMPtr<nsIMsgNewsFolder> msgNewsFolder = do_QueryInterface(folder, &rv);
00380   NS_ENSURE_SUCCESS(rv,rv);
00381 
00382   nsCOMPtr <nsIMsgDBHdr> hdr;
00383   rv = folder->GetMessageHeader(key, getter_AddRefs(hdr));
00384   NS_ENSURE_SUCCESS(rv,rv);
00385 
00386   nsXPIDLCString originalMessageUri;
00387   rv = folder->GetUriForMsg(hdr, getter_Copies(originalMessageUri));
00388   NS_ENSURE_SUCCESS(rv,rv);
00389 
00390   nsXPIDLCString messageIdURL;
00391   rv = CreateMessageIDURL(folder, key, getter_Copies(messageIdURL));
00392   NS_ENSURE_SUCCESS(rv,rv);
00393 
00394   nsCOMPtr<nsIURI> url;
00395   rv = ConstructNntpUrl((const char *)messageIdURL, aUrlListener, aMsgWindow, originalMessageUri.get(), nsINntpUrl::ActionFetchArticle, getter_AddRefs(url));
00396   NS_ENSURE_SUCCESS(rv,rv);
00397 
00398   rv = RunNewsUrl(url, aMsgWindow, aConsumer);
00399   NS_ENSURE_SUCCESS(rv,rv);
00400 
00401   if (aURL) 
00402   {
00403     *aURL = url;
00404     NS_IF_ADDREF(*aURL);
00405   }
00406 
00407   return rv;
00408 }
00409 
00410 NS_IMETHODIMP nsNntpService::FetchMimePart(nsIURI *aURI, const char *aMessageURI, nsISupports *aDisplayConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIURI **aURL)
00411 {
00412   nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(aURI));
00413   msgUrl->SetMsgWindow(aMsgWindow);
00414 
00415   // set up the url listener
00416     if (aUrlListener)
00417       msgUrl->RegisterListener(aUrlListener);
00418  
00419     nsCOMPtr<nsIMsgMessageUrl> msgMessageUrl = do_QueryInterface(aURI);
00420 // this code isn't ready yet, but it helps getting opening attachments
00421 // while offline working
00422 //    if (msgMessageUrl)
00423 //    {
00424 //      nsCAutoString spec;
00425 //      aURI->GetSpec(spec);
00426 //      msgMessageUrl->SetOriginalSpec(spec.get());
00427 //    }
00428   return RunNewsUrl(msgUrl, aMsgWindow, aDisplayConsumer);
00429 }
00430 
00431 NS_IMETHODIMP nsNntpService::OpenAttachment(const char *aContentType, 
00432                                             const char *aFileName,
00433                                             const char *aUrl, 
00434                                             const char *aMessageUri, 
00435                                             nsISupports *aDisplayConsumer, 
00436                                             nsIMsgWindow *aMsgWindow, 
00437                                             nsIUrlListener *aUrlListener)
00438 {
00439 
00440   nsCOMPtr<nsIURI> url;
00441   nsresult rv = NS_OK;
00442   nsCAutoString newsUrl;
00443   newsUrl = aUrl;
00444   newsUrl += "&type=";
00445   newsUrl += aContentType;
00446   newsUrl += "&filename=";
00447   newsUrl += aFileName;
00448 
00449   NewURI(newsUrl, nsnull, nsnull, getter_AddRefs(url));
00450 
00451   if (NS_SUCCEEDED(rv) && url)
00452   {
00453     nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(url));
00454     msgUrl->SetMsgWindow(aMsgWindow);
00455     msgUrl->SetFileName(nsDependentCString(aFileName));
00456 // this code isn't ready yet, but it helps getting opening attachments
00457 // while offline working
00458 //   nsCOMPtr<nsIMsgMessageUrl> msgMessageUrl = do_QueryInterface(url);
00459 //    if (msgMessageUrl)
00460 //      msgMessageUrl->SetOriginalSpec(newsUrl.get());
00461     // set up the url listener
00462          if (aUrlListener)
00463               msgUrl->RegisterListener(aUrlListener);
00464 
00465          nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
00466          if (NS_SUCCEEDED(rv) && docShell) 
00467     {
00468                 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
00469                      docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
00470                      loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink);
00471            return docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
00472     }
00473     else
00474       return RunNewsUrl(url, aMsgWindow, aDisplayConsumer);
00475   }
00476   return NS_OK;
00477 }
00478 
00479 NS_IMETHODIMP nsNntpService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL, nsIMsgWindow *aMsgWindow) 
00480 {
00481   nsresult rv = NS_OK;
00482    
00483   NS_ENSURE_ARG_POINTER(aMessageURI);
00484 
00485   // double check that it is a news-message:/ uri
00486   if (PL_strncmp(aMessageURI, kNewsMessageRootURI, kNewsMessageRootURILen)) 
00487   {
00488     rv = NS_ERROR_UNEXPECTED;
00489     NS_ENSURE_SUCCESS(rv,rv);
00490   }
00491 
00492   nsCOMPtr <nsIMsgFolder> folder;
00493   nsMsgKey key = nsMsgKey_None;
00494   rv = DecomposeNewsMessageURI(aMessageURI, getter_AddRefs(folder), &key);
00495   NS_ENSURE_SUCCESS(rv,rv);
00496 
00497   nsXPIDLCString messageIdURL;
00498   rv = CreateMessageIDURL(folder, key, getter_Copies(messageIdURL));
00499   NS_ENSURE_SUCCESS(rv,rv);
00500 
00501   // this is only called by view message source
00502   rv = ConstructNntpUrl(messageIdURL.get(), nsnull, aMsgWindow, aMessageURI, nsINntpUrl::ActionFetchArticle, aURL);
00503   NS_ENSURE_SUCCESS(rv,rv);
00504   if (folder && *aURL)
00505   {
00506     nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(*aURL);
00507     if (mailnewsUrl)
00508     {
00509       PRBool useLocalCache = PR_FALSE;
00510       folder->HasMsgOffline(key, &useLocalCache);  
00511       mailnewsUrl->SetMsgIsInLocalCache(useLocalCache);
00512     }
00513   }
00514   return rv;
00515 
00516 }
00517 
00518 NS_IMETHODIMP
00519 nsNntpService::DecomposeNewsURI(const char *uri, nsIMsgFolder **folder, nsMsgKey *aMsgKey)
00520 {
00521   nsresult rv;
00522   // if we fix DecomposeNewsMessage to handle news message scheme, we could use it exclusively
00523   if (nsCRT::strncmp(uri, kNewsMessageRootURI, kNewsMessageRootURILen) == 0) 
00524   {
00525     rv = DecomposeNewsMessageURI(uri, folder, aMsgKey);
00526     NS_ENSURE_SUCCESS(rv,rv);
00527   }
00528   else {
00529     rv = GetFolderFromUri(uri, folder);
00530     NS_ENSURE_SUCCESS(rv,rv);
00531     *aMsgKey = nsMsgKey_None;
00532   }
00533   return rv;
00534 }
00535 
00536 nsresult
00537 nsNntpService::DecomposeNewsMessageURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey)
00538 {
00539     NS_ENSURE_ARG_POINTER(aMessageURI);
00540     NS_ENSURE_ARG_POINTER(aFolder);
00541     NS_ENSURE_ARG_POINTER(aMsgKey);
00542 
00543     nsresult rv = NS_OK;
00544     nsCAutoString folderURI;
00545 #if 0 // this not ready yet.
00546     // check if we have a url of this form:
00547     // "news://news.mozilla.org:119/3D612B96.1050301%40netscape.com?part=1.2&type=image/gif&filename=hp_icon_logo.gif"
00548     // if so, we're going to iterate through the open msg windows, finding ones with news folders loaded,
00549     // opening the db's for those folders, and searching for messages with the message id
00550     if (!PL_strncmp(aMessageURI, kNewsRootURI, kNewsRootURILen)) {
00551       nsCAutoString messageUri(aMessageURI + kNewsRootURILen + 1);
00552       PRInt32 slashPos = messageUri.FindChar('/');
00553       if (slashPos != kNotFound && slashPos + 1 != messageUri.Length())
00554       {
00555         nsCAutoString messageId;
00556         PRInt32 questionPos = messageUri.FindChar('?');
00557         if (questionPos == kNotFound)
00558           questionPos = messageUri.Length();
00559 
00560         PRInt32 atPos = messageUri.Find("%40");
00561         if (atPos != kNotFound)
00562         {
00563           PRInt32 messageIdLength = questionPos - slashPos - 1;
00564           messageUri.Mid(messageId, slashPos + 1, messageIdLength);
00565           nsUnescape(messageId.BeginWriting());
00566           nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00567           NS_ENSURE_SUCCESS(rv, rv);
00568           nsCOMPtr <nsISupportsArray> msgWindows;
00569           rv = mailSession->GetMsgWindowsArray(getter_AddRefs(msgWindows));
00570           NS_ENSURE_SUCCESS(rv, rv);
00571           PRUint32 numMsgWindows;
00572           msgWindows->Count(&numMsgWindows);
00573           for (PRUint32 windowIndex = 0; windowIndex < numMsgWindows; windowIndex++)
00574           {
00575             nsCOMPtr <nsIMsgWindow> msgWindow = do_QueryElementAt(msgWindows, windowIndex);
00576             NS_ENSURE_SUCCESS(rv, rv);
00577             nsCOMPtr <nsIMsgFolder> openFolder;
00578             msgWindow->GetOpenFolder(getter_AddRefs(openFolder));
00579             if (openFolder)
00580             {
00581               nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(openFolder);
00582               // only interested in news folders.
00583               if (newsFolder)
00584               {
00585                 nsCOMPtr <nsIMsgDatabase> msgDatabase;
00586                 openFolder->GetMsgDatabase(msgWindow, getter_AddRefs(msgDatabase));
00587                 if (msgDatabase)
00588                 {
00589                   nsCOMPtr <nsIMsgDBHdr> msgHdr;
00590                   msgDatabase->GetMsgHdrForMessageID(messageId.get(), getter_AddRefs(msgHdr));
00591                   if (msgHdr)
00592                   {
00593                     msgHdr->GetMessageKey(aMsgKey);
00594                     NS_ADDREF(*aFolder = openFolder);
00595                     break;
00596                   }
00597                 }
00598               }
00599             }
00600           }
00601         }
00602       }
00603     }
00604     else
00605 #endif
00606     {
00607       rv = nsParseNewsMessageURI(aMessageURI, folderURI, aMsgKey);
00608       NS_ENSURE_SUCCESS(rv,rv);
00609 
00610       rv = GetFolderFromUri(folderURI.get(), aFolder);
00611       NS_ENSURE_SUCCESS(rv,rv);
00612     }
00613     return NS_OK;
00614 }
00615 
00616 nsresult
00617 nsNntpService::GetFolderFromUri(const char *aUri, nsIMsgFolder **aFolder)
00618 {
00619   NS_ENSURE_ARG_POINTER(aUri);
00620   NS_ENSURE_ARG_POINTER(aFolder);
00621 
00622   nsCOMPtr<nsIURI> uri;
00623   nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aUri));
00624   NS_ENSURE_SUCCESS(rv,rv);
00625 
00626   nsCAutoString path;
00627   rv = uri->GetPath(path);
00628   NS_ENSURE_SUCCESS(rv,rv);
00629 
00630   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00631   NS_ENSURE_SUCCESS(rv,rv);
00632 
00633   nsCOMPtr <nsIMsgIncomingServer> server;
00634   rv = accountManager->FindServerByURI(uri, PR_FALSE, getter_AddRefs(server));
00635   NS_ENSURE_SUCCESS(rv,rv);
00636 
00637   nsCOMPtr <nsIMsgFolder> rootFolder;
00638   rv = server->GetRootFolder(getter_AddRefs(rootFolder));
00639   NS_ENSURE_SUCCESS(rv,rv);
00640 
00641   // check if path is "/"
00642   // if so, use the root folder
00643   if (path.Length() == 1)
00644   {
00645     NS_ADDREF(*aFolder = rootFolder);
00646     return NS_OK;
00647   }
00648 
00649   // the URI is news://host/(escaped group)
00650   // but the *name* of the newsgroup (we are calling ::GetChildNamed())
00651   // is unescaped.  see http://bugzilla.mozilla.org/show_bug.cgi?id=210089#c17
00652   // for more about this
00653   char *unescapedPath = PL_strdup(path.get() + 1); /* skip the leading slash */
00654   if (!unescapedPath)
00655     return NS_ERROR_OUT_OF_MEMORY;
00656   nsUnescape(unescapedPath);
00657 
00658   nsCOMPtr<nsISupports> subFolder;
00659   rv = rootFolder->GetChildNamed(NS_ConvertUTF8toUTF16(unescapedPath).get() ,
00660                                  getter_AddRefs(subFolder));
00661   PL_strfree(unescapedPath);
00662   NS_ENSURE_SUCCESS(rv,rv);
00663 
00664   return CallQueryInterface(subFolder, aFolder);
00665 }
00666 
00667 NS_IMETHODIMP
00668 nsNntpService::CopyMessage(const char * aSrcMessageURI, nsIStreamListener * aMailboxCopyHandler, PRBool moveMessage,
00669                                              nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL)
00670 {
00671   NS_ENSURE_ARG_POINTER(aSrcMessageURI);
00672   NS_ENSURE_ARG_POINTER(aMailboxCopyHandler);
00673 
00674   nsresult rv;
00675   nsCOMPtr<nsISupports> streamSupport = do_QueryInterface(aMailboxCopyHandler, &rv);
00676   NS_ENSURE_SUCCESS(rv,rv);
00677 
00678   rv = DisplayMessage(aSrcMessageURI, streamSupport, aMsgWindow, aUrlListener, nsnull, aURL);
00679   return rv;
00680 }
00681 
00682 NS_IMETHODIMP
00683 nsNntpService::CopyMessages(nsMsgKeyArray *keys, nsIMsgFolder *srcFolder, nsIStreamListener * aMailboxCopyHandler, PRBool moveMessage,
00684                                              nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL)
00685 {
00686   return NS_ERROR_NOT_IMPLEMENTED;
00687 }
00688 
00689 struct findNewsServerEntry {
00690   const char *newsgroup;
00691   nsINntpIncomingServer *server;
00692 };
00693 
00694 
00695 PRBool 
00696 nsNntpService::findNewsServerWithGroup(nsISupports *aElement, void *data)
00697 {
00698   nsresult rv;
00699   
00700   nsCOMPtr<nsINntpIncomingServer> newsserver = do_QueryInterface(aElement, &rv);
00701   if (NS_FAILED(rv) || ! newsserver) return PR_TRUE;
00702   
00703   findNewsServerEntry *entry = (findNewsServerEntry*) data;
00704   
00705   PRBool containsGroup = PR_FALSE;
00706   
00707   NS_ASSERTION(IsUTF8(nsDependentCString(entry->newsgroup)),
00708                       "newsgroup is not in UTF-8");
00709   rv = newsserver->ContainsNewsgroup(nsDependentCString(entry->newsgroup),
00710                                      &containsGroup);
00711   if (NS_FAILED(rv)) return PR_TRUE;
00712   
00713   if (containsGroup) 
00714   {    
00715     entry->server = newsserver;
00716     return PR_FALSE;            // stop on first find
00717   }
00718   else 
00719   {
00720     return PR_TRUE;
00721   }
00722 }
00723 
00724 nsresult
00725 nsNntpService::FindServerWithNewsgroup(nsCString &host, nsCString &groupName)
00726 {
00727   nsresult rv;
00728 
00729   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00730   NS_ENSURE_SUCCESS(rv,rv);
00731   nsCOMPtr<nsISupportsArray> servers;
00732   
00733   rv = accountManager->GetAllServers(getter_AddRefs(servers));
00734   NS_ENSURE_SUCCESS(rv,rv);
00735 
00736   findNewsServerEntry serverInfo;
00737   serverInfo.server = nsnull;
00738   serverInfo.newsgroup = groupName.get();
00739 
00740   // XXX TODO
00741   // this only looks at the list of subscribed newsgroups.  
00742   // fix to use the hostinfo.dat information
00743   servers->EnumerateForwards(findNewsServerWithGroup, (void *)&serverInfo);
00744   if (serverInfo.server) 
00745   {
00746     nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(serverInfo.server);
00747     nsXPIDLCString thisHostname;
00748     rv = server->GetRealHostName(getter_Copies(thisHostname));
00749     NS_ENSURE_SUCCESS(rv,rv);
00750    
00751     host = (const char *)thisHostname;
00752   }
00753   
00754   return NS_OK;
00755 }
00756 
00757 nsresult nsNntpService::FindHostFromGroup(nsCString &host, nsCString &groupName)
00758 {
00759   nsresult rv = NS_OK;
00760   // host always comes in as ""
00761   NS_ASSERTION(host.IsEmpty(), "host is not empty");
00762   if (!host.IsEmpty()) return NS_ERROR_FAILURE;
00763  
00764   rv = FindServerWithNewsgroup(host, groupName);
00765   NS_ENSURE_SUCCESS(rv,rv);
00766 
00767   // host can be empty
00768   return NS_OK;
00769 }
00770 
00771 nsresult 
00772 nsNntpService::SetUpNntpUrlForPosting(const char *aAccountKey, char **newsUrlSpec)
00773 {
00774   nsresult rv = NS_OK;
00775 
00776   nsXPIDLCString host;
00777   PRInt32 port;
00778 
00779   nsCOMPtr<nsIMsgIncomingServer> nntpServer;
00780   rv = GetNntpServerByAccount(aAccountKey, getter_AddRefs(nntpServer));
00781   if (NS_SUCCEEDED(rv) && nntpServer)
00782   {
00783     nntpServer->GetRealHostName(getter_Copies(host));
00784     nntpServer->GetPort(&port);
00785   }
00786 
00787   *newsUrlSpec = PR_smprintf("%s/%s:%d",kNewsRootURI, host.IsEmpty() ? "news" : host.get(), port);
00788   if (!*newsUrlSpec) return NS_ERROR_FAILURE;
00789 
00790   return NS_OK;
00791 }
00793 // nsINntpService support
00795 // XXX : may not work with non-ASCII newsgroup names and IDN hostnames
00796 NS_IMETHODIMP
00797 nsNntpService::GenerateNewsHeaderValsForPosting(const char *newsgroupsList, char **newsgroupsHeaderVal, char **newshostHeaderVal)
00798 {
00799   nsresult rv = NS_OK;
00800 
00801   NS_ENSURE_ARG_POINTER(newsgroupsList);
00802   NS_ENSURE_ARG_POINTER(newsgroupsHeaderVal);
00803   NS_ENSURE_ARG_POINTER(newshostHeaderVal);
00804   NS_ENSURE_ARG_POINTER(*newsgroupsList);
00805 
00806   // newsgroupsList can be a comma separated list of these:
00807   // news://host/group
00808   // news://group
00809   // host/group
00810   // group
00811   //
00812   // we are not going to allow the user to cross post to multiple hosts.
00813   // if we detect that, we stop and return error.
00814 
00815   // nsCRT::strtok is going destroy what we pass to it, so we need to make a copy of newsgroupsNames.
00816   char *list = nsCRT::strdup(newsgroupsList);
00817   char *token = nsnull;
00818   char *rest = list;
00819   nsCAutoString host;
00820   nsCAutoString str;
00821   nsCAutoString newsgroups;
00822     
00823   token = nsCRT::strtok(rest, ",", &rest);
00824   while (token && *token) 
00825   {
00826     str = token;
00827     str.StripWhitespace();
00828 
00829     if (!str.IsEmpty()) 
00830     {
00831       nsCAutoString currentHost;
00832       nsCAutoString theRest;
00833 
00834       // does str start with "news:/"?
00835       if (str.Find(kNewsRootURI) == 0)
00836       {
00837         // we have news://group or news://host/group
00838         // set theRest to what's after news://
00839         str.Right(theRest, str.Length() - kNewsRootURILen /* for news:/ */ - 1 /* for the slash */);
00840       }
00841       else if (str.Find(":/") != -1) 
00842       {
00843         // we have x:/y where x != news. this is bad, return failure
00844         CRTFREEIF(list);
00845         return NS_ERROR_FAILURE;
00846       }
00847       else
00848       {
00849         theRest = str;
00850       }
00851 
00852       // theRest is "group" or "host/group"
00853       PRInt32 slashpos = theRest.FindChar('/');
00854       if (slashpos > 0 ) 
00855       {
00856         nsCAutoString currentGroup;
00857         
00858         // theRest is "host/group"
00859         theRest.Left(currentHost, slashpos);
00860 
00861         // from "host/group", put "group" into currentGroup;
00862         theRest.Right(currentGroup, theRest.Length() - currentHost.Length() - 1);
00863 
00864         NS_ASSERTION(!currentGroup.IsEmpty(), "currentGroup is empty");
00865         if (currentGroup.IsEmpty()) 
00866         {
00867           CRTFREEIF(list);
00868           return NS_ERROR_FAILURE;
00869         }
00870         
00871         // build up the newsgroups
00872         if (!newsgroups.IsEmpty()) 
00873           newsgroups += ",";
00874         newsgroups += currentGroup;
00875       }
00876       else 
00877       {
00878         // str is "group"
00879         rv = FindHostFromGroup(currentHost, str);
00880         if (NS_FAILED(rv)) 
00881         {
00882           CRTFREEIF(list);
00883           return rv;
00884         }
00885 
00886         // build up the newsgroups
00887         if (!newsgroups.IsEmpty())
00888           newsgroups += ",";
00889         newsgroups += str;
00890       }
00891 
00892       if (!currentHost.IsEmpty())
00893       {
00894         if (host.IsEmpty()) 
00895         {
00896           host = currentHost;
00897         }
00898         else 
00899         {
00900           if (!host.Equals(currentHost)) 
00901           {
00902             CRTFREEIF(list);
00903             return NS_ERROR_NNTP_NO_CROSS_POSTING;
00904           }
00905         }
00906       }
00907 
00908       str = "";
00909       currentHost = "";
00910     }
00911     token = nsCRT::strtok(rest, ",", &rest);
00912   }
00913   CRTFREEIF(list);
00914   
00915   *newshostHeaderVal = ToNewCString(host);
00916   if (!*newshostHeaderVal) return NS_ERROR_OUT_OF_MEMORY;
00917 
00918   *newsgroupsHeaderVal = ToNewCString(newsgroups);
00919   if (!*newsgroupsHeaderVal) return NS_ERROR_OUT_OF_MEMORY;
00920   
00921   return NS_OK;
00922 }
00923 
00924 nsresult
00925 nsNntpService::GetNntpServerByAccount(const char *aAccountKey, nsIMsgIncomingServer **aNntpServer)
00926 {
00927   NS_ENSURE_ARG_POINTER(aNntpServer);
00928   nsresult rv = NS_ERROR_FAILURE;
00929 
00930   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00931   NS_ENSURE_SUCCESS(rv,rv);
00932   if (aAccountKey)
00933   {
00934     nsCOMPtr <nsIMsgAccount> account;
00935     rv = accountManager->GetAccount(aAccountKey, getter_AddRefs(account));
00936     if (NS_SUCCEEDED(rv) && account)
00937       rv = account->GetIncomingServer(aNntpServer);
00938   }
00939 
00940   // if we don't have a news host, find the first news server and use it
00941   if (NS_FAILED(rv) || !*aNntpServer)
00942     rv = accountManager->FindServer("","","nntp", aNntpServer);
00943 
00944   return rv;
00945 }
00946 
00947 NS_IMETHODIMP
00948 nsNntpService::PostMessage(nsIFileSpec *fileToPost, const char *newsgroupsNames, const char *aAccountKey, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **_retval)
00949 {
00950   // aMsgWindow might be null
00951   NS_ENSURE_ARG_POINTER(newsgroupsNames);
00952  
00953   if (*newsgroupsNames == '\0') return NS_ERROR_INVALID_ARG;
00954     
00955   NS_LOCK_INSTANCE();
00956   
00957   nsresult rv;
00958   
00959   nsCOMPtr <nsINntpUrl> nntpUrl = do_CreateInstance(NS_NNTPURL_CONTRACTID, &rv);
00960   NS_ENSURE_SUCCESS(rv,rv);
00961 
00962   rv = nntpUrl->SetNewsAction(nsINntpUrl::ActionPostArticle);
00963   NS_ENSURE_SUCCESS(rv,rv);
00964 
00965   nsXPIDLCString newsUrlSpec;
00966   rv = SetUpNntpUrlForPosting(aAccountKey, getter_Copies(newsUrlSpec));
00967   NS_ENSURE_SUCCESS(rv,rv);
00968 
00969   nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(nntpUrl, &rv);
00970   NS_ENSURE_SUCCESS(rv,rv);
00971   if (!mailnewsurl) return NS_ERROR_FAILURE;
00972 
00973   mailnewsurl->SetSpec(newsUrlSpec);
00974   
00975   if (aUrlListener) // register listener if there is one...
00976     mailnewsurl->RegisterListener(aUrlListener);
00977   
00978   nsCOMPtr <nsINNTPNewsgroupPost> post = do_CreateInstance(NS_NNTPNEWSGROUPPOST_CONTRACTID, &rv);
00979   NS_ENSURE_SUCCESS(rv,rv);
00980   if (!post) return NS_ERROR_FAILURE;
00981 
00982   rv = post->SetPostMessageFile(fileToPost);
00983   NS_ENSURE_SUCCESS(rv,rv);
00984   
00985   rv = nntpUrl->SetMessageToPost(post);
00986   NS_ENSURE_SUCCESS(rv,rv);
00987 
00988   nsCOMPtr <nsIURI> url = do_QueryInterface(nntpUrl);
00989   rv = RunNewsUrl(url, aMsgWindow, nsnull /* consumer */);
00990   NS_ENSURE_SUCCESS(rv,rv);
00991 
00992   if (_retval)
00993     rv = CallQueryInterface(nntpUrl, _retval);
00994     
00995   NS_UNLOCK_INSTANCE();
00996 
00997   return rv;
00998 }
00999 
01000 nsresult 
01001 nsNntpService::ConstructNntpUrl(const char *urlString, nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow, const char *originalMessageUri, PRInt32 action, nsIURI ** aUrl)
01002 {
01003   nsresult rv = NS_OK;
01004 
01005   nsCOMPtr <nsINntpUrl> nntpUrl = do_CreateInstance(NS_NNTPURL_CONTRACTID,&rv);
01006   NS_ENSURE_SUCCESS(rv,rv);
01007   
01008   nsCOMPtr <nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(nntpUrl);
01009   mailnewsurl->SetMsgWindow(aMsgWindow);
01010   nsCOMPtr <nsIMsgMessageUrl> msgUrl = do_QueryInterface(nntpUrl);
01011   msgUrl->SetUri(originalMessageUri);
01012   mailnewsurl->SetSpec(nsDependentCString(urlString));
01013   nntpUrl->SetNewsAction(action);
01014   
01015   if (originalMessageUri)
01016   {
01017     // we'll use this later in nsNNTPProtocol::ParseURL()
01018     rv = msgUrl->SetOriginalSpec(originalMessageUri);
01019     NS_ENSURE_SUCCESS(rv,rv);
01020   }
01021 
01022   if (aUrlListener) // register listener if there is one...
01023     mailnewsurl->RegisterListener(aUrlListener);
01024 
01025   (*aUrl) = mailnewsurl;
01026   NS_IF_ADDREF(*aUrl);
01027   return rv;
01028 }
01029 
01030 nsresult
01031 nsNntpService::CreateNewsAccount(const char *aHostname, PRBool aIsSecure, PRInt32 aPort, nsIMsgIncomingServer **aServer)
01032 {
01033   NS_ENSURE_ARG_POINTER(aHostname);
01034   NS_ENSURE_ARG_POINTER(aServer);
01035   
01036   nsresult rv;       
01037   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
01038   NS_ENSURE_SUCCESS(rv,rv);
01039   
01040   nsCOMPtr <nsIMsgAccount> account;
01041   rv = accountManager->CreateAccount(getter_AddRefs(account));
01042   if (NS_FAILED(rv)) return rv;
01043   
01044   // for news, username is always null
01045   rv = accountManager->CreateIncomingServer(nsnull /* username */, aHostname, "nntp", aServer);
01046   if (NS_FAILED(rv)) return rv;
01047   
01048   rv = (*aServer)->SetIsSecure(aIsSecure);
01049   if (NS_FAILED(rv)) return rv;
01050   
01051   rv = (*aServer)->SetPort(aPort);
01052   if (NS_FAILED(rv)) return rv;
01053   
01054   nsCOMPtr <nsIMsgIdentity> identity;
01055   rv = accountManager->CreateIdentity(getter_AddRefs(identity));
01056   if (NS_FAILED(rv)) return rv;
01057   if (!identity) return NS_ERROR_FAILURE;
01058   
01059   // by default, news accounts should be composing in plain text
01060   rv = identity->SetComposeHtml(PR_FALSE);
01061   NS_ENSURE_SUCCESS(rv,rv);
01062   
01063   // the identity isn't filled in, so it is not valid.
01064   rv = (*aServer)->SetValid(PR_FALSE);
01065   if (NS_FAILED(rv)) return rv;
01066   
01067   // hook them together
01068   rv = account->SetIncomingServer(*aServer);
01069   if (NS_FAILED(rv)) return rv;
01070   rv = account->AddIdentity(identity);
01071   if (NS_FAILED(rv)) return rv;
01072   
01073   // Now save the new acct info to pref file.
01074   rv = accountManager->SaveAccountInfo();
01075   if (NS_FAILED(rv)) return rv;
01076   
01077   return NS_OK;
01078 }
01079 
01080 nsresult
01081 nsNntpService::GetProtocolForUri(nsIURI *aUri, nsIMsgWindow *aMsgWindow, nsINNTPProtocol **aProtocol)
01082 {
01083   nsCAutoString hostName;
01084   nsCAutoString scheme;
01085   nsCAutoString path;
01086   PRInt32 port = 0;
01087   nsresult rv;
01088   
01089   rv = aUri->GetAsciiHost(hostName);
01090   rv = aUri->GetScheme(scheme);
01091   rv = aUri->GetPort(&port);
01092   rv = aUri->GetPath(path);
01093 
01094   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
01095   NS_ENSURE_SUCCESS(rv,rv);
01096 
01097   // find the incoming server, it if exists.
01098   // migrate if necessary, before searching for it.
01099   // if it doesn't exist, create it.
01100   nsCOMPtr<nsIMsgIncomingServer> server;
01101   nsCOMPtr<nsINntpIncomingServer> nntpServer;
01102 
01103 #ifdef DEBUG_sspitzer
01104   printf("for bug, #36661, see if there are any accounts, if not, try migrating.  should this be pushed into FindServer()?\n");
01105 #endif
01106   nsCOMPtr <nsISupportsArray> accounts;
01107   rv = accountManager->GetAccounts(getter_AddRefs(accounts));
01108   if (NS_FAILED(rv)) return rv;
01109 
01110   PRUint32 accountCount;
01111   rv = accounts->Count(&accountCount);
01112   if (NS_FAILED(rv)) return rv;
01113 
01114   if (accountCount == 0)
01115   {
01116        nsCOMPtr <nsIMessengerMigrator> messengerMigrator = do_GetService(kMessengerMigratorCID, &rv);
01117     if (NS_FAILED(rv)) return rv;
01118     if (!messengerMigrator) return NS_ERROR_FAILURE;
01119 
01120     // migration can fail;
01121     messengerMigrator->UpgradePrefs(); 
01122   }
01123 
01124   // news:group becomes news://group, so we have three types of urls:
01125   // news://group       (autosubscribing without a host)
01126   // news://host/group  (autosubscribing with a host)
01127   // news://host        (updating the unread message counts on a server)
01128   //
01129   // first, check if hostName is really a server or a group
01130   // by looking for a server with hostName
01131   //
01132   // xxx todo what if we have two servers on the same host, but different ports?
01133   // or no port, but isSecure (snews:// vs news://) is different?
01134   rv = accountManager->FindServerByURI(aUri, PR_FALSE,
01135                                 getter_AddRefs(server));
01136 
01137   if (!server)
01138   {
01139     // try the "real" settings ("realservername" and "realusername")
01140     rv = accountManager->FindServerByURI(aUri, PR_TRUE,
01141                                 getter_AddRefs(server));
01142   }
01143 
01144   // if we didn't find the server, and path was "/", this is a news://group url
01145   if (!server && !strcmp("/",path.get())) 
01146   {
01147     // the uri was news://group and we want to turn that into news://host/group
01148     // step 1, set the path to be the hostName;
01149     rv = aUri->SetPath(hostName);
01150     NS_ENSURE_SUCCESS(rv,rv);
01151 
01152     // until we support default news servers, use the first nntp server we find
01153     rv = accountManager->FindServerByURI(aUri, PR_FALSE, getter_AddRefs(server));
01154     if (NS_FAILED(rv) || !server)
01155     {
01156         // step 2, set the uri's hostName and the local variable hostName
01157         // to be "news"
01158         rv = aUri->SetHost(NS_LITERAL_CSTRING("news"));
01159         NS_ENSURE_SUCCESS(rv,rv);
01160 
01161         rv = aUri->GetAsciiHost(hostName);
01162         NS_ENSURE_SUCCESS(rv,rv);
01163     }
01164     else 
01165     {
01166         // step 2, set the uri's hostName and the local variable hostName
01167         // to be the host name of the server we found
01168         nsXPIDLCString hostBuf;
01169         rv = server->GetHostName(getter_Copies(hostBuf));
01170         NS_ENSURE_SUCCESS(rv,rv);
01171         hostName = hostBuf;
01172 
01173         rv = aUri->SetHost(hostName);
01174         NS_ENSURE_SUCCESS(rv,rv);
01175     }
01176   }
01177 
01178   if (NS_FAILED(rv) || !server)
01179   {
01180     PRBool isSecure = PR_FALSE;
01181     if (PL_strcasecmp("snews",scheme.get()) == 0)
01182     {
01183       isSecure = PR_TRUE;
01184       if ((port == 0) || (port == -1)) 
01185           port = SECURE_NEWS_PORT;
01186     }
01187     rv = CreateNewsAccount(hostName.get(), isSecure, port, getter_AddRefs(server));
01188   }
01189    
01190   if (NS_FAILED(rv)) return rv;
01191   if (!server) return NS_ERROR_FAILURE;
01192   
01193   nntpServer = do_QueryInterface(server, &rv);
01194 
01195   if (!nntpServer || NS_FAILED(rv))
01196     return rv;
01197 
01198   nsCAutoString spec;
01199   rv = aUri->GetSpec(spec);
01200   NS_ENSURE_SUCCESS(rv,rv);
01201 
01202 #if 0 // this not ready yet. 
01203   nsNewsAction action = nsINntpUrl::ActionUnknown;
01204   nsCOMPtr <nsINntpUrl> nntpUrl = do_QueryInterface(aUri);
01205   if (nntpUrl) {
01206     rv = nntpUrl->GetNewsAction(&action);
01207     NS_ENSURE_SUCCESS(rv,rv);
01208   }
01209 
01210   // if this is a news-message:/ uri, decompose it and set hasMsgOffline on the uri
01211   // Or, if it's of this form, we need to do the same.
01212   // "news://news.mozilla.org:119/3D612B96.1050301%40netscape.com?part=1.2&type=image/gif&filename=hp_icon_logo.gif"
01213 
01214   // XXX todo, or do we want to check if it is a news-message:// uri or
01215   // a news:// uri (but action is not a fetch related action?)
01216   if (!PL_strncmp(spec.get(), kNewsMessageRootURI, kNewsMessageRootURILen) ||
01217       (action == nsINntpUrl::ActionFetchPart || action == nsINntpUrl::ActionFetchArticle)) 
01218   {
01219 #else
01220   // if this is a news-message:/ uri, decompose it and set hasMsgOffline on the uri
01221   if (!PL_strncmp(spec.get(), kNewsMessageRootURI, kNewsMessageRootURILen)) 
01222   {
01223 #endif
01224     nsCOMPtr <nsIMsgFolder> folder;
01225     nsMsgKey key = nsMsgKey_None;
01226     rv = DecomposeNewsMessageURI(spec.get(), getter_AddRefs(folder), &key);
01227     if (NS_SUCCEEDED(rv) && folder)
01228     {
01229       PRBool hasMsgOffline = PR_FALSE;
01230       folder->HasMsgOffline(key, &hasMsgOffline);
01231       nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(aUri));
01232       if (msgUrl)
01233         msgUrl->SetMsgIsInLocalCache(hasMsgOffline);
01234     }
01235   }
01236 
01237   rv = nntpServer->GetNntpConnection(aUri, aMsgWindow, aProtocol);
01238   if (NS_FAILED(rv) || !*aProtocol) 
01239     return NS_ERROR_OUT_OF_MEMORY;
01240   return rv;
01241 }
01242 
01243 PRBool nsNntpService::WeAreOffline()
01244 {
01245        nsresult rv = NS_OK;
01246   PRBool offline = PR_FALSE;
01247 
01248   nsCOMPtr<nsIIOService> netService(do_GetService(kIOServiceCID, &rv));
01249   if (NS_SUCCEEDED(rv) && netService)
01250     netService->GetOffline(&offline);
01251 
01252   return offline;
01253 }
01254 
01255 nsresult 
01256 nsNntpService::RunNewsUrl(nsIURI * aUri, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer)
01257 {
01258   nsresult rv;
01259 
01260   if (WeAreOffline())
01261     return NS_MSG_ERROR_OFFLINE;
01262 
01263   // almost there...now create a nntp protocol instance to run the url in...
01264   nsCOMPtr <nsINNTPProtocol> nntpProtocol;
01265   rv = GetProtocolForUri(aUri, aMsgWindow, getter_AddRefs(nntpProtocol));
01266 
01267   if (NS_SUCCEEDED(rv))
01268     rv = nntpProtocol->Initialize(aUri, aMsgWindow);
01269   if (NS_FAILED(rv)) return rv;
01270   
01271   rv = nntpProtocol->LoadNewsUrl(aUri, aConsumer);
01272   return rv;
01273 }
01274 
01275 NS_IMETHODIMP nsNntpService::GetNewNews(nsINntpIncomingServer *nntpServer, const char *uri, PRBool aGetOld, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **_retval)
01276 {
01277   NS_ENSURE_ARG_POINTER(uri);
01278 
01279   NS_LOCK_INSTANCE();
01280   nsresult rv = NS_OK;
01281   
01282   nsCOMPtr<nsIMsgIncomingServer> server;
01283   server = do_QueryInterface(nntpServer);
01284  
01285   /* double check that it is a "news:/" url */
01286   if (nsCRT::strncmp(uri, kNewsRootURI, kNewsRootURILen) == 0)
01287   {
01288     nsCOMPtr<nsIURI> aUrl;
01289     rv = ConstructNntpUrl(uri, aUrlListener, aMsgWindow, nsnull, nsINntpUrl::ActionGetNewNews, getter_AddRefs(aUrl));
01290     if (NS_FAILED(rv)) return rv;
01291     
01292     nsCOMPtr<nsINntpUrl> nntpUrl = do_QueryInterface(aUrl);
01293     if (nntpUrl) 
01294     {
01295       rv = nntpUrl->SetGetOldMessages(aGetOld);
01296       if (NS_FAILED(rv)) return rv;
01297     }
01298     
01299     nsCOMPtr<nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(aUrl);
01300     if (mailNewsUrl) 
01301       mailNewsUrl->SetUpdatingFolder(PR_TRUE);
01302 
01303     rv = RunNewsUrl(aUrl, aMsgWindow, nsnull);  
01304        
01305     if (_retval) 
01306       NS_IF_ADDREF(*_retval = aUrl);
01307   }
01308   else 
01309   {
01310     NS_ASSERTION(0,"not a news:/ url");
01311     rv = NS_ERROR_FAILURE;
01312   }
01313   
01314       
01315   NS_UNLOCK_INSTANCE();
01316   return rv;
01317 }
01318 
01319 NS_IMETHODIMP 
01320 nsNntpService::CancelMessage(const char *cancelURL, const char *messageURI, nsISupports * aConsumer, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI ** aURL)
01321 {
01322   nsresult rv;
01323   NS_ENSURE_ARG_POINTER(cancelURL);
01324   NS_ENSURE_ARG_POINTER(messageURI);
01325 
01326   nsCOMPtr<nsIURI> url;
01327   // the url should be "news://host/message-id?cancel"
01328   rv = ConstructNntpUrl(cancelURL, aUrlListener,  aMsgWindow, messageURI, nsINntpUrl::ActionCancelArticle, getter_AddRefs(url));
01329   NS_ENSURE_SUCCESS(rv,rv);
01330 
01331   rv = RunNewsUrl(url, aMsgWindow, aConsumer);  
01332   NS_ENSURE_SUCCESS(rv,rv);
01333 
01334   if (aURL)
01335   {
01336     *aURL = url;
01337     NS_IF_ADDREF(*aURL);
01338   }
01339 
01340   return rv; 
01341 }
01342 
01343 NS_IMETHODIMP nsNntpService::GetScheme(nsACString &aScheme)
01344 {
01345   aScheme = "news";
01346   return NS_OK; 
01347 }
01348 
01349 NS_IMETHODIMP nsNntpService::GetDefaultDoBiff(PRBool *aDoBiff)
01350 {
01351     NS_ENSURE_ARG_POINTER(aDoBiff);
01352     // by default, don't do biff for NNTP servers
01353     *aDoBiff = PR_FALSE;    
01354     return NS_OK;
01355 }
01356 
01357 NS_IMETHODIMP nsNntpService::GetDefaultPort(PRInt32 *aDefaultPort)
01358 {
01359     NS_ENSURE_ARG_POINTER(aDefaultPort);
01360     *aDefaultPort = NEWS_PORT;
01361     return NS_OK;
01362 }
01363 
01364 NS_IMETHODIMP nsNntpService::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
01365 {
01366     *_retval = PR_TRUE; // allow news on any port
01367     return NS_OK;
01368 }
01369 
01370 NS_IMETHODIMP
01371 nsNntpService::GetDefaultServerPort(PRBool isSecure, PRInt32 *aDefaultPort)
01372 {
01373     nsresult rv = NS_OK;
01374 
01375     // Return Secure NNTP Port if secure option chosen i.e., if isSecure is TRUE
01376     if (isSecure)
01377         *aDefaultPort = SECURE_NEWS_PORT;
01378     else
01379         rv = GetDefaultPort(aDefaultPort);
01380  
01381     return rv;
01382 }
01383 
01384 NS_IMETHODIMP nsNntpService::GetProtocolFlags(PRUint32 *aUritype)
01385 {
01386     NS_ENSURE_ARG_POINTER(aUritype);
01387     *aUritype = URI_NORELATIVE | ALLOWS_PROXY;
01388     return NS_OK;
01389 }
01390 
01391 NS_IMETHODIMP nsNntpService::NewURI(const nsACString &aSpec,
01392                                     const char *aCharset, // ignored
01393                                     nsIURI *aBaseURI,
01394                                     nsIURI **_retval)
01395 {
01396     nsresult rv;
01397 
01398     nsCOMPtr<nsIURI> nntpUri = do_CreateInstance(NS_NNTPURL_CONTRACTID, &rv);
01399     NS_ENSURE_SUCCESS(rv,rv);
01400 
01401     if (aBaseURI) 
01402     {
01403       nsCAutoString newSpec;
01404       aBaseURI->Resolve(aSpec, newSpec);
01405       rv = nntpUri->SetSpec(newSpec);
01406     } 
01407     else 
01408     {
01409       rv = nntpUri->SetSpec(aSpec);
01410     }
01411     NS_ENSURE_SUCCESS(rv,rv);
01412 
01413     NS_ADDREF(*_retval = nntpUri);
01414     return NS_OK;
01415 }
01416 
01417 NS_IMETHODIMP nsNntpService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
01418 {
01419   NS_ENSURE_ARG_POINTER(aURI);
01420   nsresult rv = NS_OK;
01421   nsCOMPtr <nsINNTPProtocol> nntpProtocol;
01422   rv = GetProtocolForUri(aURI, nsnull, getter_AddRefs(nntpProtocol));
01423   if (NS_SUCCEEDED(rv))
01424     rv = nntpProtocol->Initialize(aURI, nsnull);
01425   if (NS_FAILED(rv)) return rv;
01426 
01427   return CallQueryInterface(nntpProtocol, _retval);
01428 }
01429 
01430 NS_IMETHODIMP
01431 nsNntpService::SetDefaultLocalPath(nsIFileSpec *aPath)
01432 {
01433     NS_ENSURE_ARG(aPath);
01434     
01435     nsFileSpec spec;
01436     nsresult rv = aPath->GetFileSpec(&spec);
01437     NS_ENSURE_SUCCESS(rv, rv);
01438     nsCOMPtr<nsILocalFile> localFile;
01439     NS_FileSpecToIFile(&spec, getter_AddRefs(localFile));
01440     if (!localFile) return NS_ERROR_FAILURE;
01441     
01442     return NS_SetPersistentFile(PREF_MAIL_ROOT_NNTP_REL, PREF_MAIL_ROOT_NNTP, localFile);
01443 }
01444 
01445 NS_IMETHODIMP
01446 nsNntpService::GetDefaultLocalPath(nsIFileSpec ** aResult)
01447 {
01448     NS_ENSURE_ARG_POINTER(aResult);
01449     *aResult = nsnull;
01450     
01451     nsresult rv;
01452     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
01453     if (NS_FAILED(rv)) return rv;
01454     
01455     PRBool havePref;
01456     nsCOMPtr<nsILocalFile> localFile;    
01457     rv = NS_GetPersistentFile(PREF_MAIL_ROOT_NNTP_REL,
01458                               PREF_MAIL_ROOT_NNTP,
01459                               NS_APP_NEWS_50_DIR,
01460                               havePref,
01461                               getter_AddRefs(localFile));
01462     if (NS_FAILED(rv)) return rv;
01463 
01464     PRBool exists;
01465     rv = localFile->Exists(&exists);
01466     if (NS_SUCCEEDED(rv) && !exists)
01467         rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
01468     NS_ENSURE_SUCCESS(rv, rv);    
01469     // Make the resulting nsIFileSpec
01470     // TODO: Convert arg to nsILocalFile and avoid this
01471     nsCOMPtr<nsIFileSpec> outSpec;
01472     rv = NS_NewFileSpecFromIFile(localFile, getter_AddRefs(outSpec));
01473     NS_ENSURE_SUCCESS(rv, rv);    
01474     
01475     if (!havePref || !exists)
01476     {
01477         rv = NS_SetPersistentFile(PREF_MAIL_ROOT_NNTP_REL, PREF_MAIL_ROOT_NNTP, localFile);
01478         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref.");
01479     }
01480         
01481     NS_IF_ADDREF(*aResult = outSpec);
01482     return NS_OK;
01483 }
01484     
01485 NS_IMETHODIMP
01486 nsNntpService::GetServerIID(nsIID* *aServerIID)
01487 {
01488     *aServerIID = new nsIID(NS_GET_IID(nsINntpIncomingServer));
01489     return NS_OK;
01490 }
01491 
01492 NS_IMETHODIMP
01493 nsNntpService::GetRequiresUsername(PRBool *aRequiresUsername)
01494 {
01495   NS_ENSURE_ARG_POINTER(aRequiresUsername);
01496   *aRequiresUsername = PR_FALSE;
01497   return NS_OK;
01498 }
01499 
01500 NS_IMETHODIMP
01501 nsNntpService::GetPreflightPrettyNameWithEmailAddress(PRBool *aPreflightPrettyNameWithEmailAddress)
01502 {
01503   NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress);
01504   *aPreflightPrettyNameWithEmailAddress = PR_FALSE;
01505   return NS_OK;
01506 }
01507 
01508 NS_IMETHODIMP
01509 nsNntpService::GetCanLoginAtStartUp(PRBool *aCanLoginAtStartUp)
01510 {
01511   NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
01512   *aCanLoginAtStartUp = PR_TRUE;
01513   return NS_OK;
01514 }
01515 
01516 NS_IMETHODIMP
01517 nsNntpService::GetCanDelete(PRBool *aCanDelete)
01518 {
01519   NS_ENSURE_ARG_POINTER(aCanDelete);
01520   *aCanDelete = PR_TRUE;
01521   return NS_OK;
01522 }
01523 
01524 NS_IMETHODIMP
01525 nsNntpService::GetCanDuplicate(PRBool *aCanDuplicate)
01526 {
01527   NS_ENSURE_ARG_POINTER(aCanDuplicate);
01528   *aCanDuplicate = PR_TRUE;
01529   return NS_OK;
01530 }        
01531 
01532 NS_IMETHODIMP
01533 nsNntpService::GetCanGetMessages(PRBool *aCanGetMessages)
01534 {
01535     NS_ENSURE_ARG_POINTER(aCanGetMessages);
01536     *aCanGetMessages = PR_FALSE;  // poorly named, this just means we don't have an inbox.
01537     return NS_OK;
01538 }  
01539 
01540 NS_IMETHODIMP
01541 nsNntpService::GetCanGetIncomingMessages(PRBool *aCanGetIncomingMessages)
01542 {
01543     NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
01544     // temporarily returns PR_FALSE because we don't yet support spam
01545     // filtering in news.  this will change.
01546     *aCanGetIncomingMessages = PR_FALSE;
01547     return NS_OK;
01548 } 
01549 
01550 NS_IMETHODIMP
01551 nsNntpService::GetShowComposeMsgLink(PRBool *showComposeMsgLink)
01552 {
01553     NS_ENSURE_ARG_POINTER(showComposeMsgLink);
01554     *showComposeMsgLink = PR_FALSE;
01555     return NS_OK;
01556 }  
01557 
01558 NS_IMETHODIMP
01559 nsNntpService::GetNeedToBuildSpecialFolderURIs(PRBool *needToBuildSpecialFolderURIs)
01560 {
01561     NS_ENSURE_ARG_POINTER(needToBuildSpecialFolderURIs);
01562     *needToBuildSpecialFolderURIs = PR_FALSE;
01563     return NS_OK;
01564 }
01565 
01566 NS_IMETHODIMP
01567 nsNntpService::GetSpecialFoldersDeletionAllowed(PRBool *specialFoldersDeletionAllowed)
01568 {
01569     NS_ENSURE_ARG_POINTER(specialFoldersDeletionAllowed);
01570     *specialFoldersDeletionAllowed = PR_FALSE;
01571     return NS_OK;
01572 }
01573 
01574 //
01575 // rhp: Right now, this is the same as simple DisplayMessage, but it will change
01576 // to support print rendering.
01577 //
01578 NS_IMETHODIMP nsNntpService::DisplayMessageForPrinting(const char* aMessageURI, nsISupports * aDisplayConsumer, 
01579                                                   nsIMsgWindow *aMsgWindow, nsIUrlListener * aUrlListener, nsIURI ** aURL)
01580 {
01581   mPrintingOperation = PR_TRUE;
01582   nsresult rv = DisplayMessage(aMessageURI, aDisplayConsumer, aMsgWindow, aUrlListener, nsnull, aURL);
01583   mPrintingOperation = PR_FALSE;
01584   return rv;
01585 }
01586 
01587 NS_IMETHODIMP
01588 nsNntpService::StreamMessage(const char *aMessageURI, nsISupports *aConsumer, 
01589                               nsIMsgWindow *aMsgWindow,
01590                               nsIUrlListener *aUrlListener, 
01591                               PRBool /* convertData */,
01592                               const char *aAdditionalHeader,
01593                               nsIURI **aURL)
01594 {
01595     // The nntp protocol object will look for "header=filter" to decide if it wants to convert 
01596     // the data instead of using aConvertData. It turns out to be way too hard to pass aConvertData 
01597     // all the way over to the nntp protocol object.
01598     nsCAutoString aURIString(aMessageURI);
01599     if (aAdditionalHeader)
01600     {
01601       aURIString.FindChar('?') == kNotFound ? aURIString += "?" : aURIString += "&";
01602       aURIString += "header=";
01603       aURIString += aAdditionalHeader;
01604     }
01605     return DisplayMessage(aURIString.get(), aConsumer, aMsgWindow, aUrlListener, nsnull, aURL);
01606 }
01607 
01608 NS_IMETHODIMP nsNntpService::Search(nsIMsgSearchSession *aSearchSession, nsIMsgWindow *aMsgWindow, nsIMsgFolder *aMsgFolder, const char *aSearchUri)
01609 {
01610   NS_ENSURE_ARG(aMsgFolder);
01611   NS_ENSURE_ARG(aSearchUri);
01612     
01613   nsresult rv;
01614 
01615   nsXPIDLCString folderUri;
01616   rv = aMsgFolder->GetURI(getter_Copies(folderUri));
01617   NS_ENSURE_SUCCESS(rv,rv);
01618 
01619   nsCAutoString searchUrl((const char *)folderUri);
01620   searchUrl += aSearchUri;
01621   nsCOMPtr <nsIUrlListener> urlListener = do_QueryInterface(aSearchSession);
01622 
01623   nsCOMPtr<nsIURI> url;
01624   rv = ConstructNntpUrl(searchUrl.get(), urlListener, aMsgWindow, nsnull, nsINntpUrl::ActionSearch, getter_AddRefs(url));
01625   NS_ENSURE_SUCCESS(rv,rv);
01626 
01627   nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(url));
01628   if (msgurl)
01629     msgurl->SetSearchSession(aSearchSession);
01630 
01631   // run the url to update the counts
01632   rv = RunNewsUrl(url, nsnull, nsnull);  
01633   NS_ENSURE_SUCCESS(rv,rv);
01634   return NS_OK;
01635 }
01636 
01637 
01638 NS_IMETHODIMP
01639 nsNntpService::UpdateCounts(nsINntpIncomingServer *aNntpServer, nsIMsgWindow *aMsgWindow)
01640 {
01641   nsresult rv;
01642   NS_ENSURE_ARG_POINTER(aNntpServer);
01643   
01644   nsCOMPtr<nsIURI> url;
01645   nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(aNntpServer, &rv);
01646   if (NS_FAILED(rv)) return rv;
01647   if (!server) return NS_ERROR_FAILURE;
01648   
01649   nsXPIDLCString serverUri;
01650   rv = server->GetServerURI(getter_Copies(serverUri));
01651   if (NS_FAILED(rv)) return rv;
01652   
01653   rv = ConstructNntpUrl((const char *)serverUri, nsnull, aMsgWindow, nsnull, nsINntpUrl::ActionUpdateCounts, getter_AddRefs(url));
01654   if (NS_FAILED(rv)) return rv;
01655   
01656   // run the url to update the counts
01657   rv = RunNewsUrl(url, aMsgWindow, nsnull);
01658   
01659   // being offline is not an error.
01660   if (NS_SUCCEEDED(rv) || (rv == NS_MSG_ERROR_OFFLINE))
01661     return NS_OK;
01662 
01663   return rv;
01664 }
01665 
01666 NS_IMETHODIMP 
01667 nsNntpService::GetListOfGroupsOnServer(nsINntpIncomingServer *aNntpServer, nsIMsgWindow *aMsgWindow)
01668 {
01669   nsresult rv;
01670   
01671   NS_ENSURE_ARG_POINTER(aNntpServer);
01672   
01673   nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(aNntpServer, &rv);
01674   if (NS_FAILED(rv)) return rv;
01675   if (!server) return NS_ERROR_FAILURE;
01676   
01677   nsXPIDLCString serverUri;
01678   rv = server->GetServerURI(getter_Copies(serverUri));
01679   
01680   nsCAutoString uriStr;
01681   uriStr += (const char *)serverUri;
01682   uriStr += "/*";
01683               
01684   nsCOMPtr <nsIUrlListener> listener = do_QueryInterface(aNntpServer, &rv);
01685   if (NS_FAILED(rv)) 
01686     return rv;
01687   if (!listener) 
01688     return NS_ERROR_FAILURE;
01689   
01690   nsCOMPtr<nsIURI> url;
01691   rv = ConstructNntpUrl(uriStr.get(), listener, aMsgWindow, nsnull, nsINntpUrl::ActionListGroups, getter_AddRefs(url));
01692   if (NS_FAILED(rv)) 
01693     return rv;
01694   
01695   // now run the url to add the rest of the groups
01696   rv = RunNewsUrl(url, aMsgWindow, nsnull);
01697   if (NS_FAILED(rv))
01698     return rv;
01699   
01700   return NS_OK;
01701 }
01702 
01703 
01704 #ifdef MOZ_XUL_APP
01705 
01706 NS_IMETHODIMP
01707 nsNntpService::Handle(nsICommandLine* aCmdLine)
01708 {
01709   nsresult rv;
01710   PRBool found;
01711 
01712   rv = aCmdLine->HandleFlag(NS_LITERAL_STRING("news"), PR_FALSE, &found);
01713   if (NS_SUCCEEDED(rv) && found) {
01714     nsCOMPtr<nsIWindowWatcher> wwatch (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
01715     NS_ENSURE_TRUE(wwatch, NS_ERROR_FAILURE);
01716 
01717     nsCOMPtr<nsIDOMWindow> opened;
01718     wwatch->OpenWindow(nsnull, "chrome://messenger/content/", "_blank",
01719                        "chrome,dialog=no,all", nsnull, getter_AddRefs(opened));
01720     aCmdLine->SetPreventDefault(PR_TRUE);
01721   }
01722 
01723   return NS_OK;
01724 }
01725 
01726 NS_IMETHODIMP
01727 nsNntpService::GetHelpInfo(nsACString& aResult)
01728 {
01729   aResult.Assign(NS_LITERAL_CSTRING("  -news                Open the news client.\n"));
01730   return NS_OK;
01731 }
01732 
01733 #else // MOZ_XUL_APP
01734 
01735 CMDLINEHANDLER3_IMPL(nsNntpService,"-news","general.startup.news","Start with news.",NS_NEWSSTARTUPHANDLER_CONTRACTID,"News Cmd Line Handler", PR_FALSE,"", PR_TRUE)
01736 
01737 NS_IMETHODIMP nsNntpService::GetChromeUrlForTask(char **aChromeUrlForTask) 
01738 { 
01739   if (!aChromeUrlForTask) return NS_ERROR_FAILURE; 
01740   nsresult rv;
01741   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
01742   if (NS_SUCCEEDED(rv))
01743   {
01744     PRInt32 layout;
01745     rv = prefBranch->GetIntPref("mail.pane_config", &layout);         
01746     if(NS_SUCCEEDED(rv))
01747     {
01748       if(layout == 0)
01749         *aChromeUrlForTask = PL_strdup("chrome://messenger/content/messenger.xul");
01750       else
01751         *aChromeUrlForTask = PL_strdup("chrome://messenger/content/mail3PaneWindowVertLayout.xul");
01752       
01753       return NS_OK;
01754       
01755     }  
01756   }
01757   *aChromeUrlForTask = PL_strdup("chrome://messenger/content/messenger.xul"); 
01758   return NS_OK; 
01759 }
01760 #endif // MOZ_XUL_APP
01761 
01762 NS_IMETHODIMP 
01763 nsNntpService::HandleContent(const char * aContentType, nsIInterfaceRequestor* aWindowContext, nsIRequest *request)
01764 {
01765   nsresult rv;
01766   NS_ENSURE_ARG_POINTER(request);
01767   
01768   nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request, &rv);
01769   NS_ENSURE_SUCCESS(rv, rv);
01770 
01771   // check for x-application-newsgroup or x-application-newsgroup-listids
01772   if (PL_strncasecmp(aContentType, "x-application-newsgroup", 23) == 0)
01773   {
01774     nsCOMPtr<nsIURI> uri;
01775     rv = aChannel->GetURI(getter_AddRefs(uri));
01776     NS_ENSURE_SUCCESS(rv, rv);
01777     if (uri)
01778     {
01779       nsXPIDLCString uriStr;
01780       nsCOMPtr <nsIMsgFolder> msgFolder;
01781       nsCOMPtr <nsINNTPProtocol> protocol = do_QueryInterface(aChannel);
01782       if (protocol)
01783         protocol->GetCurrentFolder(getter_AddRefs(msgFolder));
01784       if (msgFolder)
01785         msgFolder->GetURI(getter_Copies(uriStr));
01786 
01787       if (!uriStr.IsEmpty())
01788       {
01789         nsCOMPtr <nsIURI> originalUri;
01790         aChannel->GetOriginalURI(getter_AddRefs(originalUri));
01791         if (originalUri)
01792         {
01793           nsCOMPtr <nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(originalUri);
01794           if (mailUrl)
01795           {
01796             nsCOMPtr <nsIMsgWindow> msgWindow;
01797             mailUrl->GetMsgWindow(getter_AddRefs(msgWindow));
01798             if (msgWindow)
01799               msgWindow->SelectFolder(uriStr);
01800           }
01801         }
01802       }
01803     }
01804   } else 
01805   {
01806     // The content-type was not x-application-newsgroup.
01807     return NS_ERROR_WONT_HANDLE_CONTENT;
01808   }
01809 
01810   return rv;
01811 }
01812 
01813 NS_IMETHODIMP
01814 nsNntpService::MessageURIToMsgHdr(const char *uri, nsIMsgDBHdr **_retval)
01815 {
01816   NS_ENSURE_ARG_POINTER(uri);
01817   NS_ENSURE_ARG_POINTER(_retval);
01818   nsresult rv = NS_OK;
01819 
01820   nsCOMPtr <nsIMsgFolder> folder;
01821   nsMsgKey msgKey;
01822 
01823   rv = DecomposeNewsMessageURI(uri, getter_AddRefs(folder), &msgKey);
01824   NS_ENSURE_SUCCESS(rv,rv);
01825 
01826   rv = folder->GetMessageHeader(msgKey, _retval);
01827   NS_ENSURE_SUCCESS(rv,rv);
01828   return NS_OK;
01829 }
01830 
01831 NS_IMETHODIMP
01832 nsNntpService::DownloadNewsgroupsForOffline(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener)
01833 {
01834   nsresult rv = NS_OK;
01835   nsMsgDownloadAllNewsgroups *newsgroupDownloader = new nsMsgDownloadAllNewsgroups(aMsgWindow, aListener);
01836   if (newsgroupDownloader)
01837     rv = newsgroupDownloader->ProcessNextGroup();
01838   else
01839     rv = NS_ERROR_OUT_OF_MEMORY;
01840   return rv;
01841 }
01842 
01843 NS_IMETHODIMP nsNntpService::GetCacheSession(nsICacheSession **result)
01844 {
01845   nsresult rv = NS_OK;
01846   if (!mCacheSession)
01847   {
01848     nsCOMPtr<nsICacheService> serv = do_GetService(kCacheServiceCID, &rv);
01849     NS_ENSURE_SUCCESS(rv, rv);
01850     
01851     rv = serv->CreateSession("NNTP-memory-only", nsICache::STORE_IN_MEMORY, nsICache::STREAM_BASED, getter_AddRefs(mCacheSession));
01852     NS_ENSURE_SUCCESS(rv, rv);
01853     rv = mCacheSession->SetDoomEntriesIfExpired(PR_FALSE);
01854   }
01855 
01856   *result = mCacheSession;
01857   NS_IF_ADDREF(*result);
01858   return rv;
01859 }