Back to index

lightning-sunbird  0.9+nobinonly
nsMessengerWinIntegration.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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  *   Jens Bannmann <jens.b@web.de>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include <windows.h>
00043 #include <shellapi.h>
00044 
00045 #include "nsMessengerWinIntegration.h"
00046 #include "nsIMsgAccountManager.h"
00047 #include "nsIMsgMailSession.h"
00048 #include "nsIMsgIncomingServer.h"
00049 #include "nsIMsgIdentity.h"
00050 #include "nsIMsgAccount.h"
00051 #include "nsIRDFResource.h"
00052 #include "nsIMsgFolder.h"
00053 #include "nsCOMPtr.h"
00054 #include "nsMsgBaseCID.h"
00055 #include "nsMsgFolderFlags.h"
00056 #include "nsDirectoryServiceDefs.h"
00057 #include "nsAppDirectoryServiceDefs.h"
00058 #include "nsIDirectoryService.h"
00059 #include "nsIWindowWatcher.h"
00060 #include "nsIWindowMediator.h"
00061 #include "nsIDOMWindowInternal.h"
00062 #include "nsPIDOMWindow.h"
00063 #include "nsIScriptGlobalObject.h"
00064 #include "nsIDocShell.h"
00065 #include "nsIBaseWindow.h"
00066 #include "nsIWidget.h"
00067 #include "nsWidgetsCID.h"
00068 #include "nsILookAndFeel.h"
00069 
00070 #include "nsIMessengerWindowService.h"
00071 #include "prprf.h"
00072 #include "nsIWeakReference.h"
00073 #include "nsIStringBundle.h"
00074 #include "nsIAlertsService.h"
00075 #include "nsIPrefService.h"
00076 #include "nsIPrefBranch.h"
00077 #include "nsISupportsPrimitives.h"
00078 #include "nsIInterfaceRequestorUtils.h"
00079 #include "nsNativeCharsetUtils.h"
00080 
00081 #ifdef MOZ_THUNDERBIRD
00082 #include "nsToolkitCompsCID.h" 
00083 #define PROFILE_COMMANDLINE_ARG " -profile "
00084 #else
00085 #include "nsIProfile.h"
00086 #define PROFILE_COMMANDLINE_ARG " -p "
00087 #endif
00088 
00089 #define XP_SHSetUnreadMailCounts "SHSetUnreadMailCountW"
00090 #define XP_SHEnumerateUnreadMailAccounts "SHEnumerateUnreadMailAccountsW"
00091 #define ShellNotifyWideVersion "Shell_NotifyIconW"
00092 #define NOTIFICATIONCLASSNAME "MailBiffNotificationMessageWindow"
00093 #define UNREADMAILNODEKEY "Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\"
00094 #define SHELL32_DLL NS_LITERAL_CSTRING("shell32.dll")
00095 #define DOUBLE_QUOTE "\""
00096 #define MAIL_COMMANDLINE_ARG " -mail"
00097 #define IDI_MAILBIFF 101
00098 #define UNREAD_UPDATE_INTERVAL     (20 * 1000)   // 20 seconds
00099 #define ALERT_CHROME_URL "chrome://messenger/content/newmailalert.xul"
00100 #define NEW_MAIL_ALERT_ICON "chrome://messenger/skin/icons/new-mail-alert.png"
00101 #define SHOW_ALERT_PREF     "mail.biff.show_alert"
00102 #define SHOW_TRAY_ICON_PREF "mail.biff.show_tray_icon"
00103 
00104 // since we are including windows.h in this file, undefine get user name....
00105 #ifdef GetUserName
00106 #undef GetUserName
00107 #endif
00108 
00109 // begin shameless copying from nsNativeAppSupportWin
00110 HWND hwndForDOMWindow( nsISupports *window ) 
00111 {
00112   nsCOMPtr<nsIScriptGlobalObject> ppScriptGlobalObj( do_QueryInterface(window) );
00113   if ( !ppScriptGlobalObj )
00114       return 0;
00115   
00116   nsCOMPtr<nsIBaseWindow> ppBaseWindow =
00117       do_QueryInterface( ppScriptGlobalObj->GetDocShell() );
00118   if (!ppBaseWindow) return 0;
00119 
00120   nsCOMPtr<nsIWidget> ppWidget;
00121   ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
00122 
00123   return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
00124 }
00125 
00126 static void activateWindow( nsIDOMWindowInternal *win ) 
00127 {
00128   // Try to get native window handle.
00129   HWND hwnd = hwndForDOMWindow( win );
00130   if ( hwnd ) 
00131   {
00132     // Restore the window if it is minimized.
00133     if ( ::IsIconic( hwnd ) ) 
00134       ::ShowWindow( hwnd, SW_RESTORE );
00135     // Use the OS call, if possible.
00136     ::SetForegroundWindow( hwnd );
00137   } else // Use internal method.  
00138     win->Focus();
00139 }
00140 // end shameless copying from nsNativeAppWinSupport.cpp
00141 
00142 static void openMailWindow(const PRUnichar * aMailWindowName, const char * aFolderUri)
00143 {
00144   nsCOMPtr<nsIWindowMediator> mediator ( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID) );
00145   if (!mediator)
00146     return;
00147 
00148   nsCOMPtr<nsIDOMWindowInternal> domWindow;
00149   mediator->GetMostRecentWindow(aMailWindowName, getter_AddRefs(domWindow));
00150   if (domWindow)
00151   {
00152     if (aFolderUri)
00153     {
00154       nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(domWindow));
00155       if (piDOMWindow)
00156       {
00157         nsCOMPtr<nsISupports> xpConnectObj;
00158         piDOMWindow->GetObjectProperty(NS_LITERAL_STRING("MsgWindowCommands").get(), getter_AddRefs(xpConnectObj));
00159         nsCOMPtr<nsIMsgWindowCommands> msgWindowCommands = do_QueryInterface(xpConnectObj);
00160         if (msgWindowCommands)
00161           msgWindowCommands->SelectFolder(aFolderUri);
00162       }
00163     }
00164 
00165     activateWindow(domWindow);
00166   }
00167   else
00168   {
00169     // the user doesn't have a mail window open already so open one for them...
00170     nsCOMPtr<nsIMessengerWindowService> messengerWindowService =
00171       do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID);
00172     // if we want to preselect the first account with new mail,
00173     // here is where we would try to generate a uri to pass in
00174     // (and add code to the messenger window service to make that work)
00175     if (messengerWindowService)
00176       messengerWindowService->OpenMessengerWindowWithUri(
00177                                 "mail:3pane", aFolderUri, nsMsgKey_None);
00178   }
00179 }
00180 
00181 static void CALLBACK delayedSingleClick(HWND msgWindow, UINT msg, INT_PTR idEvent, DWORD dwTime)
00182 {
00183   ::KillTimer(msgWindow, idEvent);
00184 
00185 #ifdef MOZ_THUNDERBIRD
00186   // single clicks on the biff icon should re-open the alert notification
00187   nsresult rv = NS_OK;
00188   nsCOMPtr<nsIMessengerOSIntegration> integrationService = 
00189     do_GetService(NS_MESSENGEROSINTEGRATION_CONTRACTID, &rv);
00190   if (NS_SUCCEEDED(rv))
00191   {
00192     // we know we are dealing with the windows integration object    
00193     nsMessengerWinIntegration * winIntegrationService = NS_STATIC_CAST(nsMessengerWinIntegration*, 
00194                                                                        NS_STATIC_CAST(nsIMessengerOSIntegration*, integrationService.get()));
00195     winIntegrationService->ShowNewAlertNotification(PR_TRUE);
00196   }
00197 #endif
00198 }
00199 
00200 // Window proc.
00201 static long CALLBACK MessageWindowProc( HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp ) 
00202 {
00203   if (msg == WM_USER)
00204   {
00205     if (lp == WM_LBUTTONDOWN)
00206     {
00207       // the only way to tell a single left click 
00208       // from a double left click is to fire a timer which gets cleared if we end up getting
00209       // a WM_LBUTTONDBLK event.
00210       ::SetTimer(msgWindow, 1, GetDoubleClickTime(), (TIMERPROC) delayedSingleClick);
00211     } 
00212     else if (lp == WM_LBUTTONDBLCLK)
00213     {
00214       ::KillTimer(msgWindow, 1);
00215       NS_NAMED_LITERAL_STRING(mailName, "mail:3pane");
00216       openMailWindow(mailName.get(), nsnull);
00217     }
00218   }
00219 
00220   return TRUE;
00221 }
00222 
00223 static HWND msgWindow;
00224 
00225 // Create: Register class and create window.
00226 static nsresult Create() 
00227 {
00228   if (msgWindow)
00229     return NS_OK;
00230 
00231   WNDCLASS classStruct = { 0,                          // style
00232                            &MessageWindowProc,         // lpfnWndProc
00233                            0,                          // cbClsExtra
00234                            0,                          // cbWndExtra
00235                            0,                          // hInstance
00236                            0,                          // hIcon
00237                            0,                          // hCursor
00238                            0,                          // hbrBackground
00239                            0,                          // lpszMenuName
00240                            NOTIFICATIONCLASSNAME };    // lpszClassName
00241 
00242   // Register the window class.
00243   NS_ENSURE_TRUE( ::RegisterClass( &classStruct ), NS_ERROR_FAILURE );
00244   // Create the window.
00245   NS_ENSURE_TRUE( msgWindow = ::CreateWindow( NOTIFICATIONCLASSNAME,
00246                                               0,          // title
00247                                               WS_CAPTION, // style
00248                                               0,0,0,0,    // x, y, cx, cy
00249                                               0,          // parent
00250                                               0,          // menu
00251                                               0,          // instance
00252                                               0 ),        // create struct
00253                   NS_ERROR_FAILURE );
00254   return NS_OK;
00255 }
00256 
00257 
00258 nsMessengerWinIntegration::nsMessengerWinIntegration()
00259 {
00260   mDefaultServerAtom = do_GetAtom("DefaultServer");
00261   mTotalUnreadMessagesAtom = do_GetAtom("TotalUnreadMessages");
00262 
00263   mUnreadTimerActive = PR_FALSE;
00264   mInboxURI = nsnull;
00265   mEmail = nsnull;
00266   mStoreUnreadCounts = PR_FALSE; 
00267 
00268   mBiffStateAtom = do_GetAtom("BiffState");
00269   mBiffIconVisible = PR_FALSE;
00270   mSuppressBiffIcon = PR_FALSE;
00271   mAlertInProgress = PR_FALSE;
00272   mBiffIconInitialized = PR_FALSE;
00273   mUseWideCharBiffIcon = PR_FALSE;
00274   NS_NewISupportsArray(getter_AddRefs(mFoldersWithNewMail));
00275 }
00276 
00277 nsMessengerWinIntegration::~nsMessengerWinIntegration()
00278 {
00279   if (mUnreadCountUpdateTimer) {
00280     mUnreadCountUpdateTimer->Cancel();
00281     mUnreadCountUpdateTimer = nsnull;
00282   }
00283 
00284   // one last attempt, update the registry
00285   nsresult rv = UpdateRegistryWithCurrent();
00286   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to update registry on shutdown");
00287   
00288   CRTFREEIF(mInboxURI);
00289   CRTFREEIF(mEmail);
00290 
00291   DestroyBiffIcon(); 
00292 }
00293 
00294 NS_IMPL_ADDREF(nsMessengerWinIntegration)
00295 NS_IMPL_RELEASE(nsMessengerWinIntegration)
00296 
00297 NS_INTERFACE_MAP_BEGIN(nsMessengerWinIntegration)
00298    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMessengerOSIntegration)
00299    NS_INTERFACE_MAP_ENTRY(nsIMessengerOSIntegration)
00300    NS_INTERFACE_MAP_ENTRY(nsIFolderListener)
00301    NS_INTERFACE_MAP_ENTRY(nsIObserver)
00302 NS_INTERFACE_MAP_END
00303 
00304 
00305 nsresult
00306 nsMessengerWinIntegration::ResetCurrent()
00307 {
00308   CRTFREEIF(mInboxURI);
00309   CRTFREEIF(mEmail);
00310 
00311   mCurrentUnreadCount = -1;
00312   mLastUnreadCountWrittenToRegistry = -1;
00313 
00314   mDefaultAccountMightHaveAnInbox = PR_TRUE;
00315   return NS_OK;
00316 }
00317 
00318 NOTIFYICONDATA nsMessengerWinIntegration::sNativeBiffIconData = { sizeof(NOTIFYICONDATA),
00319                                                     0,
00320                                                     2,
00321                                                     NIF_ICON | NIF_MESSAGE | NIF_TIP,
00322                                                     WM_USER,
00323                                                     0,
00324                                                     0 };
00325 
00326 NOTIFYICONDATAW nsMessengerWinIntegration::sWideBiffIconData = { sizeof(NOTIFYICONDATAW),
00327                                                     0,
00328                                                     2,
00329                                                     NIF_ICON | NIF_MESSAGE | NIF_TIP,
00330                                                     WM_USER,
00331                                                     0,
00332                                                     0 };
00333 
00334 #ifdef MOZ_THUNDERBIRD
00335 #ifdef MOZ_STATIC_BUILD
00336 #define MAIL_DLL_NAME NULL
00337 #else
00338 #define MAIL_DLL_NAME "mail.dll"
00339 #endif
00340 #else
00341 #define MAIL_DLL_NAME "msgbase.dll"
00342 #endif
00343 
00344 void nsMessengerWinIntegration::InitializeBiffStatusIcon()
00345 {
00346   // initialize our biff status bar icon 
00347   Create();
00348 
00349   if (mUseWideCharBiffIcon)
00350   {
00351     sWideBiffIconData.hWnd = (HWND) msgWindow;
00352     sWideBiffIconData.hIcon =  ::LoadIcon( ::GetModuleHandle( MAIL_DLL_NAME ), MAKEINTRESOURCE(IDI_MAILBIFF) );
00353     sWideBiffIconData.szTip[0] = 0;
00354   }
00355   else
00356   {
00357     sNativeBiffIconData.hWnd = (HWND) msgWindow;
00358     sNativeBiffIconData.hIcon =  ::LoadIcon( ::GetModuleHandle( MAIL_DLL_NAME ), MAKEINTRESOURCE(IDI_MAILBIFF) );
00359     sNativeBiffIconData.szTip[0] = 0;
00360   }
00361 
00362   mBiffIconInitialized = PR_TRUE;
00363 }
00364 
00365 nsresult
00366 nsMessengerWinIntegration::Init()
00367 {
00368   nsresult rv;
00369 
00370   // get directory service to build path for shell dll
00371   nsCOMPtr<nsIProperties> directoryService = 
00372     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00373   NS_ENSURE_SUCCESS(rv,rv);
00374 
00375   // get path strings needed for unread mail count update
00376   nsCOMPtr<nsIFile> systemDir;
00377   rv = directoryService->Get(NS_OS_SYSTEM_DIR, 
00378                              NS_GET_IID(nsIFile), 
00379                              getter_AddRefs(systemDir));
00380   NS_ENSURE_SUCCESS(rv,rv);
00381 
00382   // get path to shell dll.
00383   nsCAutoString shellFile;
00384   rv = systemDir->GetNativePath(shellFile);
00385   NS_ENSURE_SUCCESS(rv,rv);
00386 
00387   mShellDllPath.Assign(shellFile + NS_LITERAL_CSTRING("\\") + SHELL32_DLL);
00388 
00389   // load shell dll. If no such dll found, return 
00390   HMODULE hModule = ::LoadLibrary(mShellDllPath.get());
00391   if (!hModule)
00392     return NS_OK;
00393 
00394   // get process addresses for the unread mail count functions
00395   if (hModule) {
00396     mSHSetUnreadMailCount = (fnSHSetUnreadMailCount)GetProcAddress(hModule, XP_SHSetUnreadMailCounts);
00397     mSHEnumerateUnreadMailAccounts = (fnSHEnumerateUnreadMailAccounts)GetProcAddress(hModule, XP_SHEnumerateUnreadMailAccounts);
00398     mShellNotifyWideChar = (fnShellNotifyW)GetProcAddress(hModule, ShellNotifyWideVersion);
00399     if (mShellNotifyWideChar)
00400        mUseWideCharBiffIcon = PR_TRUE; // this version of the shell supports I18N friendly ShellNotify routines.
00401   }
00402 
00403   // if failed to get either of the process addresses, this is not XP platform
00404   // so we aren't storing unread counts
00405   if (mSHSetUnreadMailCount && mSHEnumerateUnreadMailAccounts)
00406     mStoreUnreadCounts = PR_TRUE; 
00407 
00408   nsCOMPtr <nsIMsgAccountManager> accountManager = 
00409     do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00410   NS_ENSURE_SUCCESS(rv,rv);
00411 
00412   // because we care if the default server changes
00413   rv = accountManager->AddRootFolderListener(this);
00414   NS_ENSURE_SUCCESS(rv,rv);
00415 
00416   nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00417   NS_ENSURE_SUCCESS(rv,rv);
00418 
00419   // because we care if the unread total count changes
00420   rv = mailSession->AddFolderListener(this, nsIFolderListener::boolPropertyChanged | nsIFolderListener::intPropertyChanged);
00421   NS_ENSURE_SUCCESS(rv,rv);
00422 
00423   if (mStoreUnreadCounts)
00424   {
00425 #ifdef MOZ_THUNDERBIRD
00426     // get current profile path for the commandliner
00427     nsCOMPtr<nsIFile> profilePath;
00428     rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR, 
00429                                NS_GET_IID(nsIFile), 
00430                                getter_AddRefs(profilePath));
00431     NS_ENSURE_SUCCESS(rv,rv);
00432 
00433     rv = profilePath->GetPath(mProfilePath);
00434     NS_ENSURE_SUCCESS(rv, rv);
00435 #else
00436     // get current profile name to fill in commandliner. 
00437     nsCOMPtr<nsIProfile> profileService = do_GetService(NS_PROFILE_CONTRACTID, &rv);
00438     NS_ENSURE_SUCCESS(rv,rv);
00439 
00440     profileService->GetCurrentProfile(getter_Copies(mProfileName));
00441 #endif
00442 
00443     // get application path 
00444     char appPath[_MAX_PATH] = {0};
00445     GetModuleFileName(nsnull, appPath, sizeof(appPath));
00446     WCHAR wideFormatAppPath[_MAX_PATH*2] = {0};
00447     MultiByteToWideChar(CP_ACP, 0, appPath, strlen(appPath), wideFormatAppPath, _MAX_PATH*2);
00448     mAppName.Assign((PRUnichar *)wideFormatAppPath);
00449 
00450     rv = ResetCurrent();
00451     NS_ENSURE_SUCCESS(rv,rv);
00452   }
00453 
00454   return NS_OK;
00455 }
00456 
00457 NS_IMETHODIMP
00458 nsMessengerWinIntegration::OnItemPropertyChanged(nsIRDFResource *, nsIAtom *, char const *, char const *)
00459 {
00460   return NS_OK;
00461 }
00462 
00463 NS_IMETHODIMP
00464 nsMessengerWinIntegration::OnItemUnicharPropertyChanged(nsIRDFResource *, nsIAtom *, const PRUnichar *, const PRUnichar *)
00465 {
00466   return NS_OK;
00467 }
00468 
00469 NS_IMETHODIMP
00470 nsMessengerWinIntegration::OnItemRemoved(nsIRDFResource *, nsISupports *)
00471 {
00472   return NS_OK;
00473 }
00474 
00475 nsresult nsMessengerWinIntegration::GetStringBundle(nsIStringBundle **aBundle)
00476 {
00477   nsresult rv = NS_OK;
00478   NS_ENSURE_ARG_POINTER(aBundle);
00479   nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00480   nsCOMPtr<nsIStringBundle> bundle;
00481   if (bundleService && NS_SUCCEEDED(rv))
00482     bundleService->CreateBundle("chrome://messenger/locale/messenger.properties", getter_AddRefs(bundle));
00483   NS_IF_ADDREF(*aBundle = bundle);
00484   return rv;
00485 }
00486 
00487 #ifndef MOZ_THUNDERBIRD
00488 nsresult nsMessengerWinIntegration::ShowAlertMessage(const PRUnichar * aAlertTitle, const PRUnichar * aAlertText, const char * aFolderURI)
00489 {
00490   nsresult rv;
00491   
00492   // if we are already in the process of showing an alert, don't try to show another....
00493   if (mAlertInProgress) 
00494     return NS_OK; 
00495 
00496   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00497   PRBool showAlert = PR_TRUE;
00498   
00499   if (prefBranch)
00500     prefBranch->GetBoolPref(SHOW_ALERT_PREF, &showAlert);
00501   
00502   if (showAlert)
00503   {
00504     nsCOMPtr<nsIAlertsService> alertsService (do_GetService(NS_ALERTSERVICE_CONTRACTID, &rv));
00505     if (NS_SUCCEEDED(rv))
00506     {
00507       rv = alertsService->ShowAlertNotification(NS_LITERAL_STRING(NEW_MAIL_ALERT_ICON), nsDependentString(aAlertTitle),
00508                                                 nsDependentString(aAlertText), PR_TRUE, 
00509                                                 NS_ConvertASCIItoUCS2(aFolderURI), this); 
00510       mAlertInProgress = PR_TRUE;
00511     }
00512   }
00513 
00514   if (!showAlert || NS_FAILED(rv)) // go straight to showing the system tray icon.
00515     AlertFinished();
00516 
00517   return rv;
00518 }
00519 #else
00520 // Opening Thunderbird's new mail alert notification window
00521 // aUserInitiated --> true if we are opening the alert notification in response to a user action
00522 //                    like clicking on the biff icon
00523 nsresult nsMessengerWinIntegration::ShowNewAlertNotification(PRBool aUserInitiated)
00524 {
00525   nsresult rv;
00526 
00527   // if we are already in the process of showing an alert, don't try to show another....
00528   if (mAlertInProgress) 
00529     return NS_OK;
00530   
00531   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00532   PRBool showAlert = PR_TRUE;
00533   
00534   if (prefBranch)
00535     prefBranch->GetBoolPref(SHOW_ALERT_PREF, &showAlert);
00536   
00537   if (showAlert)
00538   {
00539     nsCOMPtr<nsISupportsArray> argsArray;
00540     rv = NS_NewISupportsArray(getter_AddRefs(argsArray));
00541     NS_ENSURE_SUCCESS(rv, rv);
00542 
00543     // pass in the array of folders with unread messages
00544     nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00545     NS_ENSURE_SUCCESS(rv, rv);
00546     ifptr->SetData(mFoldersWithNewMail);
00547     ifptr->SetDataIID(&NS_GET_IID(nsISupportsArray));
00548     rv = argsArray->AppendElement(ifptr);
00549     NS_ENSURE_SUCCESS(rv, rv);
00550 
00551     // pass in the observer
00552     ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00553     NS_ENSURE_SUCCESS(rv, rv);
00554     nsCOMPtr <nsISupports> supports = do_QueryInterface(NS_STATIC_CAST(nsIMessengerOSIntegration*, this));
00555     ifptr->SetData(supports);
00556     ifptr->SetDataIID(&NS_GET_IID(nsIObserver));
00557     rv = argsArray->AppendElement(ifptr);
00558     NS_ENSURE_SUCCESS(rv, rv);
00559     
00560     // pass in the animation flag
00561     nsCOMPtr<nsISupportsPRBool> scriptableUserInitiated (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID, &rv));
00562     NS_ENSURE_SUCCESS(rv, rv);
00563     scriptableUserInitiated->SetData(aUserInitiated);
00564     rv = argsArray->AppendElement(scriptableUserInitiated);
00565     NS_ENSURE_SUCCESS(rv, rv);
00566 
00567     // pass in the alert origin
00568     nsCOMPtr<nsISupportsPRUint8> scriptableOrigin (do_CreateInstance(NS_SUPPORTS_PRUINT8_CONTRACTID));
00569     NS_ENSURE_TRUE(scriptableOrigin, NS_ERROR_FAILURE);
00570     scriptableOrigin->SetData(0);
00571     nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService("@mozilla.org/widget/lookandfeel;1");
00572     if (lookAndFeel)
00573     {
00574       PRInt32 origin;
00575       lookAndFeel->GetMetric(nsILookAndFeel::eMetric_AlertNotificationOrigin,
00576                              origin);
00577       if (origin && origin >= 0 && origin <= 7)
00578         scriptableOrigin->SetData(origin);
00579     }
00580     rv = argsArray->AppendElement(scriptableOrigin);
00581     NS_ENSURE_SUCCESS(rv, rv);
00582 
00583     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00584     nsCOMPtr<nsIDOMWindow> newWindow;
00585     rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank",
00586                 "chrome,dialog=yes,titlebar=no,popup=yes", argsArray,
00587                  getter_AddRefs(newWindow));
00588 
00589     mAlertInProgress = PR_TRUE;
00590   }
00591 
00592   // if the user has turned off the mail alert, or  openWindow generated an error, 
00593   // then go straight to the system tray.
00594   if (!showAlert || NS_FAILED(rv)) 
00595     AlertFinished();
00596 
00597   return rv;
00598 }
00599 #endif
00600 
00601 nsresult nsMessengerWinIntegration::AlertFinished()
00602 {
00603   // okay, we are done showing the alert
00604   // now put an icon in the system tray, if allowed
00605   PRBool showTrayIcon = !mSuppressBiffIcon;
00606   if (showTrayIcon)
00607   {
00608     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
00609     if (prefBranch)
00610       prefBranch->GetBoolPref(SHOW_TRAY_ICON_PREF, &showTrayIcon);
00611   }
00612   if (showTrayIcon)
00613   {
00614     GenericShellNotify(NIM_ADD);
00615     mBiffIconVisible = PR_TRUE;
00616   }
00617   mSuppressBiffIcon = PR_FALSE;
00618   mAlertInProgress = PR_FALSE;
00619   return NS_OK;
00620 }
00621 
00622 nsresult nsMessengerWinIntegration::AlertClicked()
00623 {
00624 #ifdef MOZ_THUNDERBIRD
00625   nsresult rv;
00626   nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00627   NS_ENSURE_SUCCESS(rv,rv);
00628   nsCOMPtr<nsIMsgWindow> topMostMsgWindow;
00629   rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(topMostMsgWindow));
00630   if (topMostMsgWindow)
00631   {
00632     nsCOMPtr<nsIDocShell> rootDocShell;
00633     rv = topMostMsgWindow->GetRootDocShell(getter_AddRefs(rootDocShell));
00634     NS_ENSURE_SUCCESS(rv, rv);
00635     
00636     nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(rootDocShell, &rv));
00637     NS_ENSURE_SUCCESS(rv, rv);
00638     
00639     activateWindow(domWindow);
00640   }
00641 #else
00642   // make sure we don't insert the icon in the system tray since the user clicked on the alert.
00643   mSuppressBiffIcon = PR_TRUE;
00644 
00645   nsXPIDLCString folderURI;
00646   GetFirstFolderWithNewMail(getter_Copies(folderURI));
00647 
00648   openMailWindow(NS_LITERAL_STRING("mail:3pane").get(), folderURI);
00649 #endif
00650   return NS_OK;
00651 }
00652 
00653 NS_IMETHODIMP
00654 nsMessengerWinIntegration::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
00655 {
00656   if (strcmp(aTopic, "alertfinished") == 0)
00657       return AlertFinished();
00658 
00659   if (strcmp(aTopic, "alertclickcallback") == 0)
00660       return AlertClicked();
00661 
00662   return NS_OK;
00663 }
00664 
00665 void nsMessengerWinIntegration::FillToolTipInfo()
00666 {
00667   // iterate over all the folders in mFoldersWithNewMail
00668   nsXPIDLString accountName;
00669   nsXPIDLCString hostName; 
00670   nsAutoString toolTipText;
00671   nsAutoString animatedAlertText;
00672   nsCOMPtr<nsIMsgFolder> folder;
00673   nsCOMPtr<nsIWeakReference> weakReference;
00674   PRInt32 numNewMessages = 0;
00675 
00676   PRUint32 count = 0;
00677   mFoldersWithNewMail->Count(&count);
00678   PRUint32 maxTooltipSize = GetToolTipSize();
00679 
00680   for (PRUint32 index = 0; index < count; index++)
00681   {
00682     weakReference = do_QueryElementAt(mFoldersWithNewMail, index);
00683     folder = do_QueryReferent(weakReference);
00684     if (folder)
00685     {
00686       folder->GetPrettiestName(getter_Copies(accountName));
00687 
00688       numNewMessages = 0;   
00689       folder->GetNumNewMessages(PR_TRUE, &numNewMessages);
00690       nsCOMPtr<nsIStringBundle> bundle; 
00691       GetStringBundle(getter_AddRefs(bundle));
00692       if (bundle)
00693       { 
00694         nsAutoString numNewMsgsText;     
00695         numNewMsgsText.AppendInt(numNewMessages);
00696 
00697         const PRUnichar *formatStrings[] =
00698         {
00699           numNewMsgsText.get(),       
00700         };
00701        
00702         nsXPIDLString finalText; 
00703         if (numNewMessages == 1)
00704           bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_message").get(), formatStrings, 1, getter_Copies(finalText));
00705         else
00706           bundle->FormatStringFromName(NS_LITERAL_STRING("biffNotification_messages").get(), formatStrings, 1, getter_Copies(finalText));
00707 
00708         // the alert message is special...we actually only want to show the first account with 
00709         // new mail in the alert. 
00710         if (animatedAlertText.IsEmpty()) // if we haven't filled in the animated alert text yet
00711           animatedAlertText = finalText;
00712 
00713         // only add this new string if it will fit without truncation....
00714         if (maxTooltipSize >= toolTipText.Length() + accountName.Length() + finalText.Length() + 2)
00715         {
00716            if (index > 0)
00717             toolTipText.Append(NS_LITERAL_STRING("\n").get());
00718           toolTipText.Append(accountName);
00719           toolTipText.AppendLiteral(" ");
00720                     toolTipText.Append(finalText);
00721         }
00722       } // if we got a bundle
00723     } // if we got a folder
00724   } // for each folder
00725 
00726   SetToolTipStringOnIconData(toolTipText.get());
00727 
00728   if (!mBiffIconVisible)
00729   {
00730 #ifndef MOZ_THUNDERBIRD
00731     ShowAlertMessage(accountName, animatedAlertText.get(), "");
00732 #else
00733     ShowNewAlertNotification(PR_FALSE);
00734 #endif
00735   }
00736   else
00737    GenericShellNotify( NIM_MODIFY);
00738 }
00739 
00740 // get the first top level folder which we know has new mail, then enumerate over all the subfolders
00741 // looking for the first real folder with new mail. Return the folderURI for that folder.
00742 nsresult nsMessengerWinIntegration::GetFirstFolderWithNewMail(char ** aFolderURI)
00743 {
00744   nsresult rv;
00745   NS_ENSURE_TRUE(mFoldersWithNewMail, NS_ERROR_FAILURE); 
00746 
00747   nsCOMPtr<nsIMsgFolder> folder;
00748   nsCOMPtr<nsIWeakReference> weakReference;
00749   PRInt32 numNewMessages = 0;
00750 
00751   PRUint32 count = 0;
00752   mFoldersWithNewMail->Count(&count);
00753 
00754   if (!count)  // kick out if we don't have any folders with new mail
00755     return NS_OK;
00756 
00757   weakReference = do_QueryElementAt(mFoldersWithNewMail, 0);
00758   folder = do_QueryReferent(weakReference);
00759   
00760   if (folder)
00761   {
00762     nsCOMPtr<nsIMsgFolder> msgFolder;
00763     // enumerate over the folders under this root folder till we find one with new mail....
00764     nsCOMPtr<nsISupportsArray> allFolders;
00765     NS_NewISupportsArray(getter_AddRefs(allFolders));
00766     rv = folder->ListDescendents(allFolders);
00767     NS_ENSURE_SUCCESS(rv, rv);
00768 
00769     nsCOMPtr<nsIEnumerator> enumerator;
00770     allFolders->Enumerate(getter_AddRefs(enumerator));
00771     if (enumerator)
00772     {
00773       nsCOMPtr<nsISupports> supports;
00774       nsresult more = enumerator->First();
00775       while (NS_SUCCEEDED(more))
00776       {
00777         rv = enumerator->CurrentItem(getter_AddRefs(supports));
00778         if (supports)
00779         {                   
00780           msgFolder = do_QueryInterface(supports, &rv);
00781           if (msgFolder)
00782           {
00783             numNewMessages = 0;   
00784             msgFolder->GetNumNewMessages(PR_FALSE, &numNewMessages);
00785             if (numNewMessages)
00786               break; // kick out of the while loop
00787             more = enumerator->Next();
00788           }
00789         } // if we have a folder
00790       }  // if we have more potential folders to enumerate
00791     }  // if enumerator
00792     
00793     if (msgFolder)
00794       msgFolder->GetURI(aFolderURI);
00795   }
00796 
00797   return NS_OK;
00798 }
00799 
00800 void nsMessengerWinIntegration::DestroyBiffIcon()
00801 {
00802   GenericShellNotify(NIM_DELETE); 
00803   // Don't call DestroyIcon().  see http://bugzilla.mozilla.org/show_bug.cgi?id=134745
00804 }
00805 
00806 PRUint32 nsMessengerWinIntegration::GetToolTipSize()
00807 {
00808   if (mUseWideCharBiffIcon)
00809     return (sizeof(sWideBiffIconData.szTip)/sizeof(sWideBiffIconData.szTip[0]));
00810   else
00811     return (sizeof(sNativeBiffIconData.szTip));
00812 }
00813 
00814 void nsMessengerWinIntegration::SetToolTipStringOnIconData(const PRUnichar * aToolTipString)
00815 {
00816   if (!aToolTipString) return;
00817 
00818   PRUint32 toolTipBufSize = GetToolTipSize();
00819   
00820   if (mUseWideCharBiffIcon)
00821   {
00822     ::wcsncpy( sWideBiffIconData.szTip, aToolTipString, toolTipBufSize);
00823     if (wcslen(aToolTipString) >= toolTipBufSize)
00824       sWideBiffIconData.szTip[toolTipBufSize - 1] = 0;
00825   }
00826   else
00827   {
00828     nsCAutoString nativeToolTipString;
00829     NS_CopyUnicodeToNative(nsDependentString(aToolTipString),
00830                            nativeToolTipString);
00831     ::strncpy(sNativeBiffIconData.szTip,
00832               nativeToolTipString.get(), GetToolTipSize());
00833     if (nativeToolTipString.Length() >= toolTipBufSize)
00834       sNativeBiffIconData.szTip[toolTipBufSize - 1] = 0;
00835   }
00836 }
00837 
00838 void nsMessengerWinIntegration::GenericShellNotify(DWORD aMessage)
00839 {
00840   if (mUseWideCharBiffIcon)
00841   {
00842     BOOL res = mShellNotifyWideChar( aMessage, &sWideBiffIconData );
00843     if (!res)
00844       RevertToNonUnicodeShellAPI(); // oops we don't really implement the unicode shell apis...fall back.
00845     else
00846       return; 
00847   }
00848   
00849   ::Shell_NotifyIcon( aMessage, &sNativeBiffIconData ); 
00850 }
00851 
00852 // some flavors of windows define ShellNotifyW but when you actually try to use it,
00853 // they return an error. In this case, we'll have a routine which converts us over to the 
00854 // default ASCII version. 
00855 void nsMessengerWinIntegration::RevertToNonUnicodeShellAPI()
00856 {
00857   mUseWideCharBiffIcon = PR_FALSE;
00858 
00859   // now initialize the ascii shell notify struct
00860   InitializeBiffStatusIcon();
00861 
00862   // now we need to copy over any left over tool tip strings
00863   if (sWideBiffIconData.szTip)
00864   {
00865     const PRUnichar * oldTooltipString = sWideBiffIconData.szTip;
00866     SetToolTipStringOnIconData(oldTooltipString);
00867   }
00868 }
00869 
00870 NS_IMETHODIMP
00871 nsMessengerWinIntegration::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, PRUint32 oldFlag, PRUint32 newFlag)
00872 {
00873   nsresult rv = NS_OK;
00874   
00875   return NS_OK;
00876 }
00877 
00878 NS_IMETHODIMP
00879 nsMessengerWinIntegration::OnItemAdded(nsIRDFResource *, nsISupports *)
00880 {
00881   return NS_OK;
00882 }
00883 
00884 NS_IMETHODIMP
00885 nsMessengerWinIntegration::OnItemBoolPropertyChanged(nsIRDFResource *aItem,
00886                                                          nsIAtom *aProperty,
00887                                                          PRBool aOldValue,
00888                                                          PRBool aNewValue)
00889 {
00890   if (aProperty == mDefaultServerAtom) {
00891     nsresult rv;
00892 
00893     // this property changes multiple times
00894     // on account deletion or when the user changes their
00895     // default account.  ResetCurrent() will set
00896     // mInboxURI to null, so we use that
00897     // to prevent us from attempting to remove 
00898     // something from the registry that has already been removed
00899     if (mInboxURI && mEmail) {
00900       rv = RemoveCurrentFromRegistry();
00901       NS_ENSURE_SUCCESS(rv,rv);
00902     }
00903 
00904     // reset so we'll go get the new default server next time
00905     rv = ResetCurrent();
00906     NS_ENSURE_SUCCESS(rv,rv);
00907 
00908     rv = UpdateUnreadCount();
00909     NS_ENSURE_SUCCESS(rv,rv);
00910   }
00911   return NS_OK;
00912 }
00913 
00914 NS_IMETHODIMP
00915 nsMessengerWinIntegration::OnItemEvent(nsIMsgFolder *, nsIAtom *)
00916 {
00917   return NS_OK;
00918 }
00919 
00920 NS_IMETHODIMP
00921 nsMessengerWinIntegration::OnItemIntPropertyChanged(nsIRDFResource *aItem, nsIAtom *aProperty, PRInt32 aOldValue, PRInt32 aNewValue)
00922 {
00923   // if we got new mail show a icon in the system tray
00924   if (mBiffStateAtom == aProperty && mFoldersWithNewMail)
00925   {
00926     if (!mBiffIconInitialized)
00927       InitializeBiffStatusIcon(); 
00928 
00929     nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(aItem);
00930     NS_ENSURE_TRUE(folder, NS_OK);
00931 
00932     if (aNewValue == nsIMsgFolder::nsMsgBiffState_NewMail) 
00933     {
00934       // if the icon is not already visible, only show a system tray icon iff 
00935       // we are performing biff (as opposed to the user getting new mail)
00936       if (!mBiffIconVisible)
00937       {
00938         PRBool performingBiff = PR_FALSE;
00939         nsCOMPtr<nsIMsgIncomingServer> server;
00940         folder->GetServer(getter_AddRefs(server));
00941         if (server)
00942           server->GetPerformingBiff(&performingBiff);
00943         if (!performingBiff) 
00944           return NS_OK; // kick out right now...
00945       }
00946       nsCOMPtr<nsIWeakReference> weakFolder = do_GetWeakReference(folder); 
00947 
00948       if (mFoldersWithNewMail->IndexOf(weakFolder) == -1)
00949         mFoldersWithNewMail->AppendElement(weakFolder);
00950       // now regenerate the tooltip
00951       FillToolTipInfo();    
00952     }
00953     else if (aNewValue == nsIMsgFolder::nsMsgBiffState_NoMail)
00954     {
00955       // we are always going to remove the icon whenever we get our first no mail
00956       // notification. 
00957       
00958       // avoid a race condition where we are told to remove the icon before we've actually
00959       // added it to the system tray. This happens when the user reads a new message before
00960       // the animated alert has gone away.
00961       if (mAlertInProgress)
00962         mSuppressBiffIcon = PR_TRUE;
00963 
00964       mFoldersWithNewMail->Clear(); 
00965       if (mBiffIconVisible) 
00966       {
00967         mBiffIconVisible = PR_FALSE;
00968         GenericShellNotify(NIM_DELETE); 
00969       }
00970     }
00971   } // if the biff property changed
00972 
00973   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
00974 
00975   if (aProperty == mTotalUnreadMessagesAtom) {
00976     const char *itemURI = nsnull;
00977     nsresult rv;
00978     rv = aItem->GetValueConst(&itemURI);
00979     NS_ENSURE_SUCCESS(rv,rv);
00980 
00981     if (itemURI && mInboxURI && !strcmp(itemURI, mInboxURI)) {
00982       mCurrentUnreadCount = aNewValue;
00983     }
00984 
00985     // If the timer isn't running yet, then we immediately update the
00986     // registry and then start a one-shot timer. If the Unread counter
00987     // has toggled zero / nonzero, we also update immediately.
00988     // Otherwise, if the timer is running, defer the update. This means
00989     // that all counter updates that occur within the timer interval are
00990     // batched into a single registry update, to avoid hitting the
00991     // registry too frequently. We also do a final update on shutdown,
00992     // regardless of the timer.
00993     if (!mUnreadTimerActive ||
00994          (!mCurrentUnreadCount && mLastUnreadCountWrittenToRegistry) ||
00995          (mCurrentUnreadCount && mLastUnreadCountWrittenToRegistry < 1)) {
00996       rv = UpdateUnreadCount();
00997       NS_ENSURE_SUCCESS(rv,rv);
00998       // If timer wasn't running, start it.
00999       if (!mUnreadTimerActive)
01000         rv = SetupUnreadCountUpdateTimer();
01001     }
01002   }
01003   return NS_OK;
01004 }
01005 
01006 void 
01007 nsMessengerWinIntegration::OnUnreadCountUpdateTimer(nsITimer *timer, void *osIntegration)
01008 {
01009   nsMessengerWinIntegration *winIntegration = (nsMessengerWinIntegration*)osIntegration;
01010 
01011   winIntegration->mUnreadTimerActive = PR_FALSE;
01012   nsresult rv = winIntegration->UpdateUnreadCount();
01013   NS_ASSERTION(NS_SUCCEEDED(rv), "updating unread count failed");
01014 }
01015 
01016 nsresult
01017 nsMessengerWinIntegration::RemoveCurrentFromRegistry()
01018 {
01019   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
01020 
01021   // If Windows XP, open the registry and get rid of old account registry entries
01022   // If there is a email prefix, get it and use it to build the registry key.
01023   // Otherwise, just the email address will be the registry key.
01024   nsAutoString currentUnreadMailCountKey;
01025   if (!mEmailPrefix.IsEmpty()) {
01026     currentUnreadMailCountKey.Assign(mEmailPrefix);
01027     currentUnreadMailCountKey.AppendWithConversion(mEmail);
01028   }
01029   else {
01030     currentUnreadMailCountKey.AssignWithConversion(mEmail);
01031   }
01032 
01033 
01034   WCHAR registryUnreadMailCountKey[_MAX_PATH] = {0};
01035   // Enumerate through registry entries to delete the key matching 
01036   // currentUnreadMailCountKey
01037   int index = 0;
01038   while (SUCCEEDED(mSHEnumerateUnreadMailAccounts(HKEY_CURRENT_USER, 
01039                                                   index, 
01040                                                   registryUnreadMailCountKey, 
01041                                                   sizeof(registryUnreadMailCountKey))))
01042   {
01043     if (wcscmp(registryUnreadMailCountKey, currentUnreadMailCountKey.get())==0) {
01044       nsAutoString deleteKey;
01045       deleteKey.Assign(NS_LITERAL_STRING(UNREADMAILNODEKEY).get());
01046       deleteKey.Append(currentUnreadMailCountKey.get());
01047 
01048       if (!deleteKey.IsEmpty()) {
01049         // delete this key and berak out of the loop
01050         RegDeleteKey(HKEY_CURRENT_USER, 
01051                      NS_ConvertUCS2toUTF8(deleteKey).get());
01052         break;
01053       }
01054       else {
01055         index++;
01056       }
01057     }
01058     else {
01059       index++;
01060     }
01061   }
01062   return NS_OK;
01063 }
01064 
01065 nsresult 
01066 nsMessengerWinIntegration::UpdateRegistryWithCurrent()
01067 {
01068   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
01069 
01070   if (!mInboxURI || !mEmail) 
01071     return NS_OK;
01072 
01073   // only update the registry if the count has changed
01074   // and if the unread count is valid
01075   if ((mCurrentUnreadCount < 0) || (mCurrentUnreadCount == mLastUnreadCountWrittenToRegistry)) {
01076     return NS_OK;
01077   }
01078 
01079   // commandliner has to be built in the form of statement
01080   // which can be open the mailer app to the default user account
01081   // For given profile 'foo', commandliner will be built as 
01082   // ""<absolute path to application>" -p foo -mail" where absolute
01083   // path to application is extracted from mAppName
01084   nsAutoString commandLinerForAppLaunch;
01085   commandLinerForAppLaunch.Assign(NS_LITERAL_STRING(DOUBLE_QUOTE));
01086   commandLinerForAppLaunch.Append(mAppName);
01087   commandLinerForAppLaunch.Append(NS_LITERAL_STRING(DOUBLE_QUOTE));
01088   commandLinerForAppLaunch.Append(NS_LITERAL_STRING(PROFILE_COMMANDLINE_ARG));
01089 #ifdef MOZ_THUNDERBIRD
01090   commandLinerForAppLaunch.Append(NS_LITERAL_STRING(DOUBLE_QUOTE));
01091   commandLinerForAppLaunch.Append(mProfilePath);
01092   commandLinerForAppLaunch.Append(NS_LITERAL_STRING(DOUBLE_QUOTE));
01093 #else
01094   commandLinerForAppLaunch.Append(mProfileName);
01095 #endif
01096   commandLinerForAppLaunch.Append(NS_LITERAL_STRING(MAIL_COMMANDLINE_ARG));
01097 
01098   if (!commandLinerForAppLaunch.IsEmpty())
01099   {
01100     nsAutoString pBuffer;
01101 
01102     if (!mEmailPrefix.IsEmpty()) {
01103       pBuffer.Assign(mEmailPrefix);
01104       pBuffer.AppendWithConversion(mEmail);
01105     }
01106     else {
01107       pBuffer.AssignWithConversion(mEmail);
01108     }
01109 
01110     // Write the info into the registry
01111     HRESULT hr = mSHSetUnreadMailCount(pBuffer.get(), 
01112                                        mCurrentUnreadCount, 
01113                                        commandLinerForAppLaunch.get());
01114   }
01115 
01116   // do this last
01117   mLastUnreadCountWrittenToRegistry = mCurrentUnreadCount;
01118 
01119   return NS_OK;
01120 }
01121 
01122 nsresult 
01123 nsMessengerWinIntegration::SetupInbox()
01124 {
01125   nsresult rv;
01126   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
01127 
01128   // get default account
01129   nsCOMPtr <nsIMsgAccountManager> accountManager = 
01130     do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); 
01131   NS_ENSURE_SUCCESS(rv,rv);
01132 
01133   nsCOMPtr <nsIMsgAccount> account;
01134   rv = accountManager->GetDefaultAccount(getter_AddRefs(account));
01135   if (NS_FAILED(rv)) {
01136     // this can happen if we launch mail on a new profile
01137     // we don't have a default account yet
01138     mDefaultAccountMightHaveAnInbox = PR_FALSE;
01139     return NS_OK;
01140   }
01141 
01142   // get incoming server
01143   nsCOMPtr <nsIMsgIncomingServer> server;
01144   rv = account->GetIncomingServer(getter_AddRefs(server));
01145   NS_ENSURE_SUCCESS(rv,rv);
01146 
01147   nsXPIDLCString type;
01148   rv = server->GetType(getter_Copies(type));
01149   NS_ENSURE_SUCCESS(rv,rv);
01150 
01151   // we only care about imap and pop3
01152   if (!(nsCRT::strcmp(type.get(), "imap")) ||
01153       !(nsCRT::strcmp(type.get(), "pop3"))) {
01154     // imap and pop3 account should have an Inbox
01155     mDefaultAccountMightHaveAnInbox = PR_TRUE;
01156 
01157     // get the redirector type, use it to get the prefix
01158     // todo remove this extra copy
01159     nsXPIDLCString redirectorType;
01160     server->GetRedirectorType(getter_Copies(redirectorType));
01161 
01162     if (redirectorType) {
01163       nsCAutoString providerPrefixPref;
01164       providerPrefixPref.Assign("mail.");
01165       providerPrefixPref.Append(redirectorType);
01166       providerPrefixPref.Append(".unreadMailCountRegistryKeyPrefix");
01167 
01168       // get pref service
01169       nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
01170       NS_ENSURE_SUCCESS(rv,rv);
01171 
01172       nsCOMPtr<nsISupportsString> tmp;
01173       rv = prefBranch->GetComplexValue(providerPrefixPref.get(), NS_GET_IID(nsISupportsString),
01174                                        getter_AddRefs(tmp));
01175 
01176       if (NS_SUCCEEDED(rv))
01177         tmp->GetData(mEmailPrefix);
01178       else
01179         mEmailPrefix.Truncate();
01180     }
01181     else {
01182       mEmailPrefix.Truncate();
01183     }
01184 
01185     // Get user's email address
01186     nsCOMPtr<nsIMsgIdentity> identity;
01187     rv = account->GetDefaultIdentity(getter_AddRefs(identity));
01188     NS_ENSURE_SUCCESS(rv,rv);
01189  
01190     if (!identity)
01191       return NS_ERROR_FAILURE;
01192  
01193     rv = identity->GetEmail(&mEmail);
01194     NS_ENSURE_SUCCESS(rv,rv);
01195     
01196     nsCOMPtr<nsIMsgFolder> rootMsgFolder;
01197     rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
01198     NS_ENSURE_SUCCESS(rv,rv);
01199  
01200     if (!rootMsgFolder)
01201       return NS_ERROR_FAILURE;
01202  
01203     PRUint32 numFolders = 0;
01204     nsCOMPtr <nsIMsgFolder> inboxFolder;
01205     rv = rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, 1, &numFolders, getter_AddRefs(inboxFolder));
01206     NS_ENSURE_SUCCESS(rv,rv);
01207  
01208     if (!inboxFolder)
01209      return NS_ERROR_FAILURE;
01210  
01211     rv = inboxFolder->GetURI(&mInboxURI);
01212     NS_ENSURE_SUCCESS(rv,rv);
01213 
01214     rv = inboxFolder->GetNumUnread(PR_FALSE, &mCurrentUnreadCount);
01215     NS_ENSURE_SUCCESS(rv,rv);
01216   }
01217   else {
01218     // the default account is valid, but it's not something 
01219     // that we expect to have an inbox.  (local folders, news accounts)
01220     // set this flag to avoid calling SetupInbox() every time
01221     // the timer goes off.
01222     mDefaultAccountMightHaveAnInbox = PR_FALSE;
01223   }
01224 
01225   return NS_OK;
01226 }
01227 
01228 nsresult
01229 nsMessengerWinIntegration::UpdateUnreadCount()
01230 {
01231   nsresult rv;
01232   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
01233 
01234   if (mDefaultAccountMightHaveAnInbox && !mInboxURI) {
01235     rv = SetupInbox();
01236     NS_ENSURE_SUCCESS(rv,rv);
01237   }
01238   
01239   rv = UpdateRegistryWithCurrent();
01240   NS_ENSURE_SUCCESS(rv,rv);
01241 
01242   return NS_OK;
01243 }
01244 
01245 nsresult
01246 nsMessengerWinIntegration::SetupUnreadCountUpdateTimer()
01247 {
01248   if (!mStoreUnreadCounts) return NS_OK; // don't do anything here if we aren't storing unread counts...
01249   mUnreadTimerActive = PR_TRUE;
01250   if (mUnreadCountUpdateTimer) {
01251     mUnreadCountUpdateTimer->Cancel();
01252   }
01253   else
01254   {
01255     mUnreadCountUpdateTimer = do_CreateInstance("@mozilla.org/timer;1");
01256   }
01257 
01258   mUnreadCountUpdateTimer->InitWithFuncCallback(OnUnreadCountUpdateTimer,
01259     (void *)this, UNREAD_UPDATE_INTERVAL, nsITimer::TYPE_ONE_SHOT);
01260 
01261   return NS_OK;
01262 }
01263