Back to index

lightning-sunbird  0.9+nobinonly
nsMsgWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsMsgWindow.h"
00039 #include "nsReadableUtils.h"
00040 #include "nsIURILoader.h"
00041 #include "nsCURILoader.h"
00042 #include "nsIDocShell.h"
00043 #include "nsIDocShellTreeItem.h"
00044 #include "nsIDocShellTreeNode.h"
00045 #include "nsIScriptGlobalObject.h"
00046 #include "nsIDOMElement.h"
00047 #include "nsIDOMWindowInternal.h"
00048 #include "nsTransactionManagerCID.h"
00049 #include "nsIComponentManager.h"
00050 #include "nsIDocumentLoader.h"
00051 #include "nsILoadGroup.h"
00052 #include "nsIMsgMailNewsUrl.h"
00053 #include "nsIInterfaceRequestor.h"
00054 #include "nsIInterfaceRequestorUtils.h"
00055 #include "nsIWebProgress.h"
00056 #include "nsIWebProgressListener.h"
00057 #include "nsPIDOMWindow.h"
00058 #include "nsIPrompt.h"
00059 #include "nsIAuthPrompt.h"
00060 #include "nsICharsetAlias.h"
00061 #include "nsIChannel.h"
00062 #include "nsIRequestObserver.h"
00063 #include "netCore.h"
00064 
00065 #include "plbase64.h"
00066 #include "nsMsgI18N.h"
00067 #include "nsIWebNavigation.h"
00068 #include "nsISupportsObsolete.h"
00069 
00070 // used to dispatch urls to default protocol handlers
00071 #include "nsCExternalHandlerService.h"
00072 #include "nsIExternalProtocolService.h"
00073 
00074 static NS_DEFINE_CID(kTransactionManagerCID, NS_TRANSACTIONMANAGER_CID);
00075 
00076 NS_IMPL_THREADSAFE_ISUPPORTS3(nsMsgWindow,
00077                               nsIMsgWindow,
00078                               nsIURIContentListener,
00079                               nsISupportsWeakReference)
00080 
00081 nsMsgWindow::nsMsgWindow()
00082 {
00083   mCharsetOverride = PR_FALSE;
00084   m_stopped = PR_FALSE;
00085 }
00086 
00087 nsMsgWindow::~nsMsgWindow()
00088 {
00089   CloseWindow();
00090 }
00091 
00092 nsresult nsMsgWindow::Init()
00093 {
00094   // register ourselves as a content listener with the uri dispatcher service
00095   nsresult rv;
00096   nsCOMPtr<nsIURILoader> dispatcher = 
00097            do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
00098   if (NS_FAILED(rv))
00099     return rv;
00100 
00101   rv = dispatcher->RegisterContentListener(this);
00102   if (NS_FAILED(rv))
00103     return rv;
00104 
00105   // create Undo/Redo Transaction Manager
00106   mTransactionManager = do_CreateInstance(kTransactionManagerCID, &rv);
00107   if (NS_SUCCEEDED(rv))
00108     mTransactionManager->SetMaxTransactionCount(-1);
00109 
00110   return rv;
00111 }
00112 
00113 void nsMsgWindow::GetMessageWindowDocShell(nsIDocShell ** aDocShell)
00114 {
00115   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mMessageWindowDocShellWeak));
00116   if (!docShell)
00117   {
00118     // if we don't have a docshell, then we need to look up the message pane docshell
00119     nsCOMPtr<nsIDocShell> rootShell(do_QueryReferent(mRootDocShellWeak));
00120     if (rootShell)
00121     {
00122       nsCOMPtr<nsIDocShellTreeNode> rootAsNode(do_QueryInterface(rootShell));
00123 
00124       nsCOMPtr<nsIDocShellTreeItem> msgDocShellItem;
00125       if(rootAsNode)
00126          rootAsNode->FindChildWithName(NS_LITERAL_STRING("messagepane").get(),
00127                                        PR_TRUE, PR_FALSE, nsnull, nsnull,
00128                                        getter_AddRefs(msgDocShellItem));
00129 
00130       docShell = do_QueryInterface(msgDocShellItem);
00131       // we don't own mMessageWindowDocShell so don't try to keep a reference to it!
00132       mMessageWindowDocShellWeak = do_GetWeakReference(docShell);
00133     }
00134   }
00135 
00136   *aDocShell = docShell;
00137   NS_IF_ADDREF(*aDocShell);
00138 }
00139 
00140 /* void SelectFolder (in string folderUri); */
00141 NS_IMETHODIMP nsMsgWindow::SelectFolder(const char *folderUri)
00142 {
00143        return mMsgWindowCommands->SelectFolder(folderUri);
00144 }
00145 
00146 /* void SelectMessage (in string messasgeUri); */
00147 NS_IMETHODIMP nsMsgWindow::SelectMessage(const char *messageUri)
00148 {
00149     return (mMsgWindowCommands) ? mMsgWindowCommands->SelectMessage(messageUri)
00150       : NS_ERROR_NULL_POINTER;;
00151 }
00152 
00153 NS_IMETHODIMP nsMsgWindow::CloseWindow()
00154 {
00155   nsresult rv = NS_OK;
00156   nsCOMPtr<nsIURILoader> dispatcher = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
00157   if (NS_SUCCEEDED(rv)) 
00158     rv = dispatcher->UnRegisterContentListener(this);
00159 
00160   // make sure the status feedback object
00161   // knows the window is going away...
00162 
00163   if (mStatusFeedback)
00164     mStatusFeedback->CloseWindow(); 
00165 
00166   mMsgPaneController = nsnull;
00167 
00168   StopUrls();
00169 
00170   nsCOMPtr<nsIDocShell> rootShell(do_QueryReferent(mRootDocShellWeak));
00171   if(rootShell)
00172   {
00173     nsCOMPtr<nsIURIContentListener> listener(do_GetInterface(rootShell));
00174     if (listener) {
00175       listener->SetParentContentListener(nsnull);
00176     }
00177     mRootDocShellWeak = nsnull;
00178     mMessageWindowDocShellWeak = nsnull;
00179   }
00180 
00181 
00182   // in case nsMsgWindow leaks, make sure other stuff doesn't leak.
00183   mTransactionManager = nsnull;
00184   return NS_OK;
00185 }
00186 
00187 NS_IMETHODIMP nsMsgWindow::GetStatusFeedback(nsIMsgStatusFeedback * *aStatusFeedback)
00188 {
00189        if(!aStatusFeedback)
00190               return NS_ERROR_NULL_POINTER;
00191 
00192        *aStatusFeedback = mStatusFeedback;
00193        NS_IF_ADDREF(*aStatusFeedback);
00194        return NS_OK;
00195 }
00196 
00197 NS_IMETHODIMP nsMsgWindow::SetStatusFeedback(nsIMsgStatusFeedback * aStatusFeedback)
00198 {
00199   nsCOMPtr<nsIDocShell> messageWindowDocShell; 
00200   GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
00201 
00202   nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(messageWindowDocShell));
00203   mStatusFeedback = aStatusFeedback;
00204 
00205   // register our status feedback object
00206   if (webProgress && mStatusFeedback && messageWindowDocShell)
00207   {
00208     nsCOMPtr<nsIWebProgressListener> webProgressListener = do_QueryInterface(mStatusFeedback);
00209     webProgress->AddProgressListener(webProgressListener, nsIWebProgress::NOTIFY_ALL);
00210   }
00211 
00212        return NS_OK;
00213 }
00214 
00215 NS_IMETHODIMP nsMsgWindow::GetMessagePaneController(nsIMsgMessagePaneController * * aMsgPaneController)
00216 {
00217   NS_ENSURE_ARG(aMsgPaneController);
00218 
00219   *aMsgPaneController = mMsgPaneController;
00220        NS_IF_ADDREF(*aMsgPaneController);
00221        return NS_OK;
00222 }
00223 
00224 NS_IMETHODIMP nsMsgWindow::SetMessagePaneController(nsIMsgMessagePaneController * aMsgPaneController)
00225 {
00226        mMsgPaneController = aMsgPaneController;
00227        return NS_OK;
00228 }
00229 
00230 NS_IMETHODIMP nsMsgWindow::GetMsgHeaderSink(nsIMsgHeaderSink * *aMsgHdrSink)
00231 {
00232        if(!aMsgHdrSink)
00233               return NS_ERROR_NULL_POINTER;
00234 
00235        *aMsgHdrSink = mMsgHeaderSink;
00236        NS_IF_ADDREF(*aMsgHdrSink);
00237        return NS_OK;
00238 }
00239 
00240 NS_IMETHODIMP nsMsgWindow::SetMsgHeaderSink(nsIMsgHeaderSink * aMsgHdrSink)
00241 {
00242        mMsgHeaderSink = aMsgHdrSink;
00243        return NS_OK;
00244 }
00245 
00246 NS_IMETHODIMP nsMsgWindow::GetTransactionManager(nsITransactionManager * *aTransactionManager)
00247 {
00248        NS_ENSURE_ARG_POINTER(aTransactionManager);
00249        NS_IF_ADDREF(*aTransactionManager = mTransactionManager);
00250        return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP nsMsgWindow::SetTransactionManager(nsITransactionManager * aTransactionManager)
00254 {
00255        mTransactionManager = aTransactionManager;
00256        return NS_OK;
00257 }
00258 
00259 NS_IMETHODIMP nsMsgWindow::GetOpenFolder(nsIMsgFolder * *aOpenFolder)
00260 {
00261        NS_ENSURE_ARG_POINTER(aOpenFolder);
00262        NS_IF_ADDREF(*aOpenFolder = mOpenFolder);
00263        return NS_OK;
00264 }
00265 
00266 NS_IMETHODIMP nsMsgWindow::SetOpenFolder(nsIMsgFolder * aOpenFolder)
00267 {
00268        mOpenFolder = aOpenFolder;
00269        return NS_OK;
00270 }
00271 
00272 NS_IMETHODIMP nsMsgWindow::GetRootDocShell(nsIDocShell * *aDocShell)
00273 {
00274   if (mRootDocShellWeak) {
00275     CallQueryReferent(mRootDocShellWeak.get(), aDocShell);
00276   } else {
00277     *aDocShell = nsnull;
00278   }
00279   
00280   return NS_OK;
00281 }
00282 
00283 NS_IMETHODIMP nsMsgWindow::SetRootDocShell(nsIDocShell * aDocShell)
00284 {
00285   // Query for the doc shell and release it
00286   mRootDocShellWeak = nsnull;
00287   if (aDocShell)
00288   {
00289     mRootDocShellWeak = do_GetWeakReference(aDocShell);
00290     nsCOMPtr<nsIURIContentListener> listener(do_GetInterface(aDocShell));
00291     if (listener)
00292       listener->SetParentContentListener(this);
00293   }
00294   return NS_OK;
00295 }
00296 
00297 NS_IMETHODIMP nsMsgWindow::GetMailCharacterSet(char * *aMailCharacterSet)
00298 {
00299   if(!aMailCharacterSet)
00300     return NS_ERROR_NULL_POINTER;
00301 
00302   *aMailCharacterSet = ToNewCString(mMailCharacterSet);
00303   if (!(*aMailCharacterSet))
00304     return NS_ERROR_OUT_OF_MEMORY;
00305 
00306   return NS_OK;
00307 }
00308 
00309 NS_IMETHODIMP nsMsgWindow::SetMailCharacterSet(const char * aMailCharacterSet)
00310 {
00311   mMailCharacterSet.Assign(aMailCharacterSet);
00312 
00313   // Convert to a canonical charset name instead of using the charset name from the message header as is.
00314   // This is needed for charset menu item to have a check mark correctly.
00315   nsresult rv;
00316   nsCOMPtr<nsICharsetAlias> calias =
00317       do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv);
00318   
00319   if (NS_SUCCEEDED(rv)) 
00320       calias->GetPreferred(nsDependentCString(aMailCharacterSet),
00321                            mMailCharacterSet);
00322 
00323   return NS_OK;
00324 }
00325 
00326 NS_IMETHODIMP nsMsgWindow::GetCharsetOverride(PRBool *aCharsetOverride)
00327 {
00328   NS_ENSURE_ARG_POINTER(aCharsetOverride);
00329   *aCharsetOverride = mCharsetOverride;
00330   return NS_OK;
00331 }
00332 
00333 NS_IMETHODIMP nsMsgWindow::SetCharsetOverride(PRBool aCharsetOverride)
00334 {
00335   mCharsetOverride = aCharsetOverride;
00336   return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP nsMsgWindow::SetDOMWindow(nsIDOMWindowInternal *aWindow)
00340 {
00341        if (!aWindow)
00342               return NS_ERROR_NULL_POINTER;
00343 
00344        nsresult rv = NS_OK;
00345 
00346        nsCOMPtr<nsIScriptGlobalObject> globalScript(do_QueryInterface(aWindow));
00347   nsIDocShell *docShell = nsnull;
00348        if (globalScript)
00349               docShell = globalScript->GetDocShell();
00350 
00351   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
00352 
00353   if(docShellAsItem)
00354   {
00355     nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
00356     docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
00357 
00358     nsCOMPtr<nsIDocShell> rootAsShell(do_QueryInterface(rootAsItem));
00359     SetRootDocShell(rootAsShell);
00360 
00361     // force ourselves to figure out the message pane
00362     nsCOMPtr<nsIDocShell> messageWindowDocShell; 
00363     GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
00364     SetStatusFeedback(mStatusFeedback);
00365   }
00366 
00367        //Get nsIMsgWindowCommands object 
00368   nsCOMPtr<nsISupports> xpConnectObj;
00369   nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(aWindow));
00370   if (piDOMWindow)
00371   {
00372     piDOMWindow->GetObjectProperty(NS_LITERAL_STRING("MsgWindowCommands").get(), getter_AddRefs(xpConnectObj));
00373     mMsgWindowCommands = do_QueryInterface(xpConnectObj);
00374   }
00375 
00376   return rv;
00377 }
00378 
00379 NS_IMETHODIMP nsMsgWindow::StopUrls()
00380 {
00381   m_stopped = PR_TRUE;
00382   nsCOMPtr<nsIWebNavigation> webnav(do_QueryReferent(mRootDocShellWeak));
00383   if (webnav)
00384   {
00385     return webnav->Stop(nsIWebNavigation::STOP_NETWORK);
00386   }
00387   
00388   return NS_ERROR_NULL_POINTER;
00389 }
00390 
00391 
00392 // nsIURIContentListener support
00393 NS_IMETHODIMP nsMsgWindow::OnStartURIOpen(nsIURI* aURI, PRBool* aAbortOpen)
00394 {
00395   return NS_OK;
00396 }
00397 
00398 NS_IMETHODIMP nsMsgWindow::DoContent(const char *aContentType, PRBool aIsContentPreferred,
00399                                      nsIRequest *request, nsIStreamListener **aContentHandler, PRBool *aAbortProcess)
00400 {
00401   if (aContentType)
00402   {
00403     // forward the DoContent call to our docshell
00404     nsCOMPtr<nsIDocShell> messageWindowDocShell; 
00405     GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
00406     nsCOMPtr<nsIURIContentListener> ctnListener = do_QueryInterface(messageWindowDocShell);
00407     if (ctnListener)
00408     {
00409         nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
00410         if (!aChannel) return NS_ERROR_FAILURE;
00411 
00412       // get the url for the channel...let's hope it is a mailnews url so we can set our msg hdr sink on it..
00413       // right now, this is the only way I can think of to force the msg hdr sink into the mime converter so it can
00414       // get too it later...
00415       nsCOMPtr<nsIURI> uri;
00416       aChannel->GetURI(getter_AddRefs(uri));
00417       if (uri)
00418       {
00419         nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl(do_QueryInterface(uri));
00420         if (mailnewsUrl)
00421           mailnewsUrl->SetMsgWindow(this);
00422       }
00423       return ctnListener->DoContent(aContentType, aIsContentPreferred, request, aContentHandler, aAbortProcess);
00424     }
00425   }
00426   return NS_OK;
00427 }
00428 
00429 NS_IMETHODIMP 
00430 nsMsgWindow::IsPreferred(const char * aContentType,
00431                          char ** aDesiredContentType,
00432                          PRBool * aCanHandleContent)
00433 {
00434   *aCanHandleContent = PR_FALSE;
00435   return NS_OK;
00436 }
00437 
00438 NS_IMETHODIMP nsMsgWindow::CanHandleContent(const char * aContentType,
00439                                             PRBool aIsContentPreferred,
00440                                             char ** aDesiredContentType,
00441                                             PRBool * aCanHandleContent)
00442 
00443 {
00444   // the mail window knows nothing about the default content types
00445   // its docshell can handle...ask the content area if it can handle
00446   // the content type...
00447   
00448   nsCOMPtr<nsIDocShell> messageWindowDocShell; 
00449   GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
00450   nsCOMPtr<nsIURIContentListener> ctnListener (do_GetInterface(messageWindowDocShell));
00451   if (ctnListener)
00452     return ctnListener->CanHandleContent(aContentType, aIsContentPreferred,
00453                                          aDesiredContentType, aCanHandleContent);
00454   else
00455     *aCanHandleContent = PR_FALSE;
00456   return NS_OK;
00457 }
00458 
00459 NS_IMETHODIMP nsMsgWindow::GetParentContentListener(nsIURIContentListener** aParent)
00460 {
00461   *aParent = nsnull;
00462   return NS_OK;
00463 }
00464 
00465 NS_IMETHODIMP nsMsgWindow::SetParentContentListener(nsIURIContentListener* aParent)
00466 {
00467   return NS_OK;
00468 }
00469 
00470 NS_IMETHODIMP nsMsgWindow::GetLoadCookie(nsISupports ** aLoadCookie)
00471 {
00472   *aLoadCookie = nsnull;
00473   return NS_OK;
00474 }
00475 
00476 NS_IMETHODIMP nsMsgWindow::SetLoadCookie(nsISupports * aLoadCookie)
00477 {
00478   return NS_OK;
00479 }
00480 
00481 NS_IMETHODIMP nsMsgWindow::GetPromptDialog(nsIPrompt **aPrompt)
00482 {
00483   nsresult rv = NS_OK;
00484   NS_ENSURE_ARG_POINTER(aPrompt);
00485   nsCOMPtr<nsIDocShell> rootShell(do_QueryReferent(mRootDocShellWeak));
00486   if (rootShell)
00487   {
00488     nsCOMPtr<nsIPrompt> dialog;
00489     dialog = do_GetInterface(rootShell, &rv);
00490     if (dialog)
00491     {
00492       *aPrompt = dialog;
00493       NS_ADDREF(*aPrompt);
00494     }
00495     return rv;
00496   }
00497   else
00498     return NS_ERROR_NULL_POINTER;
00499 }
00500 
00501 NS_IMETHODIMP 
00502 nsMsgWindow::DisplayHTMLInMessagePane(const PRUnichar *title, const PRUnichar *body, PRBool clearMsgHdr)
00503 {
00504   nsresult rv;
00505 
00506   if (clearMsgHdr && mMsgPaneController)
00507     mMsgPaneController->ClearMsgPane();
00508 
00509   nsString htmlStr;
00510   htmlStr.Append(NS_LITERAL_STRING("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body>").get());
00511   htmlStr.Append(body);
00512   htmlStr.Append(NS_LITERAL_STRING("</body></html>").get());
00513 
00514   char *encodedHtml = PL_Base64Encode(NS_ConvertUCS2toUTF8(htmlStr).get(), 0, nsnull);
00515   if (!encodedHtml)
00516     return NS_ERROR_OUT_OF_MEMORY;
00517 
00518   nsCString dataSpec;
00519   dataSpec = "data:text/html;base64,";
00520   dataSpec += encodedHtml;
00521 
00522   PR_FREEIF(encodedHtml);
00523 
00524   nsCOMPtr <nsIURI> uri = do_CreateInstance("@mozilla.org/network/simple-uri;1");
00525   if (!uri) return NS_ERROR_UNEXPECTED;
00526 
00527   rv = uri->SetSpec(dataSpec);
00528   NS_ENSURE_SUCCESS(rv,rv);
00529 
00530   nsCOMPtr <nsIDocShell> docShell;
00531   GetMessageWindowDocShell(getter_AddRefs(docShell));
00532   if (!docShell) return NS_ERROR_UNEXPECTED;
00533 
00534   rv = docShell->LoadURI(uri,nsnull,nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
00535   NS_ENSURE_SUCCESS(rv,rv);
00536 
00537   return NS_OK;
00538 }
00539 
00540 NS_IMPL_GETSET(nsMsgWindow, Stopped, PRBool, m_stopped)