Back to index

lightning-sunbird  0.9+nobinonly
nsMessengerUnixIntegration.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  *   Seth Spitzer <sspitzer@netscape.com>
00024  *   Bhuvan Racham <racham@netscape.com>
00025  *   Howard Chu <hyc@symas.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 #include "nsMessengerUnixIntegration.h"
00042 #include "nsIMsgAccountManager.h"
00043 #include "nsIMsgMailSession.h"
00044 #include "nsIMsgIncomingServer.h"
00045 #include "nsIMsgIdentity.h"
00046 #include "nsIMsgAccount.h"
00047 #include "nsIRDFResource.h"
00048 #include "nsIMsgFolder.h"
00049 #include "nsCOMPtr.h"
00050 #include "nsMsgBaseCID.h"
00051 #include "nsMsgFolderFlags.h"
00052 #include "nsDirectoryServiceDefs.h"
00053 #include "nsAppDirectoryServiceDefs.h"
00054 #include "nsIDirectoryService.h"
00055 #include "nsIWindowWatcher.h"
00056 #include "nsIWindowMediator.h"
00057 #include "nsIDOMWindowInternal.h"
00058 #include "nsPIDOMWindow.h"
00059 #include "nsIDocShell.h"
00060 #include "nsIBaseWindow.h"
00061 #include "nsIWidget.h"
00062 
00063 #include "nsIMessengerWindowService.h"
00064 #include "prprf.h"
00065 #include "nsIWeakReference.h"
00066 #include "nsIStringBundle.h"
00067 #include "nsIAlertsService.h"
00068 #include "nsIPrefService.h"
00069 #include "nsIPrefBranch.h"
00070 #include "nsISupportsPrimitives.h"
00071 #include "nsIInterfaceRequestorUtils.h"
00072 
00073 #include "nsNativeCharsetUtils.h"
00074 
00075 #ifdef MOZ_XUL_APP
00076 #include "nsToolkitCompsCID.h" 
00077 #endif
00078 
00079 #define ALERT_CHROME_URL "chrome://messenger/content/newmailalert.xul"
00080 #define NEW_MAIL_ALERT_ICON "chrome://messenger/skin/icons/new-mail-alert.png"
00081 #define SHOW_ALERT_PREF "mail.biff.show_alert"
00082 
00083 static void openMailWindow(const PRUnichar * aMailWindowName, const char * aFolderUri)
00084 {
00085   nsCOMPtr<nsIWindowMediator> mediator ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
00086   if (!mediator)
00087     return;
00088 
00089   nsCOMPtr<nsIDOMWindowInternal> domWindow;
00090   mediator->GetMostRecentWindow(aMailWindowName, getter_AddRefs(domWindow));
00091   if (domWindow)
00092   {
00093     if (aFolderUri)
00094     {
00095       nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(domWindow));
00096       if (piDOMWindow)
00097       {
00098         nsCOMPtr<nsISupports> xpConnectObj;
00099         piDOMWindow->GetObjectProperty(NS_LITERAL_STRING("MsgWindowCommands").get(), getter_AddRefs(xpConnectObj));
00100         nsCOMPtr<nsIMsgWindowCommands> msgWindowCommands = do_QueryInterface(xpConnectObj);
00101         if (msgWindowCommands)
00102           msgWindowCommands->SelectFolder(aFolderUri);
00103       }
00104     }
00105 
00106     domWindow->Focus();
00107   }
00108   else
00109   {
00110     // the user doesn't have a mail window open already so open one for them...
00111     nsCOMPtr<nsIMessengerWindowService> messengerWindowService =
00112       do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID);
00113     // if we want to preselect the first account with new mail,
00114     // here is where we would try to generate a uri to pass in
00115     // (and add code to the messenger window service to make that work)
00116     if (messengerWindowService)
00117       messengerWindowService->OpenMessengerWindowWithUri(
00118                                 "mail:3pane", aFolderUri, nsMsgKey_None);
00119   }
00120 }
00121 
00122 nsMessengerUnixIntegration::nsMessengerUnixIntegration()
00123 {
00124   mBiffStateAtom = do_GetAtom("BiffState");
00125   mAlertInProgress = PR_FALSE;
00126   NS_NewISupportsArray(getter_AddRefs(mFoldersWithNewMail));
00127 }
00128 
00129 NS_IMPL_ISUPPORTS3(nsMessengerUnixIntegration, nsIFolderListener, nsIObserver, nsIMessengerOSIntegration)
00130 
00131 nsresult
00132 nsMessengerUnixIntegration::Init()
00133 {
00134   nsresult rv;
00135 
00136   nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00137   NS_ENSURE_SUCCESS(rv,rv);
00138 
00139   rv = mailSession->AddFolderListener(this, nsIFolderListener::intPropertyChanged);
00140   NS_ENSURE_SUCCESS(rv,rv);
00141 
00142   return NS_OK;
00143 }
00144 
00145 NS_IMETHODIMP
00146 nsMessengerUnixIntegration::OnItemPropertyChanged(nsIRDFResource *, nsIAtom *, char const *, char const *)
00147 {
00148   return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsMessengerUnixIntegration::OnItemUnicharPropertyChanged(nsIRDFResource *, nsIAtom *, const PRUnichar *, const PRUnichar *)
00153 {
00154   return NS_OK;
00155 }
00156 
00157 NS_IMETHODIMP
00158 nsMessengerUnixIntegration::OnItemRemoved(nsIRDFResource *, nsISupports *)
00159 {
00160   return NS_OK;
00161 }
00162 
00163 nsresult nsMessengerUnixIntegration::GetStringBundle(nsIStringBundle **aBundle)
00164 {
00165   nsresult rv = NS_OK;
00166   NS_ENSURE_ARG_POINTER(aBundle);
00167   nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00168   nsCOMPtr<nsIStringBundle> bundle;
00169   if (bundleService && NS_SUCCEEDED(rv))
00170     bundleService->CreateBundle("chrome://messenger/locale/messenger.properties", getter_AddRefs(bundle));
00171   NS_IF_ADDREF(*aBundle = bundle);
00172   return rv;
00173 }
00174 
00175 #ifndef MOZ_THUNDERBIRD
00176 nsresult nsMessengerUnixIntegration::ShowAlertMessage(const PRUnichar * aAlertTitle, const PRUnichar * aAlertText, const char * aFolderURI)
00177 {
00178   nsresult rv;
00179   
00180   // if we are already in the process of showing an alert, don't try to show another....
00181   if (mAlertInProgress) 
00182     return NS_OK; 
00183 
00184   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00185   PRBool showAlert = PR_TRUE;
00186   
00187   if (prefBranch)
00188     prefBranch->GetBoolPref(SHOW_ALERT_PREF, &showAlert);
00189   
00190   if (showAlert)
00191   {
00192     nsCOMPtr<nsIAlertsService> alertsService (do_GetService(NS_ALERTSERVICE_CONTRACTID, &rv));
00193     if (NS_SUCCEEDED(rv))
00194     {
00195       rv = alertsService->ShowAlertNotification(NS_LITERAL_STRING(NEW_MAIL_ALERT_ICON), nsDependentString(aAlertTitle),
00196                                                 nsDependentString(aAlertText), PR_TRUE, 
00197                                                 NS_ConvertASCIItoUTF16(aFolderURI), this); 
00198       mAlertInProgress = PR_TRUE;
00199     }
00200   }
00201 
00202   if (!showAlert || NS_FAILED(rv)) // go straight to showing the system tray icon.
00203     AlertFinished();
00204 
00205   return rv;
00206 }
00207 #else
00208 // Opening Thunderbird's new mail alert notification window
00209 // aUserInitiated --> true if we are opening the alert notification in response to a user action
00210 //                    like clicking on the biff icon
00211 nsresult nsMessengerUnixIntegration::ShowNewAlertNotification(PRBool aUserInitiated)
00212 {
00213   nsresult rv;
00214 
00215   // if we are already in the process of showing an alert, don't try to show another....
00216   if (mAlertInProgress)
00217     return NS_OK;
00218 
00219   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00220   PRBool showAlert = PR_TRUE;
00221 
00222   if (prefBranch)
00223     prefBranch->GetBoolPref(SHOW_ALERT_PREF, &showAlert);
00224 
00225   if (showAlert)
00226   {
00227     nsCOMPtr<nsISupportsArray> argsArray;
00228     rv = NS_NewISupportsArray(getter_AddRefs(argsArray));
00229     NS_ENSURE_SUCCESS(rv, rv);
00230 
00231     // pass in the array of folders with unread messages
00232     nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00233     NS_ENSURE_SUCCESS(rv, rv);
00234     ifptr->SetData(mFoldersWithNewMail);
00235     ifptr->SetDataIID(&NS_GET_IID(nsISupportsArray));
00236     argsArray->AppendElement(ifptr);
00237 
00238     // pass in the observer
00239     ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00240     NS_ENSURE_SUCCESS(rv, rv);
00241     nsCOMPtr <nsISupports> supports = do_QueryInterface(NS_STATIC_CAST(nsIMessengerOSIntegration*, this));
00242     ifptr->SetData(supports);
00243     ifptr->SetDataIID(&NS_GET_IID(nsIObserver));
00244     argsArray->AppendElement(ifptr);
00245 
00246     // pass in the animation flag
00247     nsCOMPtr<nsISupportsPRBool> scriptableUserInitiated (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID, &rv));
00248     NS_ENSURE_SUCCESS(rv, rv);
00249     scriptableUserInitiated->SetData(aUserInitiated);
00250     argsArray->AppendElement(scriptableUserInitiated);
00251 
00252     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00253     nsCOMPtr<nsIDOMWindow> newWindow;
00254     rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank",
00255                             "chrome,dialog=yes,titlebar=no,popup=yes", argsArray,
00256                             getter_AddRefs(newWindow));
00257 
00258     mAlertInProgress = PR_TRUE;
00259   }
00260 
00261   // if the user has turned off the mail alert, or  openWindow generated an error,
00262   // then go straight to the system tray.
00263   if (!showAlert || NS_FAILED(rv))
00264     AlertFinished();
00265 
00266   return rv;
00267 }
00268 #endif
00269 
00270 nsresult nsMessengerUnixIntegration::AlertFinished()
00271 {
00272   mAlertInProgress = PR_FALSE;
00273   return NS_OK;
00274 }
00275 
00276 nsresult nsMessengerUnixIntegration::AlertClicked()
00277 {
00278 #ifdef MOZ_THUNDERBIRD
00279   nsresult rv;
00280   nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00281   NS_ENSURE_SUCCESS(rv,rv);
00282   nsCOMPtr<nsIMsgWindow> topMostMsgWindow;
00283   rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(topMostMsgWindow));
00284   if (topMostMsgWindow)
00285   {
00286     nsCOMPtr<nsIDocShell> rootDocShell;
00287     rv = topMostMsgWindow->GetRootDocShell(getter_AddRefs(rootDocShell));
00288     NS_ENSURE_SUCCESS(rv, rv);
00289 
00290     nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(rootDocShell, &rv));
00291     NS_ENSURE_SUCCESS(rv, rv);
00292 
00293     domWindow->Focus();
00294   }
00295 #else
00296   nsXPIDLCString folderURI;
00297   GetFirstFolderWithNewMail(getter_Copies(folderURI));
00298 
00299   openMailWindow(NS_LITERAL_STRING("mail:3pane").get(), folderURI);
00300 #endif
00301   return NS_OK;
00302 }
00303 
00304 NS_IMETHODIMP
00305 nsMessengerUnixIntegration::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
00306 {
00307   if (strcmp(aTopic, "alertfinished") == 0)
00308       return AlertFinished();
00309 
00310   if (strcmp(aTopic, "alertclickcallback") == 0)
00311       return AlertClicked();
00312 
00313   return NS_OK;
00314 }
00315 
00316 void nsMessengerUnixIntegration::FillToolTipInfo()
00317 {
00318   nsCOMPtr<nsIWeakReference> weakReference = do_QueryElementAt(mFoldersWithNewMail, 0);
00319   nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(weakReference);
00320   if (folder)
00321   {
00322     nsXPIDLString accountName;
00323     folder->GetPrettiestName(getter_Copies(accountName));
00324 
00325     nsCOMPtr<nsIStringBundle> bundle; 
00326     GetStringBundle(getter_AddRefs(bundle));
00327     if (bundle)
00328     { 
00329       PRInt32 numNewMessages = 0;   
00330       folder->GetNumNewMessages(PR_TRUE, &numNewMessages);
00331       nsAutoString numNewMsgsText;     
00332       numNewMsgsText.AppendInt(numNewMessages);
00333 
00334       const PRUnichar *formatStrings[] =
00335       {
00336         numNewMsgsText.get(),       
00337       };
00338      
00339       nsXPIDLString finalText; 
00340       if (numNewMessages == 1)
00341         bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_message").get(), formatStrings, 1, getter_Copies(finalText));
00342       else
00343         bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_messages").get(), formatStrings, 1, getter_Copies(finalText));
00344 
00345 #ifndef MOZ_THUNDERBIRD
00346       ShowAlertMessage(accountName, finalText, "");
00347 #else
00348       ShowNewAlertNotification(PR_FALSE);
00349 #endif
00350     } // if we got a bundle
00351   } // if we got a folder
00352 }
00353 
00354 // get the first top level folder which we know has new mail, then enumerate over all the subfolders
00355 // looking for the first real folder with new mail. Return the folderURI for that folder.
00356 nsresult nsMessengerUnixIntegration::GetFirstFolderWithNewMail(char ** aFolderURI)
00357 {
00358   nsresult rv;
00359   NS_ENSURE_TRUE(mFoldersWithNewMail, NS_ERROR_FAILURE); 
00360 
00361   nsCOMPtr<nsIMsgFolder> folder;
00362   nsCOMPtr<nsIWeakReference> weakReference;
00363   PRInt32 numNewMessages = 0;
00364 
00365   PRUint32 count = 0;
00366   mFoldersWithNewMail->Count(&count);
00367 
00368   if (!count)  // kick out if we don't have any folders with new mail
00369     return NS_OK;
00370 
00371   weakReference = do_QueryElementAt(mFoldersWithNewMail, 0);
00372   folder = do_QueryReferent(weakReference);
00373   
00374   if (folder)
00375   {
00376     nsCOMPtr<nsIMsgFolder> msgFolder;
00377     // enumerate over the folders under this root folder till we find one with new mail....
00378     nsCOMPtr<nsISupportsArray> allFolders;
00379     NS_NewISupportsArray(getter_AddRefs(allFolders));
00380     rv = folder->ListDescendents(allFolders);
00381     NS_ENSURE_SUCCESS(rv, rv);
00382 
00383     nsCOMPtr<nsIEnumerator> enumerator;
00384     allFolders->Enumerate(getter_AddRefs(enumerator));
00385     if (enumerator)
00386     {
00387       nsCOMPtr<nsISupports> supports;
00388       nsresult more = enumerator->First();
00389       while (NS_SUCCEEDED(more))
00390       {
00391         rv = enumerator->CurrentItem(getter_AddRefs(supports));
00392         if (supports)
00393         {                   
00394           msgFolder = do_QueryInterface(supports, &rv);
00395           if (msgFolder)
00396           {
00397             numNewMessages = 0;   
00398             msgFolder->GetNumNewMessages(PR_FALSE, &numNewMessages);
00399             if (numNewMessages)
00400               break; // kick out of the while loop
00401             more = enumerator->Next();
00402           }
00403         } // if we have a folder
00404       }  // if we have more potential folders to enumerate
00405     }  // if enumerator
00406     
00407     if (msgFolder)
00408       msgFolder->GetURI(aFolderURI);
00409   }
00410 
00411   return NS_OK;
00412 }
00413 
00414 NS_IMETHODIMP
00415 nsMessengerUnixIntegration::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, PRUint32 oldFlag, PRUint32 newFlag)
00416 {
00417   return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP
00421 nsMessengerUnixIntegration::OnItemAdded(nsIRDFResource *, nsISupports *)
00422 {
00423   return NS_OK;
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsMessengerUnixIntegration::OnItemBoolPropertyChanged(nsIRDFResource *aItem,
00428                                                          nsIAtom *aProperty,
00429                                                          PRBool aOldValue,
00430                                                          PRBool aNewValue)
00431 {
00432   return NS_OK;
00433 }
00434 
00435 NS_IMETHODIMP
00436 nsMessengerUnixIntegration::OnItemEvent(nsIMsgFolder *, nsIAtom *)
00437 {
00438   return NS_OK;
00439 }
00440 
00441 NS_IMETHODIMP
00442 nsMessengerUnixIntegration::OnItemIntPropertyChanged(nsIRDFResource *aItem, nsIAtom *aProperty, PRInt32 aOldValue, PRInt32 aNewValue)
00443 {
00444   // if we got new mail show a icon in the system tray
00445   if (mBiffStateAtom == aProperty && mFoldersWithNewMail)
00446   {
00447     nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(aItem);
00448     NS_ENSURE_TRUE(folder, NS_OK);
00449 
00450     if (aNewValue == nsIMsgFolder::nsMsgBiffState_NewMail) 
00451     {
00452       // only show a system tray icon iff we are performing biff
00453       // (as opposed to the user getting new mail)
00454       PRBool performingBiff = PR_FALSE;
00455       nsCOMPtr<nsIMsgIncomingServer> server;
00456       folder->GetServer(getter_AddRefs(server));
00457       if (server)
00458         server->GetPerformingBiff(&performingBiff);
00459       if (!performingBiff) 
00460         return NS_OK; // kick out right now...
00461 
00462       nsCOMPtr<nsIWeakReference> weakFolder = do_GetWeakReference(folder); 
00463 
00464       if (mFoldersWithNewMail->IndexOf(weakFolder) == -1)
00465         mFoldersWithNewMail->AppendElement(weakFolder);
00466       // now regenerate the tooltip
00467       FillToolTipInfo();    
00468     }
00469     else if (aNewValue == nsIMsgFolder::nsMsgBiffState_NoMail)
00470     {
00471       // we are always going to remove the icon whenever we get our first no mail
00472       // notification. 
00473       
00474       mFoldersWithNewMail->Clear(); 
00475     }
00476   } // if the biff property changed
00477   return NS_OK;
00478 }