Back to index

lightning-sunbird  0.9+nobinonly
nsMsgComposeService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jean-Francois Ducarroz <ducarroz@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *   Seth Spitzer <sspitzer@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #ifdef MOZ_LOGGING
00042 #define FORCE_PR_LOG /* Allow logging in the release build (sorry this breaks the PCH) */
00043 #endif
00044 
00045 #include "nsMsgComposeService.h"
00046 #include "nsMsgCompCID.h"
00047 #include "nsIMsgSend.h"
00048 #include "nsISupportsArray.h"
00049 #include "nsIServiceManager.h"
00050 #include "nsIObserverService.h"
00051 #include "nsXPIDLString.h"
00052 #include "nsIMsgIdentity.h"
00053 #include "nsISmtpUrl.h"
00054 #include "nsIURI.h"
00055 #include "nsMsgI18N.h"
00056 #include "nsIMsgComposeParams.h"
00057 #include "nsXPCOM.h"
00058 #include "nsISupportsPrimitives.h"
00059 #include "nsIWindowWatcher.h"
00060 #include "nsIDOMWindow.h"
00061 #include "nsEscape.h"
00062 #include "nsIContentViewer.h"
00063 #include "nsMsgWindow.h"
00064 #include "nsIDocShell.h"
00065 #include "nsIScriptGlobalObject.h"
00066 #include "nsIDOMDocument.h"
00067 #include "nsIDOMElement.h"
00068 #include "nsIXULWindow.h"
00069 #include "nsIWindowMediator.h"
00070 #include "nsIDocShellTreeItem.h"
00071 #include "nsIDocShellTreeOwner.h"
00072 #include "nsIBaseWindow.h"
00073 #include "nsIPrefService.h"
00074 #include "nsIPrefBranch.h"
00075 #include "nsIPrefBranch2.h"
00076 #include "nsMsgBaseCID.h"
00077 #include "nsIMsgAccountManager.h"
00078 #include "nsIMimeMiscStatus.h"
00079 
00080 #include "nsIInterfaceRequestorUtils.h"
00081 
00082 #ifdef MSGCOMP_TRACE_PERFORMANCE
00083 #include "prlog.h"
00084 #include "nsIMsgHdr.h"
00085 #include "nsIMsgMessageService.h"
00086 #include "nsMsgUtils.h"
00087 #endif
00088 
00089 // <for functions="HTMLSantinize">
00090 #include "nsIParser.h"
00091 #include "nsParserCIID.h"
00092 #include "nsIContentSink.h"
00093 #include "mozISanitizingSerializer.h"
00094 
00095 #include "nsMsgMimeCID.h"
00096 #include "nsNetUtil.h"
00097 #include "nsIMsgMailNewsUrl.h"
00098 #include "nsIMimeStreamConverter.h"
00099 #include "nsIStreamConverter.h"
00100 
00101 #ifdef MOZ_XUL_APP
00102 #include "nsICommandLine.h"
00103 #endif
00104 
00105 #ifdef XP_WIN32
00106 #include <windows.h>
00107 #include <shellapi.h>
00108 #include "nsIWidget.h"
00109 #endif
00110 
00111 static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
00112 static NS_DEFINE_CID(kNavDTDCID, NS_CNAVDTD_CID);
00113 // </for>
00114 
00115 #ifdef NS_DEBUG
00116 static PRBool _just_to_be_sure_we_create_only_one_compose_service_ = PR_FALSE;
00117 #endif
00118 
00119 #define DEFAULT_CHROME  "chrome://messenger/content/messengercompose/messengercompose.xul"
00120 
00121 #define PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS  "mail.compose.max_recycled_windows"
00122 
00123 #define MAIL_ROOT_PREF                             "mail."
00124 #define MAILNEWS_ROOT_PREF                         "mailnews."
00125 #define HTMLDOMAINUPDATE_VERSION_PREF_NAME         "global_html_domains.version"
00126 #define HTMLDOMAINUPDATE_DOMAINLIST_PREF_NAME      "global_html_domains"
00127 #define USER_CURRENT_HTMLDOMAINLIST_PREF_NAME      "html_domains"
00128 #define USER_CURRENT_PLAINTEXTDOMAINLIST_PREF_NAME "plaintext_domains"
00129 #define DOMAIN_DELIMITER                           ","
00130 
00131 #ifdef MSGCOMP_TRACE_PERFORMANCE
00132 static PRLogModuleInfo *MsgComposeLogModule = nsnull;
00133 
00134 static PRUint32 GetMessageSizeFromURI(const char * originalMsgURI)
00135 {
00136   PRUint32 msgSize = 0;
00137 
00138   if (originalMsgURI && *originalMsgURI)
00139   {
00140     nsCOMPtr <nsIMsgDBHdr> originalMsgHdr;
00141     GetMsgDBHdrFromURI(originalMsgURI, getter_AddRefs(originalMsgHdr));
00142     if (originalMsgHdr)
00143     originalMsgHdr->GetMessageSize(&msgSize);
00144   }
00145   
00146   return msgSize;
00147 }
00148 #endif
00149 
00150 nsMsgComposeService::nsMsgComposeService()
00151 {
00152 #ifdef NS_DEBUG
00153   NS_ASSERTION(!_just_to_be_sure_we_create_only_one_compose_service_, "You cannot create several message compose service!");
00154   _just_to_be_sure_we_create_only_one_compose_service_ = PR_TRUE;
00155 #endif
00156 
00157 // Defaulting the value of mLogComposePerformance to FALSE to prevent logging.
00158   mLogComposePerformance = PR_FALSE;
00159 #ifdef MSGCOMP_TRACE_PERFORMANCE
00160   if (!MsgComposeLogModule)
00161       MsgComposeLogModule = PR_NewLogModule("msgcompose");
00162 
00163   mStartTime = PR_IntervalNow();
00164   mPreviousTime = mStartTime;
00165 #endif
00166 
00167   mMaxRecycledWindows = 0;
00168   mCachedWindows = nsnull;
00169 }
00170 
00171 NS_IMPL_ISUPPORTS4(nsMsgComposeService,
00172                    nsIMsgComposeService,
00173                    nsIObserver,
00174                    ICOMMANDLINEHANDLER,
00175                    nsISupportsWeakReference)
00176 
00177 nsMsgComposeService::~nsMsgComposeService()
00178 {
00179   if (mCachedWindows)
00180   {
00181     DeleteCachedWindows();
00182     delete [] mCachedWindows;
00183   }
00184 
00185   mOpenComposeWindows.Clear();
00186 }
00187 
00188 nsresult nsMsgComposeService::Init()
00189 {
00190   nsresult rv = NS_OK;
00191   // Register observers
00192 
00193   // Register for quit application and profile change, we will need to clear the cache.
00194   nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
00195   if (NS_SUCCEEDED(rv))
00196   {
00197     rv = observerService->AddObserver(this, "quit-application", PR_TRUE);
00198     rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
00199   }
00200 
00201   // Register some pref observer
00202   nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
00203   if (pbi)
00204     rv = pbi->AddObserver(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS, this, PR_TRUE);
00205 
00206   mOpenComposeWindows.Init();
00207   Reset();
00208 
00209   AddGlobalHtmlDomains();
00210   return rv;
00211 }
00212 
00213 void nsMsgComposeService::Reset()
00214 {
00215   nsresult rv = NS_OK;
00216 
00217   if (mCachedWindows)
00218   {
00219     DeleteCachedWindows();
00220     delete [] mCachedWindows;
00221     mCachedWindows = nsnull;
00222     mMaxRecycledWindows = 0;
00223   }
00224 
00225   mOpenComposeWindows.Clear();
00226 
00227   nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
00228   if(prefs)
00229     rv = prefs->GetIntPref(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS, &mMaxRecycledWindows);
00230   if (NS_SUCCEEDED(rv) && mMaxRecycledWindows > 0)
00231   {
00232     mCachedWindows = new nsMsgCachedWindowInfo[mMaxRecycledWindows];
00233     if (!mCachedWindows)
00234       mMaxRecycledWindows = 0;
00235   }
00236   
00237   rv = prefs->GetBoolPref("mailnews.logComposePerformance", &mLogComposePerformance);
00238 
00239   return;
00240 }
00241 
00242 void nsMsgComposeService::DeleteCachedWindows()
00243 {
00244   PRInt32 i;
00245   for (i = 0; i < mMaxRecycledWindows; i ++)
00246   {
00247     CloseWindow(mCachedWindows[i].window);
00248     mCachedWindows[i].Clear();
00249   }
00250 }
00251 
00252 // Utility function to open a message compose window and pass an nsIMsgComposeParams parameter to it.
00253 nsresult nsMsgComposeService::OpenWindow(const char *chrome, nsIMsgComposeParams *params)
00254 {
00255   nsresult rv;
00256   
00257   NS_ENSURE_ARG_POINTER(params);
00258   
00259   //Use default identity if no identity has been specified
00260   nsCOMPtr<nsIMsgIdentity> identity; 
00261   params->GetIdentity(getter_AddRefs(identity));
00262   if (!identity)
00263   {
00264     GetDefaultIdentity(getter_AddRefs(identity));
00265     params->SetIdentity(identity);
00266   }
00267 
00268   //if we have a cached window for the default chrome, try to reuse it...
00269   if (chrome == nsnull || nsCRT::strcasecmp(chrome, DEFAULT_CHROME) == 0)
00270   {
00271     MSG_ComposeFormat format;
00272     params->GetFormat(&format);
00273 
00274     PRBool composeHTML = PR_TRUE;
00275     rv = DetermineComposeHTML(identity, format, &composeHTML);
00276     if (NS_SUCCEEDED(rv))
00277     {
00278       PRInt32 i;
00279       for (i = 0; i < mMaxRecycledWindows; i ++)
00280       {
00281         if (mCachedWindows[i].window && (mCachedWindows[i].htmlCompose == composeHTML) && mCachedWindows[i].listener)
00282         {
00283           /* We need to save the window pointer as OnReopen will call nsMsgComposeService::InitCompose which will
00284              clear the cache entry if everything goes well
00285           */
00286           nsCOMPtr<nsIDOMWindowInternal> domWindow(mCachedWindows[i].window);
00287           rv = ShowCachedComposeWindow(domWindow, PR_TRUE);
00288           if (NS_SUCCEEDED(rv))
00289           {
00290             mCachedWindows[i].listener->OnReopen(params);
00291             return NS_OK;
00292           }
00293         }
00294       }
00295     }
00296   }
00297       
00298   //Else, create a new one...
00299   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00300   if (!wwatch)
00301     return NS_ERROR_FAILURE;
00302 
00303   nsCOMPtr<nsISupportsInterfacePointer> msgParamsWrapper =
00304     do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00305   NS_ENSURE_SUCCESS(rv, rv);
00306 
00307   msgParamsWrapper->SetData(params);
00308   msgParamsWrapper->SetDataIID(&NS_GET_IID(nsIMsgComposeParams));
00309 
00310   nsCOMPtr<nsIDOMWindow> newWindow;
00311   rv = wwatch->OpenWindow(0, chrome && *chrome ? chrome : DEFAULT_CHROME,
00312                  "_blank", "all,chrome,dialog=no,status,toolbar", msgParamsWrapper,
00313                  getter_AddRefs(newWindow));
00314 
00315   return rv;
00316 }
00317 
00318 void nsMsgComposeService::CloseWindow(nsIDOMWindowInternal *domWindow)
00319 {
00320   if (domWindow)
00321   {
00322     nsCOMPtr<nsIDocShell> docshell;
00323     nsCOMPtr<nsIScriptGlobalObject> globalObj(do_QueryInterface(domWindow));
00324     if (globalObj)
00325     {
00326       nsCOMPtr<nsIDocShellTreeItem> treeItem =
00327         do_QueryInterface(globalObj->GetDocShell());
00328 
00329       if (treeItem)
00330       {
00331         nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
00332         treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
00333         if (treeOwner)
00334         {
00335           nsCOMPtr<nsIBaseWindow> baseWindow;
00336           baseWindow = do_QueryInterface(treeOwner);
00337           if (baseWindow)
00338             baseWindow->Destroy();
00339         }
00340       }
00341     }
00342   }
00343 }
00344 
00345 NS_IMETHODIMP
00346 nsMsgComposeService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00347 {
00348   if (!strcmp(aTopic, "profile-do-change") || !strcmp(aTopic, "quit-application"))
00349   {
00350     DeleteCachedWindows();
00351     return NS_OK;
00352   }
00353 
00354   if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
00355   {
00356     nsDependentString prefName(someData);
00357     if (prefName.EqualsLiteral(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS))
00358       Reset();
00359     return NS_OK;
00360   }
00361 
00362   return NS_OK;
00363 }
00364 
00365 NS_IMETHODIMP
00366 nsMsgComposeService::DetermineComposeHTML(nsIMsgIdentity *aIdentity, MSG_ComposeFormat aFormat, PRBool *aComposeHTML)
00367 {
00368   NS_ENSURE_ARG_POINTER(aComposeHTML);
00369 
00370   *aComposeHTML = PR_TRUE;
00371   switch (aFormat)
00372   {
00373     case nsIMsgCompFormat::HTML: 
00374       *aComposeHTML = PR_TRUE;                                 
00375       break;
00376     case nsIMsgCompFormat::PlainText:
00377       *aComposeHTML = PR_FALSE;                                
00378       break;
00379       
00380     default:
00381       nsCOMPtr<nsIMsgIdentity> identity = aIdentity;
00382       if (!identity)
00383         GetDefaultIdentity(getter_AddRefs(identity));
00384       
00385       if (identity)
00386       {
00387         identity->GetComposeHtml(aComposeHTML);
00388         if (aFormat == nsIMsgCompFormat::OppositeOfDefault)
00389           *aComposeHTML = !*aComposeHTML;
00390       }
00391       else
00392       {
00393         // default identity not found.  Use the mail.html_compose pref to determine
00394         // message compose type (HTML or PlainText).
00395         nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
00396         if (prefs)
00397         {
00398           nsresult rv;
00399           PRBool useHTMLCompose;
00400           rv = prefs->GetBoolPref(MAIL_ROOT_PREF "html_compose", &useHTMLCompose);
00401           if (NS_SUCCEEDED(rv))        
00402             *aComposeHTML = useHTMLCompose;
00403         }
00404       }
00405       break;
00406   }
00407 
00408   return NS_OK;
00409 }
00410 
00411 NS_IMETHODIMP
00412 nsMsgComposeService::OpenComposeWindow(const char *msgComposeWindowURL, const char *originalMsgURI,
00413   MSG_ComposeType type, MSG_ComposeFormat format, nsIMsgIdentity * aIdentity, nsIMsgWindow *aMsgWindow)
00414 {
00415   nsresult rv;
00416 
00417   nsCOMPtr<nsIMsgIdentity> identity = aIdentity;
00418   if (!identity)
00419     GetDefaultIdentity(getter_AddRefs(identity));
00420   
00421   /* Actually, the only way to implement forward inline is to simulate a template message. 
00422      Maybe one day when we will have more time we can change that
00423   */
00424   if (type == nsIMsgCompType::ForwardInline || type == nsIMsgCompType::Draft || type == nsIMsgCompType::Template
00425     || type == nsIMsgCompType::ReplyWithTemplate)
00426   {
00427       nsCAutoString uriToOpen(originalMsgURI);
00428       uriToOpen += (uriToOpen.FindChar('?') == kNotFound) ? "?" : "&";
00429       uriToOpen.Append("fetchCompleteMessage=true"); 
00430 
00431       return LoadDraftOrTemplate(uriToOpen, type == nsIMsgCompType::ForwardInline || type == nsIMsgCompType::Draft ? 
00432                                  nsMimeOutput::nsMimeMessageDraftOrTemplate : nsMimeOutput::nsMimeMessageEditorTemplate,  
00433                                  identity, originalMsgURI, type == nsIMsgCompType::ForwardInline, aMsgWindow);
00434   }
00435 
00436   nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
00437   if (NS_SUCCEEDED(rv) && pMsgComposeParams)
00438   {
00439     nsCOMPtr<nsIMsgCompFields> pMsgCompFields (do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv));
00440     if (NS_SUCCEEDED(rv) && pMsgCompFields)
00441     {
00442       pMsgComposeParams->SetType(type);
00443       pMsgComposeParams->SetFormat(format);
00444       pMsgComposeParams->SetIdentity(identity);
00445       
00446       if (originalMsgURI && *originalMsgURI)
00447       {
00448         if (type == nsIMsgCompType::NewsPost) 
00449         {
00450           nsCAutoString newsURI(originalMsgURI);
00451           nsCAutoString group;
00452           nsCAutoString host;
00453           
00454           PRInt32 slashpos = newsURI.RFindChar('/');
00455           if (slashpos > 0 )
00456           {
00457             // uri is "[s]news://host[:port]/group"
00458             newsURI.Left(host, slashpos);
00459             newsURI.Right(group, newsURI.Length() - slashpos - 1);
00460           }
00461           else
00462             group = originalMsgURI;
00463 
00464           nsCAutoString unescapedName;
00465           NS_UnescapeURL(group, 
00466                          esc_FileBaseName|esc_Forced|esc_AlwaysCopy,
00467                          unescapedName);
00468           pMsgCompFields->SetNewsgroups(NS_ConvertUTF8toUTF16(unescapedName));
00469           pMsgCompFields->SetNewshost(host.get());
00470         }
00471         else
00472         {
00473           pMsgComposeParams->SetOriginalMsgURI(originalMsgURI);
00474           if (PL_strstr(originalMsgURI, "type=application/x-message-display"))
00475           {
00476             nsCOMPtr <nsIMsgDBHdr> msgHdr;
00477             if (strncmp(originalMsgURI, "file:", 5))
00478               rv = GetMsgDBHdrFromURI(originalMsgURI, getter_AddRefs(msgHdr));
00479             if (aMsgWindow && !msgHdr)
00480             {
00481               nsCOMPtr <nsIMsgHeaderSink> headerSink;
00482               rv = aMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
00483               if (headerSink)
00484                 rv = headerSink->GetDummyMsgHeader(getter_AddRefs(msgHdr));
00485             }
00486             pMsgComposeParams->SetOrigMsgHdr(msgHdr);
00487           }
00488         }
00489       }
00490 
00491       pMsgComposeParams->SetComposeFields(pMsgCompFields);
00492 
00493       if(mLogComposePerformance)
00494       {
00495 #ifdef MSGCOMP_TRACE_PERFORMANCE
00496         // ducarroz, properly fix this in the case of new message (not a reply)
00497         if (type != nsIMsgCompType::NewsPost) {
00498           char buff[256];
00499           sprintf(buff, "Start opening the window, message size = %d", GetMessageSizeFromURI(originalMsgURI));
00500           TimeStamp(buff, PR_TRUE);
00501         }
00502 #endif
00503       }//end if(mLogComposePerformance)
00504 
00505       rv = OpenWindow(msgComposeWindowURL, pMsgComposeParams);
00506     }
00507   }
00508   return rv;
00509 }
00510 
00511 NS_IMETHODIMP nsMsgComposeService::GetParamsForMailto(nsIURI * aURI, nsIMsgComposeParams ** aParams)
00512 {
00513   nsresult rv = NS_OK;
00514   if (aURI)
00515   { 
00516     nsCOMPtr<nsIMailtoUrl> aMailtoUrl;
00517     rv = aURI->QueryInterface(NS_GET_IID(nsIMailtoUrl), getter_AddRefs(aMailtoUrl));
00518     if (NS_SUCCEEDED(rv))
00519     {
00520        MSG_ComposeFormat requestedComposeFormat = nsIMsgCompFormat::Default;
00521        nsXPIDLCString aToPart;
00522        nsXPIDLCString aCcPart;
00523        nsXPIDLCString aBccPart;
00524        nsXPIDLCString aSubjectPart;
00525        nsXPIDLCString aBodyPart;
00526        nsXPIDLCString aNewsgroup;
00527        nsXPIDLCString aRefPart;
00528        nsXPIDLCString aHTMLBodyPart;
00529 
00530        // we are explictly not allowing attachments to be specified in mailto: urls
00531        // as it's a potential security problem.
00532        // see bug #99055
00533        aMailtoUrl->GetMessageContents(getter_Copies(aToPart), getter_Copies(aCcPart), 
00534                                     getter_Copies(aBccPart), nsnull /* from part */,
00535                                     nsnull /* follow */, nsnull /* organization */, 
00536                                     nsnull /* reply to part */, getter_Copies(aSubjectPart),
00537                                     getter_Copies(aBodyPart), getter_Copies(aHTMLBodyPart) /* html part */, 
00538                                     getter_Copies(aRefPart), nsnull /* attachment part, must always null, see #99055 */,
00539                                     nsnull /* priority */, getter_Copies(aNewsgroup), nsnull /* host */,
00540                                     &requestedComposeFormat);
00541 
00542       nsAutoString sanitizedBody;
00543 
00544       // Since there is a buffer for each of the body types ('body', 'html-body') and
00545       // only one can be used, we give precedence to 'html-body' in the case where
00546       // both 'body' and 'html-body' are found in the url.
00547       NS_ConvertUTF8toUTF16 rawBody(aHTMLBodyPart);
00548       if(rawBody.IsEmpty())
00549         CopyUTF8toUTF16(aBodyPart, rawBody);
00550 
00551       PRBool composeHTMLFormat;
00552       DetermineComposeHTML(NULL, requestedComposeFormat, &composeHTMLFormat);
00553       if (!rawBody.IsEmpty() && composeHTMLFormat)
00554       {
00555         //For security reason, we must sanitize the message body before accepting any html...
00556 
00557         // Create a parser
00558         nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID);
00559 
00560         // Create the appropriate output sink
00561         nsCOMPtr<nsIContentSink> sink = do_CreateInstance(MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID);
00562         
00563         nsXPIDLCString allowedTags;
00564         nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
00565         if (prefs)
00566           prefs->GetCharPref(MAILNEWS_ROOT_PREF "display.html_sanitizer.allowed_tags", getter_Copies(allowedTags));
00567 
00568         if (parser && sink)
00569         {
00570           nsCOMPtr<mozISanitizingHTMLSerializer> sanSink(do_QueryInterface(sink));
00571           if (sanSink)
00572           {
00573             sanSink->Initialize(&sanitizedBody, 0, NS_ConvertASCIItoUTF16(allowedTags));
00574 
00575             parser->SetContentSink(sink);
00576             nsCOMPtr<nsIDTD> dtd = do_CreateInstance(kNavDTDCID);
00577             if (dtd)
00578             {
00579               parser->RegisterDTD(dtd);
00580 
00581               rv = parser->Parse(rawBody, 0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE);
00582               if (NS_FAILED(rv))
00583                 // Something went horribly wrong with parsing for html format
00584                 // in the body.  Set composeHTMLFormat to PR_FALSE so we show the
00585                 // plain text mail compose.
00586                 composeHTMLFormat = PR_FALSE;
00587             }
00588           }
00589         }
00590       }
00591 
00592       nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
00593       if (NS_SUCCEEDED(rv) && pMsgComposeParams)
00594       {
00595         pMsgComposeParams->SetType(nsIMsgCompType::MailToUrl);
00596         pMsgComposeParams->SetFormat(composeHTMLFormat ? nsIMsgCompFormat::HTML : nsIMsgCompFormat::PlainText);
00597 
00598 
00599         nsCOMPtr<nsIMsgCompFields> pMsgCompFields (do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv));
00600         if (pMsgCompFields)
00601         {
00602           //ugghh more conversion work!!!!
00603           pMsgCompFields->SetTo(NS_ConvertUTF8toUTF16(aToPart));
00604           pMsgCompFields->SetCc(NS_ConvertUTF8toUTF16(aCcPart));
00605           pMsgCompFields->SetBcc(NS_ConvertUTF8toUTF16(aBccPart));
00606           pMsgCompFields->SetNewsgroups(NS_ConvertUTF8toUTF16(aNewsgroup));
00607           pMsgCompFields->SetReferences(aRefPart);
00608           pMsgCompFields->SetSubject(NS_ConvertUTF8toUTF16(aSubjectPart));
00609           pMsgCompFields->SetBody(composeHTMLFormat ? sanitizedBody : rawBody);
00610           pMsgComposeParams->SetComposeFields(pMsgCompFields);
00611 
00612           NS_ADDREF(*aParams = pMsgComposeParams);
00613           return NS_OK;
00614         }
00615       } // if we created msg compose params....
00616     } // if we had a mailto url
00617   } // if we had a url...
00618 
00619   // if we got here we must have encountered an error
00620   *aParams = nsnull;
00621   return NS_ERROR_FAILURE;
00622 }
00623 
00624 NS_IMETHODIMP nsMsgComposeService::OpenComposeWindowWithURI(const char * aMsgComposeWindowURL, nsIURI * aURI)
00625 {
00626   nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams;
00627   nsresult rv = GetParamsForMailto(aURI, getter_AddRefs(pMsgComposeParams));
00628   if (NS_SUCCEEDED(rv))
00629     rv = OpenComposeWindowWithParams(aMsgComposeWindowURL, pMsgComposeParams);
00630   return rv;
00631 }
00632 
00633 nsresult nsMsgComposeService::OpenComposeWindowWithParams(const char *msgComposeWindowURL,
00634                               nsIMsgComposeParams *params)
00635 {
00636   NS_ENSURE_ARG_POINTER(params);
00637   if(mLogComposePerformance)
00638   {
00639 #ifdef MSGCOMP_TRACE_PERFORMANCE
00640     TimeStamp("Start opening the window", PR_TRUE);
00641 #endif
00642   }//end - if(mLogComposePerformance)
00643 
00644   return OpenWindow(msgComposeWindowURL, params);
00645 }
00646 
00647 // the following two Windows routines are used to ensure new compose windows
00648 // come to the very front of the desktop, even if the mozilla app is not the application
00649 // with focus. This situation happens when Simple MAPI is used to invoke the compose window.
00650 
00651 #ifdef XP_WIN32 
00652 // begin shameless copying from nsNativeAppSupportWin
00653 HWND hwndForComposeDOMWindow( nsISupports *window ) 
00654 {
00655   nsCOMPtr<nsIScriptGlobalObject> ppScriptGlobalObj( do_QueryInterface(window) );
00656   if ( !ppScriptGlobalObj )
00657       return 0;
00658 
00659   nsCOMPtr<nsIBaseWindow> ppBaseWindow =
00660     do_QueryInterface( ppScriptGlobalObj->GetDocShell() );
00661   if (!ppBaseWindow) return 0;
00662 
00663   nsCOMPtr<nsIWidget> ppWidget;
00664   ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
00665 
00666   return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
00667 }
00668 
00669 static void activateComposeWindow( nsIDOMWindowInternal *win ) 
00670 {
00671   // Try to get native window handle.
00672   HWND hwnd = hwndForComposeDOMWindow( win );
00673   if ( hwnd ) 
00674   {
00675     // Restore the window if it is minimized.
00676     if ( ::IsIconic( hwnd ) ) 
00677       ::ShowWindow( hwnd, SW_RESTORE );
00678     // Use the OS call, if possible.
00679     ::SetForegroundWindow( hwnd );
00680   } else // Use internal method.  
00681     win->Focus();
00682 }
00683 // end shameless copying from nsNativeAppWinSupport.cpp
00684 #endif
00685 
00686 NS_IMETHODIMP nsMsgComposeService::InitCompose(nsIDOMWindowInternal *aWindow,
00687                                           nsIMsgComposeParams *params,
00688                                           nsIMsgCompose **_retval)
00689 {
00690   nsresult rv;
00691   
00692   /* we need to remove the window from the cache
00693   */
00694   PRInt32 i;
00695   for (i = 0; i < mMaxRecycledWindows; i ++)
00696     if (mCachedWindows[i].window == aWindow)
00697     {
00698       mCachedWindows[i].Clear();
00699       break;
00700     }
00701 
00702   nsCOMPtr <nsIMsgCompose> msgCompose = do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv);
00703   NS_ENSURE_SUCCESS(rv,rv);
00704        
00705   rv = msgCompose->Initialize(aWindow, params);
00706   NS_ENSURE_SUCCESS(rv,rv);
00707 
00708 #ifdef XP_WIN32
00709   // on windows, ensure the compose window comes up to the front
00710   activateComposeWindow(aWindow);
00711 #endif
00712 
00713   NS_IF_ADDREF(*_retval = msgCompose);
00714   return rv;
00715 }
00716 
00717 NS_IMETHODIMP
00718 nsMsgComposeService::GetDefaultIdentity(nsIMsgIdentity **_retval)
00719 {
00720   NS_ENSURE_ARG_POINTER(_retval);
00721   *_retval = nsnull;
00722 
00723   nsresult rv;
00724   nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00725   if (NS_SUCCEEDED(rv) && accountManager)
00726   {
00727     nsCOMPtr<nsIMsgAccount> defaultAccount;
00728     rv = accountManager->GetDefaultAccount(getter_AddRefs(defaultAccount));
00729     if (NS_SUCCEEDED(rv) && defaultAccount)
00730       defaultAccount->GetDefaultIdentity(_retval);
00731   }
00732   return rv;
00733 }
00734 
00735 /* readonly attribute boolean logComposePerformance; */
00736 NS_IMETHODIMP nsMsgComposeService::GetLogComposePerformance(PRBool *aLogComposePerformance)
00737 {
00738   *aLogComposePerformance = mLogComposePerformance;
00739   return NS_OK;
00740 }
00741 
00742 NS_IMETHODIMP nsMsgComposeService::TimeStamp(const char * label, PRBool resetTime)
00743 {
00744   if (!mLogComposePerformance)
00745     return NS_OK;
00746   
00747 #ifdef MSGCOMP_TRACE_PERFORMANCE
00748 
00749   PRIntervalTime now;
00750 
00751   if (resetTime)
00752   {      
00753     PR_LOG(MsgComposeLogModule, PR_LOG_ALWAYS, ("\n[process]: [totalTime][deltaTime]\n--------------------\n"));
00754 
00755     mStartTime = PR_IntervalNow();
00756     mPreviousTime = mStartTime;
00757     now = mStartTime;
00758   }
00759   else
00760     now = PR_IntervalNow();
00761 
00762   PRIntervalTime totalTime = PR_IntervalToMilliseconds(now - mStartTime);
00763   PRIntervalTime deltaTime = PR_IntervalToMilliseconds(now - mPreviousTime);
00764 
00765 #if defined(DEBUG_ducarroz)
00766   printf("XXX Time Stamp: [%5d][%5d] - %s\n", totalTime, deltaTime, label);
00767 #endif
00768   PR_LOG(MsgComposeLogModule, PR_LOG_ALWAYS, ("[%3.2f][%3.2f] - %s\n",
00769 ((double)totalTime/1000.0) + 0.005, ((double)deltaTime/1000.0) + 0.005, label));
00770 
00771   mPreviousTime = now;
00772 #endif
00773   return NS_OK;
00774 }
00775 
00776 NS_IMETHODIMP
00777 nsMsgComposeService::IsCachedWindow(nsIDOMWindowInternal *aCachedWindow, PRBool *aIsCachedWindow)
00778 {
00779   NS_ENSURE_ARG_POINTER(aCachedWindow);
00780   NS_ENSURE_ARG_POINTER(aIsCachedWindow);
00781 
00782   PRInt32 i;
00783   for (i = 0; i < mMaxRecycledWindows; i ++)
00784     if (mCachedWindows[i].window.get() == aCachedWindow)
00785     {
00786       *aIsCachedWindow = PR_TRUE;
00787       return NS_OK;
00788     }
00789     
00790  *aIsCachedWindow = PR_FALSE;
00791   return NS_OK;
00792 }
00793 
00794 NS_IMETHODIMP
00795 nsMsgComposeService::CacheWindow(nsIDOMWindowInternal *aWindow, PRBool aComposeHTML, nsIMsgComposeRecyclingListener * aListener)
00796 {
00797   NS_ENSURE_ARG_POINTER(aWindow);
00798   NS_ENSURE_ARG_POINTER(aListener);
00799 
00800   nsresult rv;
00801 
00802   PRInt32 i;
00803   PRInt32 sameTypeId = -1;
00804   PRInt32 oppositeTypeId = -1;
00805   
00806   for (i = 0; i < mMaxRecycledWindows; i ++)
00807   {
00808     if (!mCachedWindows[i].window)
00809     {
00810       rv = ShowCachedComposeWindow(aWindow, PR_FALSE);
00811       if (NS_SUCCEEDED(rv))
00812         mCachedWindows[i].Initialize(aWindow, aListener, aComposeHTML);
00813       
00814       return rv;
00815     }
00816     else
00817       if (mCachedWindows[i].htmlCompose == aComposeHTML)
00818       {
00819         if (sameTypeId == -1)
00820           sameTypeId = i;
00821       }
00822       else
00823       {
00824         if (oppositeTypeId == -1)
00825           oppositeTypeId = i;
00826       }
00827   }
00828   
00829   /* Looks like the cache is full. In the case we try to cache a type (html or plain text) of compose window which is not
00830      already cached, we should replace an opposite one with this new one. That would allow users to be able to take advantage
00831      of the cached compose window when they switch from one type to another one
00832   */
00833   if (sameTypeId == -1 && oppositeTypeId != -1)
00834   {
00835     CloseWindow(mCachedWindows[oppositeTypeId].window);
00836     mCachedWindows[oppositeTypeId].Clear();
00837     
00838     rv = ShowCachedComposeWindow(aWindow, PR_FALSE);
00839     if (NS_SUCCEEDED(rv))
00840       mCachedWindows[oppositeTypeId].Initialize(aWindow, aListener, aComposeHTML);
00841     
00842     return rv;
00843   }
00844   
00845   return NS_ERROR_NOT_AVAILABLE;
00846 }
00847 
00848 class nsMsgTemplateReplyHelper :  public nsIStreamListener, public nsIUrlListener
00849 {
00850 public:
00851   NS_DECL_ISUPPORTS
00852   NS_DECL_NSIURLLISTENER
00853   NS_DECL_NSISTREAMLISTENER
00854   NS_DECL_NSIREQUESTOBSERVER
00855 
00856   nsMsgTemplateReplyHelper();
00857   ~nsMsgTemplateReplyHelper();
00858 
00859   nsCOMPtr <nsIMsgDBHdr> mHdrToReplyTo;
00860   nsCOMPtr <nsIMsgDBHdr> mTemplateHdr;
00861   nsCOMPtr <nsIMsgWindow> mMsgWindow;
00862   nsCOMPtr <nsIMsgIncomingServer> mServer;
00863   nsCString mTemplateBody; 
00864   PRBool mInMsgBody;
00865   char mLastBlockChars[3];
00866 };
00867 
00868 NS_IMPL_ISUPPORTS2(nsMsgTemplateReplyHelper, nsIStreamListener, nsIUrlListener)
00869 
00870 nsMsgTemplateReplyHelper::nsMsgTemplateReplyHelper()
00871 {
00872   mInMsgBody = PR_FALSE;
00873   memset(mLastBlockChars, 0, sizeof(mLastBlockChars));
00874 }
00875 
00876 nsMsgTemplateReplyHelper::~nsMsgTemplateReplyHelper()
00877 {
00878 }
00879 
00880 
00881 NS_IMETHODIMP nsMsgTemplateReplyHelper::OnStartRunningUrl(nsIURI *aUrl)
00882 {
00883   return NS_OK;
00884 }
00885 
00886 NS_IMETHODIMP nsMsgTemplateReplyHelper::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
00887 {
00888 
00889   NS_ENSURE_SUCCESS(aExitCode, aExitCode);
00890   nsresult rv;
00891   nsCOMPtr<nsIDOMWindowInternal> parentWindow;
00892   if (mMsgWindow)
00893   {
00894     nsCOMPtr<nsIDocShell> docShell;
00895     rv = mMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
00896     NS_ENSURE_SUCCESS(rv, rv);
00897     parentWindow = do_GetInterface(docShell);
00898     NS_ENSURE_TRUE(parentWindow, NS_ERROR_FAILURE);
00899   }
00900   if ( NS_FAILED(rv) ) return rv ;
00901   // get the MsgIdentity for the above key using AccountManager
00902   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ;
00903   if (NS_FAILED(rv) || (!accountManager) ) return rv ;
00904 
00905   nsCOMPtr <nsIMsgAccount> account;
00906   nsCOMPtr <nsIMsgIdentity> identity;
00907 
00908   rv = accountManager->FindAccountForServer(mServer, getter_AddRefs(account));
00909   NS_ENSURE_SUCCESS(rv, rv);
00910   account->GetDefaultIdentity(getter_AddRefs(identity));
00911   NS_ENSURE_SUCCESS(rv, rv);
00912 
00913   // create the compose params object 
00914   nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
00915   if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
00916   nsCOMPtr<nsIMsgCompFields> compFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ;
00917 
00918   nsXPIDLCString replyTo;
00919   mHdrToReplyTo->GetStringProperty("replyTo", getter_Copies(replyTo));
00920   if (replyTo.IsEmpty())
00921     mHdrToReplyTo->GetAuthor(getter_Copies(replyTo));
00922   compFields->SetTo(NS_ConvertUTF8toUTF16(replyTo));
00923 
00924   nsAutoString body;
00925   nsXPIDLString templateSubject, replySubject;
00926 
00927   mTemplateHdr->GetMime2DecodedSubject(getter_Copies(templateSubject));
00928   mHdrToReplyTo->GetMime2DecodedSubject(getter_Copies(replySubject));
00929   if (!replySubject.IsEmpty())
00930   {
00931     templateSubject.Append(NS_LITERAL_STRING(" (was: "));
00932     templateSubject.Append(replySubject);
00933     templateSubject.Append(NS_LITERAL_STRING(")"));
00934   }
00935   compFields->SetSubject(templateSubject);
00936   body.AssignWithConversion(mTemplateBody);
00937   compFields->SetBody(body);
00938   nsXPIDLCString msgUri;
00939 
00940   nsCOMPtr <nsIMsgFolder> folder;
00941   mHdrToReplyTo->GetFolder(getter_AddRefs(folder));
00942   folder->GetUriForMsg(mHdrToReplyTo, getter_Copies(msgUri));
00943   // populate the compose params
00944    // we use type new instead of reply - we might need to add a reply with template type.
00945   pMsgComposeParams->SetType(nsIMsgCompType::New);
00946   pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
00947   pMsgComposeParams->SetIdentity(identity);
00948   pMsgComposeParams->SetComposeFields(compFields); 
00949   pMsgComposeParams->SetOriginalMsgURI(msgUri);
00950   // create the nsIMsgCompose object to send the object
00951   nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
00952   if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ;
00953 
00956   rv = pMsgCompose->Initialize(parentWindow, pMsgComposeParams) ;
00957   if (NS_FAILED(rv)) return rv ;
00958 
00959   Release();
00960 
00961   return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nsnull, nsnull, nsnull) ;
00962 }
00963 
00964 NS_IMETHODIMP
00965 nsMsgTemplateReplyHelper::OnStartRequest(nsIRequest* request, nsISupports* aSupport)
00966 {
00967   return NS_OK;
00968 }
00969 
00970 NS_IMETHODIMP
00971 nsMsgTemplateReplyHelper::OnStopRequest(nsIRequest* request, nsISupports* aSupport,
00972                                 nsresult status)
00973 {
00974   if (NS_SUCCEEDED(status))
00975   {
00976     // now we've got the message body in mTemplateBody - 
00977     // need to set body in compose params and send the reply.
00978   }
00979   return NS_OK;
00980 }
00981 
00982 NS_IMETHODIMP
00983 nsMsgTemplateReplyHelper::OnDataAvailable(nsIRequest* request, 
00984                                   nsISupports* aSupport,
00985                                   nsIInputStream* inStream, 
00986                                   PRUint32 srcOffset,
00987                                   PRUint32 count)
00988 {
00989   nsresult rv = NS_OK;
00990 
00991   char readBuf[1024];
00992 
00993   PRUint32 available, readCount;
00994   PRUint32 maxReadCount = sizeof(readBuf) - 1;
00995 
00996   rv = inStream->Available(&available);
00997   while (NS_SUCCEEDED(rv) && available > 0)
00998   {
00999     PRInt32 bodyOffset = 0, readOffset = 0;
01000     if (!mInMsgBody && mLastBlockChars[0])
01001     {
01002       memcpy(readBuf, mLastBlockChars, 3);
01003       readOffset = 3;
01004       maxReadCount -= 3;
01005     }
01006     if (maxReadCount > available)
01007       maxReadCount = available;
01008     memset(readBuf, 0, sizeof(readBuf));
01009     rv = inStream->Read(readBuf + readOffset, maxReadCount, &readCount);
01010     available -= readCount;
01011     readCount += readOffset;
01012     // we're mainly interested in the msg body, so we need to
01013     // find the header/body delimiter of a blank line. A blank line
01014     // looks like <CR><CR>, <LF><LF>, or <CRLF><CRLF>
01015     if (!mInMsgBody)
01016     {
01017       for (PRInt32 charIndex = 0; charIndex < readCount && !bodyOffset; charIndex++)
01018       {
01019         if (readBuf[charIndex] == '\r' || readBuf[charIndex] == '\n')
01020         {
01021           if (charIndex + 1 < readCount)
01022           {
01023             if (readBuf[charIndex] == readBuf[charIndex + 1])
01024             {
01025             // got header+body separator
01026               bodyOffset = charIndex + 2;
01027               break;
01028             }
01029             else if ((charIndex + 3 < readCount) && !strncmp(readBuf + charIndex, "\r\n\r\n", 4))
01030             {
01031               bodyOffset = charIndex + 4;
01032               break;
01033             }
01034           }
01035         }
01036       }
01037       mInMsgBody = bodyOffset != 0;
01038       if (!mInMsgBody && readCount > 3) // still in msg hdrs
01039         strncpy(mLastBlockChars, readBuf + readCount - 3, 3);
01040 
01041     }
01042     mTemplateBody.Append(readBuf + bodyOffset);
01043   }
01044   return NS_OK;
01045 }
01046 
01047 
01048 NS_IMETHODIMP nsMsgComposeService::ReplyWithTemplate(nsIMsgDBHdr *aMsgHdr, const char *templateUri,
01049                                              nsIMsgWindow *aMsgWindow, nsIMsgIncomingServer *aServer)
01050 {
01051   // to reply with template, we need the message body of the template 
01052   // I think we're going to need to stream the template message to ourselves, 
01053   // and construct the body, and call setBody on the compFields.
01054   // We need the reply-to header of the msg we're replying to, so
01055   // we're going to add that to the db if it's different from "from:"
01056   // For imap, we could make adding a reply-to filter append
01057   // reply-to to the custom headers...
01058 
01059     nsMsgTemplateReplyHelper *helper = new nsMsgTemplateReplyHelper;
01060     if (!helper)
01061       return NS_ERROR_OUT_OF_MEMORY;
01062 
01063     NS_ADDREF(helper);
01064 
01065     helper->mHdrToReplyTo = aMsgHdr;
01066     helper->mMsgWindow = aMsgWindow;
01067     helper->mServer = aServer;
01068 
01069     nsCOMPtr <nsIMsgFolder> templateFolder;
01070     nsCOMPtr <nsIMsgDatabase> templateDB;
01071     nsXPIDLCString templateMsgHdrUri;
01072     const char * query = PL_strstr(templateUri, "?messageId=");
01073     if (!query)
01074       return NS_ERROR_FAILURE;
01075 
01076     nsCAutoString folderUri(Substring(templateUri, query)); 
01077     nsresult rv = GetExistingFolder(folderUri.get(), getter_AddRefs(templateFolder));
01078     NS_ENSURE_SUCCESS(rv, rv);
01079     rv = templateFolder->GetMsgDatabase(aMsgWindow, getter_AddRefs(templateDB));
01080     NS_ENSURE_SUCCESS(rv, rv);
01081 
01082     const char *subject = PL_strstr(templateUri, "&subject=");
01083     if (subject)
01084     {
01085       const char *subjectEnd = subject + strlen(subject);
01086       nsCAutoString messageId(Substring(query + 11, subject));
01087       nsCAutoString subjectString(Substring(subject + 9, subjectEnd));
01088       templateDB->GetMsgHdrForMessageID(messageId.get(), getter_AddRefs(helper->mTemplateHdr));
01089       if (helper->mTemplateHdr)
01090         templateFolder->GetUriForMsg(helper->mTemplateHdr, getter_Copies(templateMsgHdrUri));
01091       // to use the subject, we'd need to expose a method to find a message by subject,
01092       // or painfully iterate through messages...We'll try to make the message-id
01093       // not change when saving a template first.
01094     }
01095     if (templateMsgHdrUri.IsEmpty())
01096     {
01097       // ### probably want to return a specific error and 
01098       // have the calling code disable the filter.
01099       NS_ASSERTION(PR_FALSE, "failed to get msg hdr");
01100       return NS_ERROR_FAILURE;
01101     }
01102     // we need to convert the template uri, which is of the form
01103     // <folder uri>?messageId=<messageId>&subject=<subject>
01104     nsCOMPtr <nsIMsgMessageService> msgService;
01105     rv = GetMessageServiceFromURI(templateMsgHdrUri, getter_AddRefs(msgService));
01106     NS_ENSURE_SUCCESS(rv, rv);
01107 
01108     nsCOMPtr<nsISupports> listenerSupports;
01109     helper->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(listenerSupports));
01110 
01111     return msgService->StreamMessage(templateMsgHdrUri, listenerSupports, aMsgWindow,
01112                                           helper, PR_FALSE /* convert data */, 
01113                                                 "", nsnull);
01114 }
01115 
01116 
01117 NS_IMETHODIMP nsMsgComposeService::ForwardMessage(const nsAString &forwardTo, nsIMsgDBHdr *aMsgHdr, 
01118                                              nsIMsgWindow *aMsgWindow, nsIMsgIncomingServer *aServer)
01119 {
01120 
01121     nsresult rv;
01122     nsCOMPtr<nsIDOMWindowInternal> parentWindow;
01123     if (aMsgWindow)
01124     {
01125       nsCOMPtr<nsIDocShell> docShell;
01126       rv = aMsgWindow->GetRootDocShell(getter_AddRefs(docShell));
01127       NS_ENSURE_SUCCESS(rv, rv);
01128       parentWindow = do_GetInterface(docShell);
01129       NS_ENSURE_TRUE(parentWindow, NS_ERROR_FAILURE);
01130     }
01131     if ( NS_FAILED(rv) ) return rv ;
01132     // get the MsgIdentity for the above key using AccountManager
01133     nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ;
01134     if (NS_FAILED(rv) || (!accountManager) ) return rv ;
01135 
01136     nsCOMPtr <nsIMsgAccount> account;
01137     nsCOMPtr <nsIMsgIdentity> identity;
01138 
01139     rv = accountManager->FindAccountForServer(aServer, getter_AddRefs(account));
01140     NS_ENSURE_SUCCESS(rv, rv);
01141     account->GetDefaultIdentity(getter_AddRefs(identity));
01142     NS_ENSURE_SUCCESS(rv, rv);
01143 
01144     // create the compose params object 
01145     nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
01146     if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
01147     nsCOMPtr<nsIMsgCompFields> compFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ;
01148 
01149     compFields->SetTo(forwardTo);
01150     nsXPIDLCString msgUri;
01151     PRInt32 forwardType = 0; 
01152 
01153     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
01154     if (prefBranch)
01155       prefBranch->GetIntPref("mail.forward_message_mode", &forwardType);
01156 
01157     nsCOMPtr <nsIMsgFolder> folder;
01158     aMsgHdr->GetFolder(getter_AddRefs(folder));
01159     folder->GetUriForMsg(aMsgHdr, getter_Copies(msgUri));
01160     // populate the compose params
01161     // right now, forward inline won't work, since that requires opening a compose window,
01162     // and would require major whackage of the compose code.
01163     pMsgComposeParams->SetType(/* forwardType ? nsIMsgCompType::ForwardInline : */nsIMsgCompType::ForwardAsAttachment);
01164     pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
01165     pMsgComposeParams->SetIdentity(identity);
01166     pMsgComposeParams->SetComposeFields(compFields); 
01167     pMsgComposeParams->SetOriginalMsgURI(msgUri);
01168     // create the nsIMsgCompose object to send the object
01169     nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
01170     if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ;
01171 
01174     rv = pMsgCompose->Initialize(parentWindow, pMsgComposeParams) ;
01175     if (NS_FAILED(rv)) return rv ;
01176 
01177     return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nsnull, nsnull, nsnull) ;
01178 }
01179 
01180 
01181 nsresult nsMsgComposeService::ShowCachedComposeWindow(nsIDOMWindowInternal *aComposeWindow, PRBool aShow)
01182 {
01183   nsresult rv = NS_OK;
01184 
01185   nsCOMPtr <nsIScriptGlobalObject> globalScript = do_QueryInterface(aComposeWindow, &rv);
01186 
01187   NS_ENSURE_SUCCESS(rv,rv);
01188 
01189   nsIDocShell *docShell = globalScript->GetDocShell();
01190 
01191   nsCOMPtr <nsIDocShellTreeItem> treeItem = do_QueryInterface(docShell, &rv);
01192   NS_ENSURE_SUCCESS(rv,rv);
01193 
01194   nsCOMPtr <nsIDocShellTreeOwner> treeOwner;
01195   rv = treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
01196   NS_ENSURE_SUCCESS(rv,rv);
01197   
01198   if (treeOwner) {
01199 
01200     // the window need to be sticky before we hide it.
01201     nsCOMPtr<nsIContentViewer> contentViewer;
01202     rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
01203     NS_ENSURE_SUCCESS(rv,rv);
01204     
01205     rv = contentViewer->SetSticky(!aShow);
01206     NS_ENSURE_SUCCESS(rv,rv);
01207 
01208     // disable (enable) the cached window
01209     nsCOMPtr<nsIBaseWindow> baseWindow;
01210     baseWindow = do_QueryInterface(treeOwner, &rv);
01211     NS_ENSURE_SUCCESS(rv,rv);
01212 
01213     baseWindow->SetEnabled(aShow);
01214     NS_ENSURE_SUCCESS(rv,rv);
01215 
01216     nsCOMPtr <nsIXULWindow> xulWindow = do_GetInterface(treeOwner, &rv);
01217     NS_ENSURE_SUCCESS(rv,rv);
01218 
01219     nsCOMPtr<nsIWindowMediator> windowMediator = 
01220                 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv);
01221     NS_ENSURE_SUCCESS(rv,rv);
01222 
01223     // if showing, reinstate the window with the mediator
01224     if (aShow) {
01225       rv = windowMediator->RegisterWindow(xulWindow);
01226       NS_ENSURE_SUCCESS(rv,rv);
01227     }
01228 
01229     // hide (show) the cached window
01230     rv = baseWindow->SetVisibility(aShow);
01231     NS_ENSURE_SUCCESS(rv,rv);
01232 
01233     // if hiding, remove the window from the mediator,
01234     // so that it will be removed from the task list
01235     if (!aShow) {
01236       rv = windowMediator->UnregisterWindow(xulWindow);
01237       NS_ENSURE_SUCCESS(rv,rv);
01238     }
01239   }
01240   else {
01241     rv = NS_ERROR_FAILURE;
01242   }
01243   return rv;
01244 }
01245 
01246 nsresult nsMsgComposeService::AddGlobalHtmlDomains()
01247 {
01248 
01249   nsresult rv;
01250   nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01251   NS_ENSURE_SUCCESS(rv,rv);
01252 
01253   nsCOMPtr<nsIPrefBranch> prefBranch;
01254   rv = prefs->GetBranch(MAILNEWS_ROOT_PREF, getter_AddRefs(prefBranch));
01255   NS_ENSURE_SUCCESS(rv,rv);
01256 
01257   nsCOMPtr<nsIPrefBranch> defaultsPrefBranch;
01258   rv = prefs->GetDefaultBranch(MAILNEWS_ROOT_PREF, getter_AddRefs(defaultsPrefBranch));
01259   NS_ENSURE_SUCCESS(rv,rv);
01260 
01275   PRInt32 htmlDomainListCurrentVersion, htmlDomainListDefaultVersion;
01276   rv = prefBranch->GetIntPref(HTMLDOMAINUPDATE_VERSION_PREF_NAME, &htmlDomainListCurrentVersion);
01277   NS_ENSURE_SUCCESS(rv,rv);
01278 
01279   rv = defaultsPrefBranch->GetIntPref(HTMLDOMAINUPDATE_VERSION_PREF_NAME, &htmlDomainListDefaultVersion);
01280   NS_ENSURE_SUCCESS(rv,rv);
01281   
01282   // Update the list as needed
01283   if (htmlDomainListCurrentVersion <= htmlDomainListDefaultVersion) {
01284     // Get list of global domains need to be added
01285     nsXPIDLCString globalHtmlDomainList;
01286     rv = prefBranch->GetCharPref(HTMLDOMAINUPDATE_DOMAINLIST_PREF_NAME, getter_Copies(globalHtmlDomainList));
01287 
01288     if (NS_SUCCEEDED(rv) && !globalHtmlDomainList.IsEmpty()) {
01289 
01290       // Get user's current HTML domain set for send format
01291       nsXPIDLCString currentHtmlDomainList;
01292       rv = prefBranch->GetCharPref(USER_CURRENT_HTMLDOMAINLIST_PREF_NAME, getter_Copies(currentHtmlDomainList));
01293       NS_ENSURE_SUCCESS(rv,rv);
01294 
01295       nsCAutoString newHtmlDomainList(currentHtmlDomainList);
01296       // Get the current html domain list into new list var
01297       nsCStringArray htmlDomainArray;
01298       if (!currentHtmlDomainList.IsEmpty()) 
01299         htmlDomainArray.ParseString(currentHtmlDomainList.get(), DOMAIN_DELIMITER);
01300 
01301       // Get user's current Plaintext domain set for send format
01302       nsXPIDLCString currentPlaintextDomainList;
01303       rv = prefBranch->GetCharPref(USER_CURRENT_PLAINTEXTDOMAINLIST_PREF_NAME, getter_Copies(currentPlaintextDomainList));
01304       NS_ENSURE_SUCCESS(rv,rv);
01305 
01306       // Get the current plaintext domain list into new list var
01307       nsCStringArray plaintextDomainArray;
01308       if (!currentPlaintextDomainList.IsEmpty()) 
01309         plaintextDomainArray.ParseString(currentPlaintextDomainList.get(), DOMAIN_DELIMITER);
01310     
01311       if (htmlDomainArray.Count() || plaintextDomainArray.Count()) {
01312         // Tokenize the data and add each html domain if it is not alredy there in 
01313         // the user's current html or plaintext domain lists
01314         char *newData;
01315         char *globalData = ToNewCString(globalHtmlDomainList);
01316   
01317         char *token = nsCRT::strtok(globalData, DOMAIN_DELIMITER, &newData);
01318 
01319         nsCAutoString htmlDomain;
01320         while (token) {
01321           if (token && *token) {
01322             htmlDomain.Assign(token);
01323             htmlDomain.StripWhitespace();
01324 
01325             if (htmlDomainArray.IndexOf(htmlDomain) == -1  && 
01326                 plaintextDomainArray.IndexOf(htmlDomain) == -1) {
01327               if (!newHtmlDomainList.IsEmpty())
01328                 newHtmlDomainList += DOMAIN_DELIMITER;
01329               newHtmlDomainList += htmlDomain;
01330             }
01331           }
01332           token = nsCRT::strtok(newData, DOMAIN_DELIMITER, &newData);
01333         }
01334         PR_FREEIF(globalData);
01335       }
01336       else
01337       {
01338         // User has no domains listed either in html or plain text category.
01339         // Assign the global list to be the user's current html domain list
01340         newHtmlDomainList = globalHtmlDomainList;
01341       }
01342 
01343       // Set user's html domain pref with the updated list
01344       rv = prefBranch->SetCharPref(USER_CURRENT_HTMLDOMAINLIST_PREF_NAME, newHtmlDomainList.get());
01345       NS_ENSURE_SUCCESS(rv,rv);
01346 
01347       // Increase the version to avoid running the update code unless needed (based on default version)
01348       rv = prefBranch->SetIntPref(HTMLDOMAINUPDATE_VERSION_PREF_NAME, htmlDomainListCurrentVersion + 1);
01349       NS_ENSURE_SUCCESS(rv,rv);
01350     }
01351   }
01352   return NS_OK;
01353 }
01354 
01355 NS_IMETHODIMP
01356 nsMsgComposeService::RegisterComposeWindow(nsIDOMWindowInternal * aWindow, nsIMsgCompose *aComposeObject)
01357 {
01358   NS_ENSURE_ARG_POINTER(aWindow);
01359   NS_ENSURE_ARG_POINTER(aComposeObject);
01360 
01361   nsresult rv;
01362 
01363   // add the msg compose / dom window mapping to our hash table
01364   nsCOMPtr<nsIWeakReference> weakDOMWindow = do_GetWeakReference(aWindow, &rv);
01365   NS_ENSURE_SUCCESS(rv,rv);
01366   nsCOMPtr<nsIWeakReference> weakMsgComposePtr = do_GetWeakReference(aComposeObject);
01367   NS_ENSURE_SUCCESS(rv,rv);
01368   mOpenComposeWindows.Put(weakDOMWindow, weakMsgComposePtr);
01369   
01370   return rv;
01371 }
01372 
01373 NS_IMETHODIMP
01374 nsMsgComposeService::UnregisterComposeWindow(nsIDOMWindowInternal * aWindow)
01375 {
01376   NS_ENSURE_ARG_POINTER(aWindow);
01377   
01378   nsresult rv;
01379   nsCOMPtr<nsIWeakReference> weakDOMWindow = do_GetWeakReference(aWindow, &rv);
01380   NS_ENSURE_SUCCESS(rv,rv);
01381 
01382   mOpenComposeWindows.Remove(weakDOMWindow);
01383 
01384   return rv;
01385 }
01386 
01387 NS_IMETHODIMP
01388 nsMsgComposeService::GetMsgComposeForWindow(nsIDOMWindowInternal * aWindow, nsIMsgCompose ** aComposeObject)
01389 {
01390   NS_ENSURE_ARG_POINTER(aWindow);
01391   NS_ENSURE_ARG_POINTER(aComposeObject);
01392 
01393   // get the weak reference for our dom window
01394   nsresult rv;
01395   nsCOMPtr<nsIWeakReference> weakDOMWindow = do_GetWeakReference(aWindow, &rv);
01396   NS_ENSURE_SUCCESS(rv,rv);
01397 
01398   nsCOMPtr<nsIWeakReference> weakMsgComposePtr;
01399 
01400   NS_ENSURE_TRUE(mOpenComposeWindows.Get(weakDOMWindow, getter_AddRefs(weakMsgComposePtr)), NS_ERROR_FAILURE);
01401 
01402   nsCOMPtr<nsIMsgCompose> msgCompose = do_QueryReferent(weakMsgComposePtr, &rv);
01403   NS_ENSURE_SUCCESS(rv, rv);
01404   
01405   NS_IF_ADDREF(*aComposeObject = msgCompose);
01406   return rv;
01407 }
01408 
01414 nsresult    
01415 nsMsgComposeService::LoadDraftOrTemplate(const nsACString& aMsgURI, nsMimeOutputType aOutType, 
01416                                          nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI, 
01417                                          PRBool aAddInlineHeaders, nsIMsgWindow *aMsgWindow)
01418 {
01419   nsresult rv;
01420   nsCOMPtr <nsIMsgMessageService> messageService;
01421   rv = GetMessageServiceFromURI(nsPromiseFlatCString(aMsgURI).get(), getter_AddRefs(messageService));
01422   NS_ENSURE_SUCCESS(rv, rv);
01423 
01424   // Now, we can create a mime parser (nsIStreamConverter)!
01425   nsCOMPtr<nsIMimeStreamConverter> mimeConverter = 
01426     do_CreateInstance(NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID, &rv);
01427   NS_ENSURE_SUCCESS(rv, rv);
01428   
01429   mimeConverter->SetMimeOutputType(aOutType);  // Set the type of output for libmime
01430   mimeConverter->SetForwardInline(aAddInlineHeaders);
01431   mimeConverter->SetIdentity(aIdentity);
01432   mimeConverter->SetOriginalMsgURI(aOriginalMsgURI);
01433 
01434   nsCOMPtr<nsIURI> url;
01435   PRBool fileUrl = StringBeginsWith(aMsgURI, NS_LITERAL_CSTRING("file:"));
01436   nsACString::const_iterator start, end;
01437   aMsgURI.BeginReading(start);
01438   aMsgURI.EndReading(end);
01439   if (fileUrl || FindInReadable(NS_LITERAL_CSTRING("&type=application/x-message-display"), start, end))
01440     rv = NS_NewURI(getter_AddRefs(url), aMsgURI);
01441   else
01442     rv = messageService->GetUrlForUri(nsPromiseFlatCString(aMsgURI).get(), getter_AddRefs(url), aMsgWindow);
01443   NS_ENSURE_SUCCESS(rv, rv);
01444 
01445   rv = url->SetSpec(aMsgURI);
01446   NS_ENSURE_SUCCESS(rv, rv);
01447 
01448   // if we are forwarding a message and that message used a charset over ride
01449   // then use that over ride charset instead of the charset specified in the message
01450   nsXPIDLCString mailCharset;
01451   if (aMsgWindow)
01452   {
01453     PRBool charsetOverride;
01454     if (NS_SUCCEEDED(aMsgWindow->GetCharsetOverride(&charsetOverride)) && charsetOverride)
01455     {
01456       if (NS_SUCCEEDED(aMsgWindow->GetMailCharacterSet(getter_Copies(mailCharset))))
01457       {
01458         nsCOMPtr<nsIMsgI18NUrl> i18nUrl(do_QueryInterface(url));
01459         if (i18nUrl)
01460           (void) i18nUrl->SetCharsetOverRide(mailCharset.get());
01461       }
01462     }
01463   }
01464 
01465   nsCOMPtr<nsIChannel> channel;
01466   rv = NS_NewInputStreamChannel(getter_AddRefs(channel), url, nsnull);
01467   NS_ENSURE_SUCCESS(rv, rv);
01468   
01469   nsCOMPtr<nsIStreamConverter> converter = do_QueryInterface(mimeConverter);
01470   rv = converter->AsyncConvertData(nsnull, nsnull, nsnull, channel);
01471   NS_ENSURE_SUCCESS(rv, rv);
01472 
01473   // Now, just plug the two together and get the hell out of the way!
01474   nsCOMPtr<nsIStreamListener> streamListener = do_QueryInterface(mimeConverter); 
01475   return messageService->DisplayMessage(nsPromiseFlatCString(aMsgURI).get(), streamListener, aMsgWindow, nsnull, mailCharset, nsnull);;
01476 }
01477 
01478 #ifdef MOZ_XUL_APP
01479 NS_IMETHODIMP
01480 nsMsgComposeService::Handle(nsICommandLine* aCmdLine)
01481 {
01482   nsresult rv;
01483   PRInt32 found, end, count;
01484   nsAutoString uristr;
01485   PRBool composeShouldHandle = PR_TRUE;
01486 
01487   rv = aCmdLine->FindFlag(NS_LITERAL_STRING("compose"), PR_FALSE, &found);
01488   NS_ENSURE_SUCCESS(rv, rv);
01489 
01490   // MAC OS X passes in -url mailto:mscott@mozilla.org into the command line
01491   // instead of -compose.
01492   if (found == -1)
01493   {
01494     rv = aCmdLine->FindFlag(NS_LITERAL_STRING("url"), PR_FALSE, &found);
01495     // we don't want to consume the argument for -url unless we're sure it is a mailto url and we'll
01496     // figure that out shortly.
01497     composeShouldHandle = PR_FALSE;
01498   }
01499 
01500   if (found == -1)
01501     return NS_OK;
01502 
01503   end = found;
01504 
01505   rv = aCmdLine->GetLength(&count);
01506   NS_ENSURE_SUCCESS(rv, rv);
01507 
01508   if (count > found + 1) {
01509     aCmdLine->GetArgument(found + 1, uristr);
01510     if (StringBeginsWith(uristr, NS_LITERAL_STRING("mailto:"))  ||
01511         StringBeginsWith(uristr, NS_LITERAL_STRING("to="))  ||
01512         StringBeginsWith(uristr, NS_LITERAL_STRING("cc="))  ||
01513         StringBeginsWith(uristr, NS_LITERAL_STRING("subject=")) ||
01514         StringBeginsWith(uristr, NS_LITERAL_STRING("body="))  ||
01515         StringBeginsWith(uristr, NS_LITERAL_STRING("attachment="))) {
01516       composeShouldHandle = PR_TRUE; // the -url argument looks like mailto
01517       end++;
01518       // mailto: URIs are frequently passed with spaces in them. They should be
01519       // escaped with %20, but we hack around broken clients. See bug 231032.
01520       while (end + 1 < count) {
01521         nsAutoString curarg;
01522         aCmdLine->GetArgument(end + 1, curarg);
01523         if (curarg.First() == '-')
01524           break;
01525 
01526         uristr.Append(' ');
01527         uristr.Append(curarg);
01528         ++end;
01529       }
01530     }
01531     else {
01532       uristr.Truncate();
01533     }
01534   }
01535   if (composeShouldHandle)
01536   {
01537     aCmdLine->RemoveArguments(found, end);
01538 
01539     nsCOMPtr<nsIWindowWatcher> wwatch (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
01540     NS_ENSURE_TRUE(wwatch, NS_ERROR_FAILURE);
01541 
01542     nsCOMPtr<nsISupportsString> arg;
01543     if (!uristr.IsEmpty()) {
01544       arg = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
01545       if (arg)
01546         arg->SetData(uristr);
01547     }    
01548 
01549     nsCOMPtr<nsIDOMWindow> opened;
01550     wwatch->OpenWindow(nsnull, DEFAULT_CHROME, "_blank",
01551                        "chrome,dialog=no,all", arg, getter_AddRefs(opened));
01552 
01553     aCmdLine->SetPreventDefault(PR_TRUE);
01554   }
01555   return NS_OK;
01556 }
01557 
01558 NS_IMETHODIMP
01559 nsMsgComposeService::GetHelpInfo(nsACString& aResult)
01560 {
01561   aResult.Assign(NS_LITERAL_CSTRING("  -compose             Compose a mail or news message.\n"));
01562   return NS_OK;
01563 }
01564 
01565 #else
01566 CMDLINEHANDLER_IMPL(nsMsgComposeService, "-compose", "general.startup.messengercompose", DEFAULT_CHROME,
01567                     "Start with messenger compose.", NS_MSGCOMPOSESTARTUPHANDLER_CONTRACTID, "Messenger Compose Startup Handler",
01568                     PR_TRUE, "about:blank", PR_TRUE)
01569 #endif