Back to index

lightning-sunbird  0.9+nobinonly
msgMapiHook.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2001
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *                 Krishna Mohan Khandrika (kkhandrika@netscape.com)
00023  *                 Srilatha Moturi (srilatha@netscape.com)
00024  *                 Rajiv Dayal (rdayal@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #define MAPI_STARTUP_ARG       "/MAPIStartUp"
00041 
00042 #ifdef MOZ_LOGGING
00043 // this has to be before the pre-compiled header
00044 #define FORCE_PR_LOG /* Allow logging in the release build */
00045 #endif
00046 #include <mapidefs.h>
00047 #include <mapi.h>
00048 #include <tchar.h>
00049 #include <direct.h>
00050 #include "nsCOMPtr.h"
00051 #include "nsIComponentManager.h"
00052 #include "nsIServiceManager.h"
00053 #include "nsISupports.h"
00054 #include "nsIPromptService.h"
00055 #include "nsIAppStartup.h" 
00056 #include "nsIAppShellService.h"
00057 #include "nsIDOMWindowInternal.h"
00058 #include "nsINativeAppSupport.h"
00059 #include "nsIMsgAccountManager.h"
00060 #include "nsIDOMWindowInternal.h"
00061 #include "nsXPIDLString.h"
00062 #include "nsReadableUtils.h"
00063 #include "nsMsgBaseCID.h"
00064 #include "nsIStringBundle.h"
00065 #include "nsIPrefService.h"
00066 #include "nsIPrefBranch.h"
00067 #include "nsString.h"
00068 #include "nsUnicharUtils.h"
00069 #include "nsIMsgAttachment.h"
00070 #include "nsIMsgCompFields.h"
00071 #include "nsIMsgComposeParams.h"
00072 #include "nsIMsgCompose.h"
00073 #include "nsMsgCompCID.h"
00074 #include "nsXPFEComponentsCID.h" 
00075 #include "nsIMsgSend.h"
00076 #include "nsIProxyObjectManager.h"
00077 #include "nsIMsgComposeService.h"
00078 #include "nsProxiedService.h"
00079 #include "nsDirectoryServiceDefs.h"
00080 #include "nsIDirectoryService.h"
00081 #include "nsMsgI18N.h"
00082 #include "msgMapi.h"
00083 #include "msgMapiHook.h"
00084 #include "msgMapiSupport.h"
00085 #include "msgMapiMain.h"
00086 #include "nsNetUtil.h"
00087 
00088 #include "nsEmbedCID.h"
00089 
00090 #ifndef MOZ_XUL_APP
00091 #include "nsICmdLineService.h"
00092 #endif
00093 
00094 extern PRLogModuleInfo *MAPI;
00095 
00096 class nsMAPISendListener : public nsIMsgSendListener
00097 {
00098 public:
00099 
00100     virtual ~nsMAPISendListener() { }
00101 
00102     // nsISupports interface
00103     NS_DECL_ISUPPORTS
00104 
00105     /* void OnStartSending (in string aMsgID, in PRUint32 aMsgSize); */
00106     NS_IMETHOD OnStartSending(const char *aMsgID, PRUint32 aMsgSize) { return NS_OK; }
00107 
00108     /* void OnProgress (in string aMsgID, in PRUint32 aProgress, in PRUint32 aProgressMax); */
00109     NS_IMETHOD OnProgress(const char *aMsgID, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK;}
00110 
00111     /* void OnStatus (in string aMsgID, in wstring aMsg); */
00112     NS_IMETHOD OnStatus(const char *aMsgID, const PRUnichar *aMsg) { return NS_OK;}
00113 
00114     /* void OnStopSending (in string aMsgID, in nsresult aStatus, in wstring aMsg, in nsIFileSpec returnFileSpec); */
00115     NS_IMETHOD OnStopSending(const char *aMsgID, nsresult aStatus, const PRUnichar *aMsg, 
00116                            nsIFileSpec *returnFileSpec) {
00117         PR_CEnterMonitor(this);
00118         PR_CNotifyAll(this);
00119         m_done = PR_TRUE;
00120         PR_CExitMonitor(this);
00121         return NS_OK ;
00122     }
00123 
00124        /* void OnSendNotPerformed */
00125        NS_IMETHOD OnSendNotPerformed(const char *aMsgID, nsresult aStatus)
00126        {
00127               return OnStopSending(aMsgID, aStatus, nsnull, nsnull) ;
00128        }
00129  
00130     /* void OnGetDraftFolderURI (); */
00131     NS_IMETHOD OnGetDraftFolderURI(const char *aFolderURI) {return NS_OK;}
00132 
00133     static nsresult CreateMAPISendListener( nsIMsgSendListener **ppListener);
00134 
00135     PRBool IsDone() { return m_done ; }
00136 
00137 protected :
00138     nsMAPISendListener() {
00139         m_done = PR_FALSE;
00140     }
00141 
00142     PRBool          m_done;
00143 };
00144 
00145 
00146 NS_IMPL_THREADSAFE_ISUPPORTS1(nsMAPISendListener, nsIMsgSendListener)
00147 
00148 nsresult nsMAPISendListener::CreateMAPISendListener( nsIMsgSendListener **ppListener)
00149 {
00150     NS_ENSURE_ARG_POINTER(ppListener) ;
00151 
00152     *ppListener = new nsMAPISendListener();
00153     if (! *ppListener)
00154         return NS_ERROR_OUT_OF_MEMORY;
00155 
00156     NS_ADDREF(*ppListener);
00157     return NS_OK;
00158 }
00159 
00160 PRBool nsMapiHook::isMapiService = PR_FALSE;
00161 
00162 PRBool nsMapiHook::Initialize()
00163 {
00164 #ifndef MOZ_THUNDERBIRD 
00165     nsresult rv;
00166     nsCOMPtr<nsINativeAppSupport> native;
00167     nsCOMPtr<nsICmdLineService> cmdLineArgs (do_GetService(NS_COMMANDLINESERVICE_CONTRACTID, &rv));
00168     if (NS_FAILED(rv)) return PR_FALSE; 
00169 
00170     nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID, &rv));
00171     if (NS_FAILED(rv)) return PR_FALSE; 
00172 
00173     rv = appStartup->GetNativeAppSupport(getter_AddRefs(native)); 
00174     if (NS_FAILED(rv)) return PR_FALSE;
00175 
00176     rv = native->EnsureProfile(cmdLineArgs);
00177     if (NS_FAILED(rv)) return PR_FALSE;
00178 #endif
00179     return PR_TRUE;
00180 }
00181 
00182 void nsMapiHook::CleanUp()
00183 {
00184     // This routine will be fully implemented in future
00185     // to cleanup mapi related stuff inside mozilla code.
00186 }
00187 
00188 PRBool nsMapiHook::DisplayLoginDialog(PRBool aLogin, PRUnichar **aUsername, 
00189                       PRUnichar **aPassword)
00190 {
00191     nsresult rv;
00192     PRBool btnResult = PR_FALSE;
00193    
00194     nsCOMPtr<nsIPromptService> dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv));
00195     if (NS_SUCCEEDED(rv) && dlgService)
00196     {
00197         nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
00198         if (NS_FAILED(rv) || !bundleService) return PR_FALSE;
00199 
00200         nsCOMPtr<nsIStringBundle> bundle;
00201         rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle));
00202         if (NS_FAILED(rv) || !bundle) return PR_FALSE;
00203 
00204         nsCOMPtr<nsIStringBundle> brandBundle;
00205         rv = bundleService->CreateBundle(
00206                         "chrome://branding/locale/brand.properties",
00207                         getter_AddRefs(brandBundle));
00208         if (NS_FAILED(rv)) return PR_FALSE;
00209 
00210         nsXPIDLString brandName;
00211         rv = brandBundle->GetStringFromName(
00212                            NS_LITERAL_STRING("brandFullName").get(),
00213                            getter_Copies(brandName));
00214         if (NS_FAILED(rv)) return PR_FALSE;
00215         
00216         nsXPIDLString loginTitle;
00217         const PRUnichar *brandStrings[] = { brandName.get() };
00218         NS_NAMED_LITERAL_STRING(loginTitlePropertyTag, "loginTitle");
00219         const PRUnichar *dTitlePropertyTag = loginTitlePropertyTag.get();
00220         rv = bundle->FormatStringFromName(dTitlePropertyTag, brandStrings, 1,
00221                                           getter_Copies(loginTitle));
00222         if (NS_FAILED(rv)) return PR_FALSE;
00223         
00224         if (aLogin)
00225         {
00226             nsXPIDLString loginText;
00227             rv = bundle->GetStringFromName(NS_LITERAL_STRING("loginTextwithName").get(),
00228                                            getter_Copies(loginText));
00229             if (NS_FAILED(rv) || !loginText) return PR_FALSE;
00230 
00231             rv = dlgService->PromptUsernameAndPassword(nsnull, loginTitle,
00232                                                        loginText, aUsername, aPassword,
00233                                                        nsnull, PR_FALSE, &btnResult);
00234         }
00235         else
00236         {
00237             //nsString loginString; 
00238             nsXPIDLString loginText;
00239             const PRUnichar *userNameStrings[] = { *aUsername };
00240 
00241             NS_NAMED_LITERAL_STRING(loginTextPropertyTag, "loginText");
00242             const PRUnichar *dpropertyTag = loginTextPropertyTag.get();
00243             rv = bundle->FormatStringFromName(dpropertyTag, userNameStrings, 1,
00244                                               getter_Copies(loginText));
00245             if (NS_FAILED(rv)) return PR_FALSE;
00246 
00247             rv = dlgService->PromptPassword(nsnull, loginTitle, loginText,
00248                                             aPassword, nsnull, PR_FALSE, &btnResult);
00249         }
00250     }            
00251 
00252     return btnResult;
00253 }
00254 
00255 PRBool nsMapiHook::VerifyUserName(const PRUnichar *aUsername, char **aIdKey)
00256 {
00257     nsresult rv;
00258 
00259     if (aUsername == nsnull)
00260         return PR_FALSE;
00261 
00262     nsCOMPtr<nsIMsgAccountManager> accountManager(do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv));
00263     if (NS_FAILED(rv)) return PR_FALSE;
00264     nsCOMPtr<nsISupportsArray> identities;
00265     rv = accountManager->GetAllIdentities(getter_AddRefs(identities));
00266     if (NS_FAILED(rv)) return PR_FALSE;
00267     PRUint32 numIndentities;
00268     identities->Count(&numIndentities);
00269 
00270     for (PRUint32 i = 0; i < numIndentities; i++)
00271     {
00272         // convert supports->Identity
00273         nsCOMPtr<nsISupports> thisSupports;
00274         rv = identities->GetElementAt(i, getter_AddRefs(thisSupports));
00275         if (NS_FAILED(rv)) continue;
00276         nsCOMPtr<nsIMsgIdentity> thisIdentity(do_QueryInterface(thisSupports, &rv));
00277         if (NS_SUCCEEDED(rv) && thisIdentity)
00278         {
00279             nsXPIDLCString email;
00280             rv = thisIdentity->GetEmail(getter_Copies(email));
00281             if (NS_FAILED(rv)) continue;
00282 
00283             // get the username from the email and compare with the username
00284             nsCAutoString aEmail(email.get());
00285             PRInt32 index = aEmail.FindChar('@');
00286             if (index != -1)
00287                 aEmail.Truncate(index);
00288 
00289                      if (nsDependentString(aUsername) == NS_ConvertASCIItoUCS2(aEmail))  // == overloaded
00290                 return NS_SUCCEEDED(thisIdentity->GetKey(aIdKey));
00291         }
00292     }
00293 
00294     return PR_FALSE;
00295 }
00296 
00297 PRBool 
00298 nsMapiHook::IsBlindSendAllowed()
00299 {
00300     PRBool enabled = PR_FALSE;
00301     PRBool warn = PR_TRUE;
00302     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
00303     if (prefBranch) {
00304         prefBranch->GetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND, &warn);
00305         prefBranch->GetBoolPref(PREF_MAPI_BLIND_SEND_ENABLED, &enabled);
00306     } 
00307     if (!enabled)
00308         return PR_FALSE;
00309 
00310     if (!warn)
00311         return PR_TRUE; // Everything is okay.  
00312 
00313     nsresult rv;
00314     nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
00315     if (NS_FAILED(rv) || !bundleService) return PR_FALSE;
00316 
00317     nsCOMPtr<nsIStringBundle> bundle;
00318     rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle));
00319     if (NS_FAILED(rv) || !bundle) return PR_FALSE;
00320 
00321     nsXPIDLString warningMsg;
00322     rv = bundle->GetStringFromName(NS_LITERAL_STRING("mapiBlindSendWarning").get(),
00323                                         getter_Copies(warningMsg));
00324     if (NS_FAILED(rv)) return PR_FALSE;
00325     
00326        nsXPIDLString dontShowAgainMessage;
00327     rv = bundle->GetStringFromName(NS_LITERAL_STRING("mapiBlindSendDontShowAgain").get(),
00328                                         getter_Copies(dontShowAgainMessage));
00329     if (NS_FAILED(rv)) return PR_FALSE;
00330 
00331     nsCOMPtr<nsIPromptService> dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv));
00332     if (NS_FAILED(rv) || !dlgService) return PR_FALSE;
00333     
00334     PRBool continueToWarn = PR_TRUE;
00335     PRBool okayToContinue = PR_FALSE;
00336     dlgService->ConfirmCheck(nsnull, nsnull, warningMsg, dontShowAgainMessage, &continueToWarn, &okayToContinue);
00337         
00338     if (!continueToWarn && okayToContinue && prefBranch)
00339         prefBranch->SetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND, PR_FALSE);
00340     
00341     return okayToContinue;
00342 }
00343 
00344 // this is used for Send without UI
00345 nsresult nsMapiHook::BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) 
00346 {
00347     nsresult rv = NS_OK ;
00348 
00349     if (!IsBlindSendAllowed())
00350         return NS_ERROR_FAILURE;
00351 
00354     nsCOMPtr<nsIDOMWindowInternal>  hiddenWindow;
00355     // get parent window
00356     nsCOMPtr<nsIAppShellService> appService = do_GetService( "@mozilla.org/appshell/appShellService;1", &rv);
00357     if (NS_FAILED(rv)|| (!appService) ) return rv ;
00358 
00359     rv = appService->GetHiddenDOMWindow(getter_AddRefs(hiddenWindow));
00360     if ( NS_FAILED(rv) ) return rv ;
00361     // smtp password and Logged in used IdKey from MapiConfig (session obj)
00362     nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ;
00363     if (!pMapiConfig) return NS_ERROR_FAILURE ;  // get the singelton obj
00364     PRUnichar * password = pMapiConfig->GetPassword(aSession) ;
00365     // password
00366     nsCAutoString smtpPassword ;
00367     smtpPassword.AssignWithConversion (password) ;
00368     // Id key
00369     char * MsgIdKey = pMapiConfig->GetIdKey(aSession) ;
00370 
00371     // get the MsgIdentity for the above key using AccountManager
00372     nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ;
00373     if (NS_FAILED(rv) || (!accountManager) ) return rv ;
00374 
00375     nsCOMPtr <nsIMsgIdentity> pMsgId ;
00376     rv = accountManager->GetIdentity (MsgIdKey, getter_AddRefs(pMsgId)) ;
00377     if (NS_FAILED(rv) ) return rv ;
00378 
00379     // create a send listener to get back the send status
00380     nsCOMPtr <nsIMsgSendListener> sendListener ;
00381     rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; 
00382     if (NS_FAILED(rv) || (!sendListener) ) return rv;
00383 
00384     // create the compose params object 
00385     nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
00386     if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
00387 
00388     // populate the compose params
00389     PRBool forcePlainText;
00390     aCompFields->GetForcePlainText(&forcePlainText);
00391     pMsgComposeParams->SetType(nsIMsgCompType::New);
00392     pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML);
00393     pMsgComposeParams->SetIdentity(pMsgId);
00394     pMsgComposeParams->SetComposeFields(aCompFields); 
00395     pMsgComposeParams->SetSendListener(sendListener) ;
00396     pMsgComposeParams->SetSmtpPassword(smtpPassword.get());
00397 
00398     // create the nsIMsgCompose object to send the object
00399     nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
00400     if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ;
00401 
00404     rv = pMsgCompose->Initialize(hiddenWindow, pMsgComposeParams) ;
00405     if (NS_FAILED(rv)) return rv ;
00406 
00407     return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, pMsgId, nsnull, nsnull, nsnull) ;
00408     if (NS_FAILED(rv)) return rv ;
00409 
00410     // assign to interface pointer from nsCOMPtr to facilitate typecast below
00411     nsIMsgSendListener * pSendListener = sendListener ;  
00412 
00413     // we need to wait here to make sure that we return only after send is completed
00414     // so we will have a event loop here which will process the events till the Send IsDone.
00415     nsCOMPtr<nsIEventQueueService> pEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00416     nsCOMPtr<nsIEventQueue> eventQueue;
00417     pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,getter_AddRefs(eventQueue));
00418     while ( !((nsMAPISendListener *) pSendListener)->IsDone() )
00419     {
00420         PR_CEnterMonitor(pSendListener);
00421         PR_CWait(pSendListener, PR_MicrosecondsToInterval(1000UL));
00422         PR_CExitMonitor(pSendListener);
00423         eventQueue->ProcessPendingEvents();
00424     }
00425 
00426     return rv ;
00427 }
00428 
00429 // this is used to populate comp fields with Unicode data
00430 nsresult nsMapiHook::PopulateCompFields(lpnsMapiMessage aMessage, 
00431                                     nsIMsgCompFields * aCompFields)
00432 {
00433     nsresult rv = NS_OK ;
00434 
00435     if (aMessage->lpOriginator)
00436     {
00437         char * From = aMessage->lpOriginator->lpszAddress ;
00438         nsAutoString FromStr; FromStr.AssignWithConversion(From);
00439         aCompFields->SetFrom (FromStr) ;
00440     }
00441 
00442     nsAutoString To ;
00443     nsAutoString Cc ; 
00444     nsAutoString Bcc ;
00445 
00446     NS_NAMED_LITERAL_STRING(Comma, ",") ;
00447 
00448     if (aMessage->lpRecips)
00449     {
00450         for (int i=0 ; i < (int) aMessage->nRecipCount ; i++)
00451         {
00452             if (aMessage->lpRecips[i].lpszAddress || aMessage->lpRecips[i].lpszName)
00453             {
00454                 const char *addressWithoutType = (aMessage->lpRecips[i].lpszAddress)
00455                   ? aMessage->lpRecips[i].lpszAddress : aMessage->lpRecips[i].lpszName;
00456                 if (!PL_strncasecmp(addressWithoutType, "SMTP:", 5))
00457                   addressWithoutType += 5;
00458                 switch (aMessage->lpRecips[i].ulRecipClass)
00459                 {
00460                 case MAPI_TO :
00461                     if (!To.IsEmpty())
00462                         To += Comma ;
00463                     To.AppendWithConversion(addressWithoutType) ;
00464                     break ;
00465 
00466                 case MAPI_CC :
00467                     if (!Cc.IsEmpty())
00468                         Cc += Comma ;
00469                     Cc.AppendWithConversion(addressWithoutType) ;
00470                     break ;
00471 
00472                 case MAPI_BCC :
00473                     if (!Bcc.IsEmpty())
00474                         Bcc += Comma ;
00475                     Bcc.AppendWithConversion(addressWithoutType) ; 
00476                     break ;
00477                 }
00478             }
00479         }
00480     }
00481 
00482     PR_LOG(MAPI, PR_LOG_DEBUG, ("to: %s cc: %s bcc: %s \n", NS_ConvertUCS2toUTF8(To).get(), NS_ConvertUCS2toUTF8(Cc).get(), NS_ConvertUCS2toUTF8(Bcc).get()));
00483     // set To, Cc, Bcc
00484     aCompFields->SetTo (To) ;
00485     aCompFields->SetCc (Cc) ;
00486     aCompFields->SetBcc (Bcc) ;
00487 
00488     // set subject
00489     if (aMessage->lpszSubject)
00490     {
00491         nsAutoString Subject;
00492 
00493         Subject.AssignWithConversion(aMessage->lpszSubject);
00494         aCompFields->SetSubject(Subject) ;
00495     }
00496 
00497     // handle attachments as File URL
00498     rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, PR_TRUE) ;
00499     if (NS_FAILED(rv)) return rv ;    
00500 
00501     // set body
00502     if (aMessage->lpszNoteText)
00503     {
00504         nsString Body;
00505         Body.AssignWithConversion(aMessage->lpszNoteText);
00506         if (Body.Last() != nsCRT::LF)
00507           Body.AppendLiteral(CRLF); 
00508 
00509         if (Body.Find("<html>") == kNotFound)
00510           aCompFields->SetForcePlainText(PR_TRUE);
00511 
00512         rv = aCompFields->SetBody(Body) ;
00513     }
00514 
00515 #ifdef RAJIV_DEBUG
00516     // testing what all was set in CompFields
00517     printf ("To : %S \n", To.get()) ;
00518     printf ("CC : %S \n", Cc.get() ) ;
00519     printf ("BCC : %S \n", Bcc.get() ) ;
00520 #endif
00521 
00522     return rv ;
00523 
00524 }
00525 
00526 nsresult nsMapiHook::HandleAttachments (nsIMsgCompFields * aCompFields, PRInt32 aFileCount, 
00527                                         lpnsMapiFileDesc aFiles, BOOL aIsUnicode)
00528 {
00529     nsresult rv = NS_OK ;
00530 
00531     nsCAutoString Attachments ;
00532     nsCAutoString TempFiles ;
00533 
00534     nsCOMPtr <nsILocalFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
00535     if (NS_FAILED(rv) || (!pFile) ) return rv ;        
00536     nsCOMPtr <nsILocalFile> pTempDir = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
00537     if (NS_FAILED(rv) || (!pTempDir) ) return rv ;        
00538 
00539     for (int i=0 ; i < aFileCount ; i++)
00540     {
00541         PRBool bTempFile = PR_FALSE ;
00542         if (aFiles[i].lpszPathName)
00543         {
00544             // check if attachment exists
00545             if (aIsUnicode)
00546                 pFile->InitWithPath (nsDependentString(aFiles[i].lpszPathName)); 
00547             else
00548                 pFile->InitWithNativePath (nsDependentCString((const char*)aFiles[i].lpszPathName)); 
00549 
00550             PRBool bExist ;
00551             rv = pFile->Exists(&bExist) ;
00552             PR_LOG(MAPI, PR_LOG_DEBUG, ("nsMapiHook::HandleAttachments: filename: %s path: %s exists = %s \n", (const char*)aFiles[i].lpszFileName, (const char*)aFiles[i].lpszPathName, bExist ? "true" : "false"));
00553             if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
00554 
00555             //Temp Directory
00556             nsCOMPtr <nsIFile> pTempFileDir;
00557             NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pTempFileDir));
00558             nsCOMPtr <nsILocalFile> pTempDir = do_QueryInterface(pTempFileDir);
00559 
00560             // create a new sub directory called moz_mapi underneath the temp directory
00561             pTempDir->AppendRelativePath(NS_LITERAL_STRING("moz_mapi"));
00562             pTempDir->Exists (&bExist) ;
00563             if (!bExist)
00564             {
00565                 rv = pTempDir->Create(nsIFile::DIRECTORY_TYPE, 777) ;
00566                 if (NS_FAILED(rv)) return rv ;
00567             }
00568 
00569             // rename or copy the existing temp file with the real file name
00570             
00571             nsAutoString leafName ;
00572             // convert to Unicode using Platform charset
00573             // leafName already contains a unicode leafName from lpszPathName. If we were given
00574             // a value for lpszFileName, use it. Otherwise stick with leafName
00575             if (aFiles[i].lpszFileName)
00576             {
00577               nsAutoString wholeFileName;
00578                 if (aIsUnicode)
00579                     wholeFileName.Assign(aFiles[i].lpszFileName);
00580                 else
00581                     ConvertToUnicode(nsMsgI18NFileSystemCharset(), (char *) aFiles[i].lpszFileName, wholeFileName);
00582                 // need to find the last '\' and find the leafname from that.
00583                 PRInt32 lastSlash = wholeFileName.RFindChar(PRUnichar('\\'));
00584                 if (lastSlash != kNotFound)
00585                   wholeFileName.Right(leafName, wholeFileName.Length() - lastSlash - 1);
00586                 else
00587                   leafName.Assign(wholeFileName);
00588             }
00589             else 
00590               pFile->GetLeafName (leafName);
00591 
00592              nsCOMPtr <nsIFile> pTempFile;
00593              rv = pTempDir->Clone(getter_AddRefs(pTempFile));
00594              if (NS_FAILED(rv) || (!pTempFile) ) 
00595                return rv;
00596  
00597              pTempFile->Append(leafName);
00598              pTempFile->Exists(&bExist);
00599              if (bExist)
00600              {
00601                rv = pTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777);
00602                NS_ENSURE_SUCCESS(rv, rv);
00603                pTempFile->Remove(PR_FALSE); // remove so we can copy over it.
00604              }
00605             // copy the file to its new location and file name
00606             pFile->CopyTo(pTempDir, leafName);
00607             // point pFile to the new location of the attachment
00608             pFile->InitWithFile(pTempDir); 
00609             pFile->Append(leafName);
00610 
00611             // create MsgCompose attachment object
00612             nsCOMPtr<nsIMsgAttachment> attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv);
00613             NS_ENSURE_SUCCESS(rv, rv);
00614             attachment->SetTemporary(PR_TRUE); // this one is a temp file so set the flag for MsgCompose
00615 
00616             // now set the attachment object
00617             nsCAutoString pURL ;
00618             NS_GetURLSpecFromFile(pFile, pURL);
00619             attachment->SetUrl(pURL.get()) ;
00620 
00621             // add the attachment
00622             rv = aCompFields->AddAttachment (attachment);
00623             if (NS_FAILED(rv))
00624               PR_LOG(MAPI, PR_LOG_DEBUG, ("nsMapiHook::HandleAttachments: AddAttachment rv =  %lx\n", rv));
00625         }
00626     }
00627     return rv ;
00628 }
00629 
00630 
00631 // this is used to convert non Unicode data and then populate comp fields
00632 nsresult nsMapiHook::PopulateCompFieldsWithConversion(lpnsMapiMessage aMessage, 
00633                                     nsIMsgCompFields * aCompFields)
00634 {
00635     nsresult rv = NS_OK ;
00636 
00637     if (aMessage->lpOriginator)
00638     {
00639         nsAutoString From ;
00640         From.AssignWithConversion((char *) aMessage->lpOriginator->lpszAddress);
00641         aCompFields->SetFrom (From) ;
00642     }
00643 
00644     nsAutoString To ;
00645     nsAutoString Cc ; 
00646     nsAutoString Bcc ;
00647 
00648     NS_NAMED_LITERAL_STRING(Comma, ",") ;
00649 
00650     if (aMessage->lpRecips)
00651     {
00652         for (int i=0 ; i < (int) aMessage->nRecipCount ; i++)
00653         {
00654             if (aMessage->lpRecips[i].lpszAddress || aMessage->lpRecips[i].lpszName)
00655             {
00656                 const char *addressWithoutType = (aMessage->lpRecips[i].lpszAddress)
00657                   ? aMessage->lpRecips[i].lpszAddress : aMessage->lpRecips[i].lpszName;
00658                 if (!PL_strncasecmp(addressWithoutType, "SMTP:", 5))
00659                   addressWithoutType += 5;
00660 
00661                 switch (aMessage->lpRecips[i].ulRecipClass)
00662                 {
00663                 case MAPI_TO :
00664                     if (!To.IsEmpty())
00665                         To += Comma ;
00666                     To.AppendWithConversion (addressWithoutType);
00667                     break ;
00668 
00669                 case MAPI_CC :
00670                     if (!Cc.IsEmpty())
00671                         Cc += Comma ;
00672                     Cc.AppendWithConversion (addressWithoutType);
00673                     break ;
00674 
00675                 case MAPI_BCC :
00676                     if (!Bcc.IsEmpty())
00677                         Bcc += Comma ;
00678                     Bcc.AppendWithConversion (addressWithoutType) ; 
00679                     break ;
00680                 }
00681             }
00682         }
00683     }
00684     
00685     // set To, Cc, Bcc
00686     aCompFields->SetTo (To) ;
00687     aCompFields->SetCc (Cc) ;
00688     aCompFields->SetBcc (Bcc) ;
00689 
00690     PR_LOG(MAPI, PR_LOG_DEBUG, ("to: %s cc: %s bcc: %s \n", NS_ConvertUCS2toUTF8(To).get(), NS_ConvertUCS2toUTF8(Cc).get(), NS_ConvertUCS2toUTF8(Bcc).get()));
00691 
00692     nsCAutoString platformCharSet;
00693     // set subject
00694     if (aMessage->lpszSubject)
00695     {
00696         nsAutoString Subject ;
00697         if (platformCharSet.IsEmpty())
00698             platformCharSet.Assign(nsMsgI18NFileSystemCharset());
00699         rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszSubject, Subject);
00700         if (NS_FAILED(rv)) return rv ;         
00701         aCompFields->SetSubject(Subject) ;
00702     }
00703 
00704     // handle attachments as File URL
00705     rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, PR_FALSE) ;
00706     if (NS_FAILED(rv)) return rv ;    
00707 
00708     // set body
00709     if (aMessage->lpszNoteText)
00710     {
00711         nsAutoString Body ;
00712         if (platformCharSet.IsEmpty())
00713             platformCharSet.Assign(nsMsgI18NFileSystemCharset());
00714         rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszNoteText, Body);
00715         if (NS_FAILED(rv)) return rv ;
00716         if (Body.Last() != nsCRT::LF)
00717           Body.AppendLiteral(CRLF); 
00718 
00719         if (Body.Find("<html>") == kNotFound)
00720           aCompFields->SetForcePlainText(PR_TRUE);
00721 
00722         rv = aCompFields->SetBody(Body) ;
00723     }
00724 
00725 #ifdef RAJIV_DEBUG
00726     // testing what all was set in CompFields
00727     printf ("To : %S \n", To.get()) ;
00728     printf ("CC : %S \n", Cc.get() ) ;
00729     printf ("BCC : %S \n", Bcc.get() ) ;
00730 #endif
00731 
00732     return rv ;
00733 }
00734 
00735 // this is used to populate the docs as attachments in the Comp fields for Send Documents
00736 nsresult nsMapiHook::PopulateCompFieldsForSendDocs(nsIMsgCompFields * aCompFields, ULONG aFlags, 
00737                             PRUnichar * aDelimChar, PRUnichar * aFilePaths)
00738 {
00739     nsAutoString strDelimChars ;
00740     nsString strFilePaths;
00741     nsresult rv = NS_OK ;
00742     PRBool bExist ;
00743 
00744     if (aFlags & MAPI_UNICODE)
00745     {
00746         if (aDelimChar)
00747             strDelimChars.Assign (aDelimChar) ;
00748         if (aFilePaths)
00749             strFilePaths.Assign (aFilePaths) ;
00750     }
00751     else
00752     {
00753         if (aDelimChar)
00754             strDelimChars.AssignWithConversion ((char*) aDelimChar) ;
00755         if (aFilePaths)
00756             strFilePaths.AssignWithConversion ((char *) aFilePaths) ;
00757     }
00758 
00759     // check for comma in filename 
00760     if (strDelimChars.Find (",") == kNotFound)  // if comma is not in the delimiter specified by user
00761     {
00762         if (strFilePaths.Find(",") != kNotFound) // if comma found in filenames return error
00763             return NS_ERROR_FILE_INVALID_PATH ;
00764     }
00765 
00766     nsCString Attachments ;
00767 
00768     // only 1 file is to be sent, no delim specified
00769     if (strDelimChars.IsEmpty())
00770         strDelimChars.AssignLiteral(";");
00771 
00772     PRInt32 offset = 0 ;
00773     PRInt32 FilePathsLen = strFilePaths.Length() ;
00774     if (FilePathsLen)
00775     {
00776         nsAutoString Subject ;
00777 
00778         // multiple files to be sent, delim specified
00779         nsCOMPtr <nsILocalFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
00780         if (NS_FAILED(rv) || (!pFile) ) return rv ;        
00781 
00782         PRUnichar * newFilePaths = (PRUnichar *) strFilePaths.get() ;
00783         while (offset != kNotFound)
00784         {
00785             //Temp Directory
00786             nsCOMPtr <nsIFile> pTempFileDir;
00787             NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pTempFileDir));
00788             nsCOMPtr <nsILocalFile> pTempDir = do_QueryInterface(pTempFileDir);
00789 
00790             // if not already existing, create another temp dir for mapi within Win temp dir
00791             // this is windows only so we can do "\\"
00792             pTempDir->AppendRelativePath (NS_LITERAL_STRING("moz_mapi"));
00793             pTempDir->Exists(&bExist) ;
00794             if (!bExist)
00795             {
00796                 rv = pTempDir->Create(nsIFile::DIRECTORY_TYPE, 777) ;
00797                 if (NS_FAILED(rv)) return rv ;
00798             }
00799 
00800             nsString RemainingPaths ;
00801             RemainingPaths.Assign(newFilePaths) ;
00802             offset = RemainingPaths.Find (strDelimChars) ;
00803             if (offset != kNotFound)
00804             {
00805                 RemainingPaths.SetLength (offset) ;
00806                 if ((offset + strDelimChars.Length()) < FilePathsLen)
00807                     newFilePaths += offset + strDelimChars.Length() ;
00808                 else
00809                   offset = kNotFound;
00810                 FilePathsLen -= offset + strDelimChars.Length();
00811             }
00812 
00813             if (RemainingPaths[1] != ':' && RemainingPaths[1] != '\\') 
00814             {
00815               char cwd[MAX_PATH];  
00816               if (_getdcwd(_getdrive(), cwd, MAX_PATH)) 
00817               {
00818                 nsAutoString cwdStr;
00819                 CopyASCIItoUTF16(cwd, cwdStr);
00820                 cwdStr.Append('\\');
00821                 RemainingPaths.Insert(cwdStr, 0);
00822               }
00823             }
00824 
00825             pFile->InitWithPath (RemainingPaths) ;
00826 
00827             rv = pFile->Exists(&bExist) ;
00828             if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
00829 
00830             // filename of the file attachment
00831             nsAutoString leafName ;
00832             pFile->GetLeafName (leafName) ;
00833             if(NS_FAILED(rv) || leafName.IsEmpty()) return rv ;
00834 
00835             if (!Subject.IsEmpty()) 
00836                 Subject.AppendLiteral(", ");
00837             Subject += leafName;
00838 
00839             // create MsgCompose attachment object
00840             nsCOMPtr<nsIMsgAttachment> attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv);
00841             NS_ENSURE_SUCCESS(rv, rv);
00842 
00843             nsDependentString fileNameNative(leafName.get());
00844             rv = pFile->CopyTo(pTempDir, fileNameNative);
00845             if (NS_FAILED(rv)) return rv ;
00846 
00847             // now turn pTempDir into a full file path to the temp file
00848             pTempDir->Append(fileNameNative);
00849 
00850             // this one is a temp file so set the flag for MsgCompose
00851             attachment->SetTemporary(PR_TRUE) ;
00852 
00853             // now set the attachment object
00854             nsCAutoString pURL ;
00855             NS_GetURLSpecFromFile(pTempDir, pURL);
00856             attachment->SetUrl(pURL.get()) ;
00857 
00858             // add the attachment
00859             rv = aCompFields->AddAttachment (attachment);
00860             if (NS_FAILED(rv)) return rv ;
00861         }
00862 
00863         rv = aCompFields->SetBody(Subject) ;
00864     }
00865 
00866     return rv ;
00867 }
00868 
00869 // this used for Send with UI
00870 nsresult nsMapiHook::ShowComposerWindow (unsigned long aSession, nsIMsgCompFields * aCompFields) 
00871 {
00872     nsresult rv = NS_OK ;
00873 
00874     // create a send listener to get back the send status
00875     nsCOMPtr <nsIMsgSendListener> sendListener ;
00876     rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; 
00877     if (NS_FAILED(rv) || (!sendListener) ) return rv ;
00878 
00879     // create the compose params object 
00880     nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
00881     if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
00882 
00883     PRBool forcePlainText;
00884     aCompFields->GetForcePlainText(&forcePlainText);
00885     pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::Default : nsIMsgCompFormat::HTML);
00886     // populate the compose params
00887     pMsgComposeParams->SetType(nsIMsgCompType::New);
00888     pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
00889     pMsgComposeParams->SetComposeFields(aCompFields); 
00890     pMsgComposeParams->SetSendListener(sendListener) ;
00891 
00893     nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
00894     if (NS_FAILED(rv)|| (!compService) ) return rv ;
00895 
00896     rv = compService->OpenComposeWindowWithParams(nsnull, pMsgComposeParams) ;
00897     if (NS_FAILED(rv)) return rv ;
00898 
00899     return rv ;
00900 }