Bug 430614 [GSoC] Thunderbird integration into Windows Vista/Windows Search indexer. r=beckley,r=jmathies,sr=bienvenu,ui-review=clarkbw
authorSiddharth Agarwal <sid1337@gmail.com>
Mon, 08 Sep 2008 09:12:29 +0100
changeset 279 e7a685e6761a23d407f2dbacc47896777e8e6e9c
parent 278 b3ca3c955a120c439165c160e5da11eacb8688c4
child 280 1c24eba7f7f370355acf7eba2b3e3ae66067ed4c
push idunknown
push userunknown
push dateunknown
reviewersbeckley, jmathies, bienvenu
bugs430614
Bug 430614 [GSoC] Thunderbird integration into Windows Vista/Windows Search indexer. r=beckley,r=jmathies,sr=bienvenu,ui-review=clarkbw
mail/base/content/msgMail3PaneWindow.js
mail/components/Makefile.in
mail/components/build/Makefile.in
mail/components/build/nsModule.cpp
mail/components/search/Makefile.in
mail/components/search/content/searchCommon.js
mail/components/search/content/searchIntegrationDialog.xul
mail/components/search/jar.mn
mail/components/search/nsMailWinSearchHelper.cpp
mail/components/search/nsMailWinSearchHelper.h
mail/components/search/nsSpotlightIntegration.js
mail/components/search/nsWinSearchIntegration.js
mail/components/search/public/Makefile.in
mail/components/search/public/nsIMailWinSearchHelper.idl
mail/components/search/wsenable/Makefile.in
mail/components/search/wsenable/WSEnable.cpp
mail/components/search/wsenable/WSEnable.exe.manifest
mail/components/search/wsenable/WSEnable.rc
mail/components/search/wsenable/module.ver
mail/installer/windows/nsis/shared.nsh
mail/installer/windows/nsis/uninstaller.nsi
mail/installer/windows/packages-static
mail/locales/en-US/chrome/messenger/search/searchIntegrationDialogWin.dtd
mail/locales/jar.mn
--- a/mail/base/content/msgMail3PaneWindow.js
+++ b/mail/base/content/msgMail3PaneWindow.js
@@ -797,39 +797,42 @@ function LoadPostAccountWizard()
       gStartFolderUri = null;
     }
     else
       gStartFolderUri = (window.arguments.length > 0) ? window.arguments[0] : null;
     gStartMsgKey = (window.arguments.length > 1) ? window.arguments[1]: nsMsgKey_None;
     gSearchEmailAddress = (window.arguments.length > 2) ? window.arguments[2] : null;
   }
 
+  function showDefaultClientDialog() {
 #ifdef HAVE_SHELL_SERVICE
-  var nsIShellService = Components.interfaces.nsIShellService;
-  var shellService;
-  var defaultAccount;
-  try {
-    shellService = Components.classes["@mozilla.org/mail/shell-service;1"].getService(nsIShellService);
-    defaultAccount = accountManager.defaultAccount;
-  } catch (ex) {}
+    var nsIShellService = Components.interfaces.nsIShellService;
+    var shellService;
+    var defaultAccount;
+    try {
+      shellService = Components.classes["@mozilla.org/mail/shell-service;1"].getService(nsIShellService);
+      defaultAccount = accountManager.defaultAccount;
+    } catch (ex) {}
 
-  function showDefaultClientDialog() {
-    window.openDialog("chrome://messenger/content/defaultClientDialog.xul",
-                      "DefaultClient", "modal,centerscreen,chrome,resizable=no");
+    // Show the default client dialog only if we have at least one account,
+    // we should check for the default client, and we aren't already the default
+    // for mail.
+    // Needs to be shown outside the he normal load sequence so it doesn't appear
+    // before any other displays, in the wrong place of the screen.
+    if (shellService && defaultAccount && shellService.shouldCheckDefaultClient
+        && !shellService.isDefaultClient(true, nsIShellService.MAIL))
+      window.openDialog("chrome://messenger/content/defaultClientDialog.xul",
+                        "DefaultClient", "modal,centerscreen,chrome,resizable=no");
+#endif
+
+    // All core modal dialogs are done, the user can now interact with the 3-pane window
+    NotifyObservers(window, "mail-startup-done", null);
   }
 
-  // Show the default client dialog only if we have at least one account,
-  // we should check for the default client, and we aren't already the default
-  // for mail.
-  // Needs to be shown outside the he normal load sequence so it doesn't appear
-  // before any other displays, in the wrong place of the screen.
-  if (shellService && defaultAccount && shellService.shouldCheckDefaultClient
-      && !shellService.isDefaultClient(true, nsIShellService.MAIL))
-    setTimeout(showDefaultClientDialog, 0);
-#endif
+  setTimeout(showDefaultClientDialog, 0);
 
   // FIX ME - later we will be able to use onload from the overlay
   OnLoadMsgHeaderPane();
 
   gHaveLoadedMessage = false;
 
   gNotifyDefaultInboxLoadedOnStartup = true;
 
--- a/mail/components/Makefile.in
+++ b/mail/components/Makefile.in
@@ -48,18 +48,23 @@ ifneq (,$(filter windows gtk2 mac cocoa,
 DIRS += shell
 endif
 
 ifdef MOZ_SAFE_BROWSING
 DIRS += phishing 
 endif
 
 # Mac and Windows have search integration components
-ifneq (,$(filter windows cocoa mac, $(MOZ_WIDGET_TOOLKIT)))
+ifneq (,$(filter cocoa mac, $(MOZ_WIDGET_TOOLKIT)))
 DIRS += search
 endif
+ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS
+DIRS += search
+endif
+endif
 
 DIRS += build
 
 EXTRA_PP_COMPONENTS = nsMailDefaultHandler.js
 
 include $(topsrcdir)/config/rules.mk
 
--- a/mail/components/build/Makefile.in
+++ b/mail/components/build/Makefile.in
@@ -64,36 +64,58 @@ REQUIRES = \
 	libreg \
 	intl \
 	pref \
 	msgbase \
 	import \
 	shellservice \
 	$(NULL)
 
+ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS
+REQUIRES += \
+	mailwinsearch \
+	$(NULL)
+endif
+endif
+
 CPPSRCS = nsModule.cpp \
           $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,ole32 shell32)
 endif
 
 LOCAL_INCLUDES = \
 	-I$(srcdir)/../migration/src \
 	-I$(srcdir)/../shell \
 	$(NULL)
 
+ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS
+LOCAL_INCLUDES += \
+	-I$(srcdir)/../search \
+	$(NULL)
+endif
+endif
+
 SHARED_LIBRARY_LIBS = \
 	../migration/src/$(LIB_PREFIX)profilemigration_s.$(LIB_SUFFIX) \
 	$(NULL)
 
 ifneq (,$(filter windows mac cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
 SHARED_LIBRARY_LIBS += ../shell/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
 endif
 
+ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS
+SHARED_LIBRARY_LIBS += ../search/$(LIB_PREFIX)winsearch_s.$(LIB_SUFFIX)
+endif
+endif
+
 ifdef MOZILLA_INTERNAL_API
 EXTRA_DSO_LDOPTS += \
 	$(LIBXUL_DIST)/../modules/libreg/src/$(LIB_PREFIX)mozreg_s.$(LIB_SUFFIX) \
 	$(MOZ_COMPONENT_LIBS) \
 	$(MOZ_UNICHARUTIL_LIBS) \
 	$(NULL)
 else
 EXTRA_DSO_LDOPTS += \
--- a/mail/components/build/nsModule.cpp
+++ b/mail/components/build/nsModule.cpp
@@ -73,16 +73,21 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEudoraP
 #include "nsMailGNOMEIntegration.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMailGNOMEIntegration, Init)
 #endif
 #ifdef XP_MACOSX
 #include "nsMailMacIntegration.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMailMacIntegration)
 #endif
 
+#if defined(XP_WIN32) && !defined(MOZ_DISABLE_VISTA_SDK_REQUIREMENTS)
+#include "nsMailWinSearchHelper.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMailWinSearchHelper, Init)
+#endif
+
 static const nsModuleComponentInfo components[] = {
   { "Profile Importer",
     NS_THUNDERBIRD_PROFILEIMPORT_CID,
     NS_PROFILEMIGRATOR_CONTRACTID,
     nsProfileMigratorConstructor },
   { "Seamonkey Profile Migrator",
     NS_SEAMONKEYPROFILEMIGRATOR_CID,
     NS_MAILPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey",
@@ -122,11 +127,17 @@ static const nsModuleComponentInfo compo
     nsMailGNOMEIntegrationConstructor },
 #endif
 #ifdef XP_MACOSX
   { "Mail Mac Integration",
     NS_MAILMACINTEGRATION_CID,
     "@mozilla.org/mail/shell-service;1",
     nsMailMacIntegrationConstructor },
 #endif
+#if defined(XP_WIN32) && !defined(MOZ_DISABLE_VISTA_SDK_REQUIREMENTS)
+  { "Mail Windows Search Integration Helper",
+    NS_MAILWINSEARCHHELPER_CID,
+    "@mozilla.org/mail/windows-search-helper;1",
+    nsMailWinSearchHelperConstructor },
+#endif
 };
 
 NS_IMPL_NSGETMODULE(nsMailCompsModule, components)
--- a/mail/components/search/Makefile.in
+++ b/mail/components/search/Makefile.in
@@ -41,25 +41,53 @@ VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 
 ifneq (,$(filter cocoa mac, $(MOZ_WIDGET_TOOLKIT)))
 DIRS += mdimporter
 endif
 
+ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+DIRS += wsenable
+endif
+
 #currently, we only build this dir on the mac, but if it gets built on other platforms,
 #make sure we still only build spotlight integration on the mac.
 ifneq (,$(filter cocoa mac, $(MOZ_WIDGET_TOOLKIT)))
 EXTRA_PP_COMPONENTS = \
 	nsSpotlightIntegration.js \
 	$(NULL)
 endif         
 
 # If on Windows, build Windows Search integration
 ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+MODULE = mailwinsearch
+LIBRARY_NAME = winsearch_s
+MODULE_NAME = nsMailWinSearchHelperModule
+ifdef BUILD_STATIC_LIBS
+MOZILLA_INTERNAL_API = 1
+else
+ifneq ($(MOZ_WIDGET_TOOLKIT), gtk2)
+MOZILLA_INTERNAL_API = 1
+endif
+endif
+
+REQUIRES = \
+  xpcom \
+  string \
+  $(NULL)
+
+CPPSRCS = \
+  nsMailWinSearchHelper.cpp \
+  $(NULL)
+
+DIRS += public
+
 # Windows Search component
 EXTRA_PP_COMPONENTS = \
   nsWinSearchIntegration.js \
   $(NULL)
+
+FORCE_STATIC_LIB = 1
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/mail/components/search/content/searchCommon.js
+++ b/mail/components/search/content/searchCommon.js
@@ -55,32 +55,46 @@ const Ci = Components.interfaces;
 var gCurrentFolderToIndex;
 var gLastFolderIndexedUri = ""; // this is stored in a pref
 var gHeaderEnumerator;
 var gMsgHdrsToIndex;
 var gMessenger;
 var gAlarm;
 var gBackgroundIndexingDone;
 var gPrefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch(null);
+var gEnabled;
 
 /*
  * Init function -- this should be called from the component's init function
  */
-function InitSupportIntegration()
+function InitSupportIntegration(enabled)
 {
+  SIDump("Search integration running in " + (enabled ? "active" : "backoff") + " mode\n");
+  gEnabled = enabled;
+
   gMessenger = Cc["@mozilla.org/messenger;1"].createInstance().QueryInterface(Ci.nsIMessenger);
 
   var notificationService = Cc["@mozilla.org/messenger/msgnotificationservice;1"]
     .getService(Ci.nsIMsgFolderNotificationService);
-  notificationService.addListener(gFolderListener, notificationService.all);
-  var ObserverService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-  ObserverService.addObserver(MsgMsgDisplayedObserver, "MsgMsgDisplayed", false);
-  gMsgHdrsToIndex = new Array();
 
-  restartTimer(60);
+  // We want to observe moves, deletes and renames in case we're disabled
+  // If we don't, we'll have no idea the support files exist later
+  if (enabled)
+  {
+    notificationService.addListener(gFolderListener, notificationService.all);
+    var ObserverService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+    ObserverService.addObserver(MsgMsgDisplayedObserver, "MsgMsgDisplayed", false);
+    gMsgHdrsToIndex = new Array();
+
+    restartTimer(60);
+  }
+  else
+    notificationService.addListener(gFolderListener, notificationService.msgsMoveCopyCompleted |
+                                    notificationService.msgsDeleted |
+                                    notificationService.allFolderNotifications);
 }
 
 /*
  * These functions are to index already existing messages
  */
 function FindNextFolderToIndex()
 {
   accountManager = Cc["@mozilla.org/messenger/account-manager;1"].getService(Ci.nsIMsgAccountManager);
@@ -224,17 +238,18 @@ var gFolderListener = {
     if (!file.exists())
       QueueMessageToGetIndexed(aMsg);
   },
 
   msgsDeleted: function(aMsgs)
   {
     SIDump("in msgsDeleted\n");
     // mail getting deleted, we're not idle, so restart timer.
-    restartTimer(60);
+    if (gEnabled)
+      restartTimer(60);
     var count = aMsgs.length;
     for (var i = 0; i < count; i++)
     {
       var file = GetSupportFileForMsgHdr(aMsgs.queryElementAt(i, Ci.nsIMsgDBHdr));
       if (file.exists())
         file.remove(false);
     }
   },
@@ -257,49 +272,53 @@ var gFolderListener = {
           {
             // create the directory, if it doesn't exist
             destFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0644);
           }
           catch(ex) {SIDump(ex);}
         }
         SIDump ("dst file path = " + destFile.path + "\n");
         SIDump ("src file path = " + srcFile.path + "\n");
+        // We're not going to copy in case we're not in active mode
         if (destFile.exists())
           if (aMove)
             srcFile.moveTo(destFile, "");
-          else
+          else if (gEnabled)
             srcFile.copyTo(destFile, "");
       }
     }
-    restartTimer(30);
+    if (gEnabled)
+      restartTimer(30);
     SIDump("moveCopyCompleted move = " + aMove + "\n");
   },
 
   folderDeleted: function(aFolder)
   {
     SIDump("in folderDeleted, folder name = " + aFolder.prettiestName + "\n");
     var srcFile = aFolder.filePath;
     srcFile.leafName = srcFile.leafName + ".mozmsgs";
-    srcFile.remove(true);
+    if (srcFile.exists())
+      srcFile.remove(true);
   },
 
   folderMoveCopyCompleted: function(aMove, aSrcFolder, aDestFolder)
   {
     SIDump("in folderMoveCopyCompleted, aMove = " + aMove + "\n");
     var srcFile = aSrcFolder.filePath;
     var destFile = aDestFolder.filePath;
     srcFile.leafName = srcFile.leafName + ".mozmsgs";
     destFile.leafName += ".sbd";
     SIDump("src file path = " + srcFile.path + "\n");
     SIDump("dst file path = " + destFile.path + "\n");
     if (srcFile.exists())
     {
+      // We're not going to copy if we aren't in active mode
       if (aMove)
         srcFile.moveTo(destFile, "");
-      else
+      else if (gEnabled)
         srcFile.copyTo(destFile, "");
     }
   },
 
   folderRenamed: function(aOrigFolder, aNewFolder)
   {
     SIDump("in folderRenamed, aOrigFolder = "+aOrigFolder.prettiestName+", aNewFolder = "+aNewFolder.prettiestName+"\n");
     var srcFile = aOrigFolder.filePath;
new file mode 100644
--- /dev/null
+++ b/mail/components/search/content/searchIntegrationDialog.xul
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+# -*- Mode: xml; indent-tabs-mode: nil; -*-
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Thunderbird Default Client Dialog
+#
+# The Initial Developer of the Original Code is
+# Scott MacGregor.
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Scott MacGregor <mscott@mozilla.org
+#   Siddharth Agarwal <sid1337@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+<?xml-stylesheet href="chrome://global/skin/"?>
+
+<!DOCTYPE window [
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+  %brandDTD;
+#ifdef XP_WIN
+  <!ENTITY % searchIntegrationDTD SYSTEM "chrome://messenger/locale/search/searchIntegrationDialogWin.dtd" >
+  %searchIntegrationDTD;
+#endif
+]>
+
+
+<dialog xmlns:html="http://www.w3.org/1999/xhtml"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        id="searchIntegrationDialog"
+        buttons="accept,cancel"
+        ondialogaccept="window.arguments[0].callback(true); return true"
+        ondialogcancel="window.arguments[0].callback(false); return true"
+        title="&searchIntegration.title;"
+        buttonlabelaccept="&searchIntegration.accept;"
+        buttonlabelcancel="&searchIntegration.cancel;">
+
+  <description>
+    &searchIntegration.description;
+  </description>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/mail/components/search/jar.mn
@@ -0,0 +1,2 @@
+messenger.jar:
+*   content/messenger/search/searchIntegrationDialog.xul        (content/searchIntegrationDialog.xul)
new file mode 100644
--- /dev/null
+++ b/mail/components/search/nsMailWinSearchHelper.cpp
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Windows Search integration.
+ *
+ * The Initial Developer of the Original Code is
+ *  Siddharth Agarwal <sid1337@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsMailWinSearchHelper.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsAutoPtr.h"
+#include "nsMemory.h"
+#include "nsStringGlue.h"
+#include "nsISimpleEnumerator.h"
+#include <SearchAPI.h>
+#include <winsvc.h>
+#include <ShellAPI.h>
+
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+#include <shlobj.h>
+
+static const CLSID CLSID_CSearchManager = {0x7d096c5f, 0xac08, 0x4f1f, {0xbe, 0xb7, 0x5c, 0x22, 0xc5, 0x17, 0xce, 0x39}};
+static const IID IID_ISearchManager = {0xab310581, 0xac80, 0x11d1, {0x8d, 0xf3, 0x00, 0xc0, 0x4f, 0xb6, 0xef, 0x69}};
+
+static const char* const sFoldersToIndex[] = {"Mail", "ImapMail", "News"};
+
+// APP_REG_NAME_MAIL should be kept in synch with AppRegNameMail
+// in the installer file: defines.nsi.in
+#define APP_REG_NAME_MAIL L"Thunderbird"
+
+nsMailWinSearchHelper::nsMailWinSearchHelper()
+{
+}
+
+nsresult nsMailWinSearchHelper::Init()
+{
+  CoInitialize(NULL);
+  return NS_GetSpecialDirectory("ProfD", getter_AddRefs(mProfD));
+}
+
+nsMailWinSearchHelper::~nsMailWinSearchHelper()
+{
+  CoUninitialize();
+}
+
+NS_IMPL_ISUPPORTS1(nsMailWinSearchHelper, nsIMailWinSearchHelper)
+
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetFoldersInCrawlScope(PRBool* aResult)
+{
+  *aResult = PR_FALSE;
+  NS_ENSURE_ARG_POINTER(mProfD);
+
+  // If the service isn't present or running, we shouldn't proceed.
+  PRBool serviceRunning;
+  nsresult rv = GetServiceRunning(&serviceRunning);
+  if (!serviceRunning || NS_FAILED(rv))
+    return rv;
+
+  // We need to do this every time so that we have the latest data
+  nsRefPtr<ISearchManager> searchManager;
+  HRESULT hr = CoCreateInstance(CLSID_CSearchManager, NULL, CLSCTX_ALL, IID_ISearchManager, getter_AddRefs(searchManager));
+  if (FAILED(hr))
+    return NS_ERROR_FAILURE;
+
+  nsRefPtr<ISearchCatalogManager> catalogManager;
+  hr = searchManager->GetCatalog(L"SystemIndex", getter_AddRefs(catalogManager));
+  if (FAILED(hr))
+    return NS_ERROR_FAILURE;
+
+  nsRefPtr<ISearchCrawlScopeManager> crawlScopeManager;
+  hr = catalogManager->GetCrawlScopeManager(getter_AddRefs(crawlScopeManager));
+  if (FAILED(hr))
+    return NS_ERROR_FAILURE;
+
+  // We need to create appropriate URLs to check with the crawl scope manager.
+  for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sFoldersToIndex); i++)
+  {
+    nsCOMPtr<nsIFile> subdir;
+    rv = mProfD->Clone(getter_AddRefs(subdir));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsDependentCString relativeStr(sFoldersToIndex[i]);
+    rv = subdir->AppendNative(relativeStr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsString subdirPath;
+    rv = subdir->GetPath(subdirPath);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Form a URL as required by the crawl scope manager
+    nsString subdirURL(NS_LITERAL_STRING("file:///"));
+    subdirURL.Append(subdirPath);
+    subdirURL.Append(NS_LITERAL_STRING("\\"));
+
+    BOOL included;
+    if (FAILED(crawlScopeManager->IncludedInCrawlScope(subdirURL.get(), &included)))
+      return NS_ERROR_FAILURE;
+
+    // If even one of the folders isn't there, we return false
+    if (!included)
+      return NS_OK;
+  }
+  *aResult = PR_TRUE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetServiceRunning(PRBool* aResult)
+{
+  *aResult = PR_FALSE;
+  SC_HANDLE hSCManager = OpenSCManager(nsnull, SERVICES_ACTIVE_DATABASE, SERVICE_QUERY_STATUS);
+  if (!hSCManager)
+    return NS_ERROR_FAILURE;
+
+  SC_HANDLE hService = OpenService(hSCManager, "wsearch", SERVICE_QUERY_STATUS);
+  CloseServiceHandle(hSCManager);
+  if (!hService)
+    // The service isn't present. Never mind.
+    return NS_ERROR_NOT_AVAILABLE;
+
+  SERVICE_STATUS status;
+  if (!QueryServiceStatus(hService, &status))
+  {
+    CloseServiceHandle(hService);
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = (status.dwCurrentState == SERVICE_RUNNING);
+  CloseServiceHandle(hService);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::SetFANCIBit(nsIFile* aFile, PRBool aBit, PRBool aRecurse)
+{
+  NS_ENSURE_ARG_POINTER(aFile);
+
+  PRBool exists;
+  nsresult rv = aFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  nsString filePath;
+  rv = aFile->GetPath(filePath);
+  NS_ENSURE_SUCCESS(rv, rv);
+  LPCWSTR pathStr = filePath.get();
+
+  // We should set the file attribute only if it isn't already set.
+  DWORD dwAttrs = GetFileAttributesW(pathStr);
+  if (dwAttrs == INVALID_FILE_ATTRIBUTES)
+    return NS_ERROR_FAILURE;
+
+  if (aBit)
+  {
+    if (!(dwAttrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
+      SetFileAttributesW(pathStr, dwAttrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+  }
+  else
+  {
+    if (dwAttrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+      SetFileAttributesW(pathStr, dwAttrs & ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+  }
+
+  // We should only try to recurse if it's a directory
+  PRBool isDirectory;
+  rv = aFile->IsDirectory(&isDirectory);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (aRecurse && isDirectory)
+  {
+    nsCOMPtr<nsISimpleEnumerator> children;
+    rv = aFile->GetDirectoryEntries(getter_AddRefs(children));
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    PRBool hasMore;
+    while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(children->HasMoreElements(&hasMore)) && hasMore)
+    {
+      nsCOMPtr<nsIFile> childFile;
+      rv = children->GetNext(getter_AddRefs(childFile));
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = SetFANCIBit(childFile, aBit, aRecurse);
+    }
+  }
+  return rv;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetIsFileAssociationSet(PRBool *aResult)
+{
+  NS_ENSURE_ARG_POINTER(aResult);
+  *aResult = PR_FALSE;
+
+  // We'll use the Vista method here
+  nsRefPtr<IApplicationAssociationRegistration> pAAR;
+  HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
+                                NULL,
+                                CLSCTX_INPROC,
+                                IID_IApplicationAssociationRegistration,
+                                getter_AddRefs(pAAR));
+
+  if (SUCCEEDED(hr))
+    pAAR->QueryAppIsDefault(L".wdseml", AT_FILEEXTENSION, AL_EFFECTIVE, APP_REG_NAME_MAIL, aResult);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::SetFileAssociation()
+{
+  nsRefPtr<IApplicationAssociationRegistration> pAAR;
+  HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
+                                NULL,
+                                CLSCTX_INPROC,
+                                IID_IApplicationAssociationRegistration,
+                                getter_AddRefs(pAAR));
+  if (SUCCEEDED(hr))
+    hr = pAAR->SetAppAsDefault(APP_REG_NAME_MAIL, L".wdseml", AT_FILEEXTENSION);
+
+  return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::RunSetup(PRBool aEnable)
+{
+  nsresult rv;
+  if (!mCurProcD)
+  {
+    rv = NS_GetSpecialDirectory("CurProcD", getter_AddRefs(mCurProcD));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mCurProcD->Append(NS_LITERAL_STRING("WSEnable.exe"));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  nsAutoString filePath;
+  rv = mCurProcD->GetPath(filePath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // The parameters are of the format "1 <path>" for enabling and "0 <path>" for disabling
+  nsAutoString params(aEnable ? NS_LITERAL_STRING("1 \"") : NS_LITERAL_STRING("0 \""));
+  nsAutoString profDPath;
+  rv = mProfD->GetPath(profDPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+  params.Append(profDPath);
+  params.Append(NS_LITERAL_STRING("\""));
+
+  // We need an hWnd to cause UAC to pop up immediately
+  // If GetForegroundWindow returns NULL, then the UAC prompt will still appear,
+  // but minimized.
+  HWND hWnd = GetForegroundWindow();
+
+  SHELLEXECUTEINFOW executeInfo = {0};
+
+  executeInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+  executeInfo.hwnd = hWnd;
+  executeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+  executeInfo.lpDirectory = NULL;
+  executeInfo.lpFile = filePath.get();
+  executeInfo.lpParameters = params.get();
+  executeInfo.nShow = SW_SHOWNORMAL;
+
+  DWORD dwRet;
+
+  if (ShellExecuteExW(&executeInfo))
+  {
+    // We want to block until the program exits
+    DWORD dwSignaled = WaitForSingleObject(executeInfo.hProcess, INFINITE);
+    if (dwSignaled == WAIT_OBJECT_0)
+      if (!GetExitCodeProcess(executeInfo.hProcess, &dwRet))
+        dwRet = GetLastError();
+  }
+  else
+    return NS_ERROR_ABORT;
+
+  return SUCCEEDED(HRESULT_FROM_WIN32(dwRet)) ? NS_OK : NS_ERROR_FAILURE;
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/search/nsMailWinSearchHelper.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Windows Search integration.
+ *
+ * The Initial Developer of the Original Code is
+ *  Siddharth Agarwal <sid1337@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsMailWinSearchHelper_h_
+#define nsMailWinSearchHelper_h_
+
+#include "nsIMailWinSearchHelper.h"
+#include "nsIFile.h"
+
+#define NS_MAILWINSEARCHHELPER_CID \
+{0x5dd31c99, 0x8c7, 0x4a3b, {0xae, 0xb3, 0xd2, 0xe6, 0x6, 0x65, 0xa3, 0x1a}}
+
+class nsMailWinSearchHelper : public nsIMailWinSearchHelper
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMAILWINSEARCHHELPER
+
+  NS_HIDDEN_(nsresult) Init();
+  nsMailWinSearchHelper();
+
+private:
+  ~nsMailWinSearchHelper();
+  nsCOMPtr<nsIFile> mProfD;
+  nsCOMPtr<nsIFile> mCurProcD;
+};
+
+#endif
--- a/mail/components/search/nsSpotlightIntegration.js
+++ b/mail/components/search/nsSpotlightIntegration.js
@@ -54,21 +54,19 @@ Components.utils.import("resource://gre/
 function InitSpotlightIntegration()
 {
   var enabled;
   try {
     enabled = gPrefBranch.getBoolPref(gPrefBase + ".enable");
     gLastFolderIndexedUri = gPrefBranch.getCharPref(gPrefBase + ".lastFolderIndexedUri");
   } catch (ex) {}
 
-  if (!enabled)
-    return;
-
-  SIDump("initializing spotlight integration\n");
-  InitSupportIntegration();
+  if (enabled)
+    SIDump("initializing spotlight integration\n");
+  InitSupportIntegration(enabled);
 }
 
 function xmlEscapeString(s)
 {
  s = s.replace(/&/g, "&amp;");
  s = s.replace(/>/g, "&gt;");
  s = s.replace(/</g, "&lt;");
  return s;
--- a/mail/components/search/nsWinSearchIntegration.js
+++ b/mail/components/search/nsWinSearchIntegration.js
@@ -46,31 +46,155 @@ const CRLF="\r\n";
 const gHdrIndexedProperty = "wds_indexed";
 
 // The file extension that is used for support files of this component
 const gFileExt = ".wdseml";
 
 // The pref base
 const gPrefBase = "mail.winsearch";
 
+var gWinSearchHelper;
+
+var gFoldersInCrawlScope;
+
+var gRegKeysPresent;
+
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function InitWinSearchIntegration()
 {
+  // We're currently only enabled on Vista and above
+  var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
+  var windowsVersion = sysInfo.getProperty("version");
+  if (parseFloat(windowsVersion) < 6)
+  {
+    SIDump("Windows version " + windowsVersion + " < 6.0\n");
+    return;
+  }
+
+  // enabled === undefined means that the first run hasn't occurred yet (pref isn't present).
+  // false or true means that the first run has occurred, and the user has selected
+  // the corresponding decision.
   var enabled;
   try {
     enabled = gPrefBranch.getBoolPref(gPrefBase + ".enable");
     gLastFolderIndexedUri = gPrefBranch.getCharPref(gPrefBase + ".lastFolderIndexedUri");
   } catch (ex) {}
 
-  if (!enabled)
+  gWinSearchHelper = Cc["@mozilla.org/mail/windows-search-helper;1"].getService(Ci.nsIMailWinSearchHelper);
+  var serviceRunning = false;
+  try
+  {
+    serviceRunning = gWinSearchHelper.serviceRunning;
+  }
+  catch (e) {}
+  // If the service isn't running, then we should stay in backoff mode
+  if (!serviceRunning)
+  {
+    SIDump("Windows Search service not running\n");
+    InitSupportIntegration(false);
     return;
+  }
+
+  gFoldersInCrawlScope = gWinSearchHelper.foldersInCrawlScope;
+  gRegKeysPresent = CheckRegistryKeys();
+
+  if (enabled === undefined)
+    // First run has to be handled after the main mail window is open
+    return true;
+
+  if (enabled)
+    SIDump("Initializing Windows Search integration\n");
+  InitSupportIntegration(enabled);
+}
+
+// Handles first run, once the main mail window has popped up.
+function WinSearchFirstRun(window)
+{
+  // If any of the two are not present, we need to elevate.
+  var needsElevation = !gFoldersInCrawlScope || !gRegKeysPresent;
+  var params = {in: {showUAC: needsElevation}};
+  var scope = this;
+
+  params.callback = function(enable)
+  {
+    CheckRegistryKeys();
+    if (enable && needsElevation)
+    {
+      try { scope.gWinSearchHelper.runSetup(true); }
+      catch (e) { enable = false; }
+    }
+    if (enable)
+    {
+      if (!scope.gWinSearchHelper.isFileAssociationSet)
+        scope.gWinSearchHelper.setFileAssociation();
+    }
+    scope.gPrefBranch.setBoolPref(gPrefBase + ".enable", enable);
+    scope.InitSupportIntegration(enable);
+  }
+
+  window.openDialog("chrome://messenger/content/search/searchIntegrationDialog.xul", "",
+                    "chrome, dialog, resizable=no, centerscreen", params).focus();
+}
 
-  SIDump("Initializing Windows Search integration\n");
-  InitSupportIntegration();
+const gRegKeys =
+[
+  // This is the property handler
+  {
+    root: Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
+    key: "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.wdseml",
+    name: "",
+    value: "{5FA29220-36A1-40f9-89C6-F4B384B7642E}"
+  },
+  // These two are the association with the MIME IFilter
+  {
+    root: Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT,
+    key: ".wdseml",
+    name: "Content Type",
+    value: "message/rfc822"
+  },
+  {
+    root: Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT,
+    key: ".wdseml\\PersistentHandler",
+    name: "",
+    value: "{5645c8c4-e277-11cf-8fda-00aa00a14f93}"
+  },
+  // This is the association with the Windows mail preview handler
+  {
+    root: Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT,
+    key: ".wdseml\\shellex\\{8895B1C6-B41F-4C1C-A562-0D564250836F}",
+    name: "",
+    value: "{b9815375-5d7f-4ce2-9245-c9d4da436930}"
+  },
+  // This is the association made to display results under email
+  {
+    root: Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
+    key: "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\KindMap",
+    name: ".wdseml",
+    value: "email;communication"
+  }
+];
+
+// Check whether the required registry keys exist
+function CheckRegistryKeys()
+{
+  for (var i = 0; i < gRegKeys.length; i++)
+  {
+    var regKey = Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey);
+    try {
+      regKey.open(gRegKeys[i].root, gRegKeys[i].key, regKey.ACCESS_READ);
+    }
+    catch (e) { return false; }
+    var valuePresent = regKey.hasValue(gRegKeys[i].name) &&
+                        (regKey.readStringValue(gRegKeys[i].name) == gRegKeys[i].value);
+    regKey.close();
+    if (!valuePresent)
+      return false;
+  }
+  return true;
 }
 
 // The stream listener to read messages
 var gStreamListener = {
 _buffer: "",
 outputFile: null,
 outputStream: null,
 unicodeConverter: null,
@@ -202,26 +326,36 @@ WinSearchIntegration.prototype = {
     category: "app-startup",
     service: true
   }],
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupports]),
 
   observe : function(aSubject, aTopic, aData)
   {
+    var obsSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
     switch(aTopic)
     {
     case "app-startup":
-      var obsSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
       obsSvc.addObserver(this, "profile-after-change", false);
-    break;
+      break;
     case "profile-after-change":
-      try { InitWinSearchIntegration(); }
+      try
+      {
+        if (InitWinSearchIntegration())
+          obsSvc.addObserver(this, "mail-startup-done", false);
+      }
       catch(err) { SIDump("Could not initialize winsearch component"); }
-    break;
+      break;
+    case "mail-startup-done":
+      aSubject.QueryInterface(Ci.nsIDOMWindowInternal);
+      obsSvc.removeObserver(this, "mail-startup-done");
+      try { WinSearchFirstRun(aSubject); }
+      catch(err) { SIDump("First run unsuccessful\n"); }
+      break;
     default:
       throw Components.Exception("Unknown topic: " + aTopic);
     }
   }
 };
 var components = [WinSearchIntegration];
 function NSGetModule(aCompMgr, aFileSpec)
 {
new file mode 100644
--- /dev/null
+++ b/mail/components/search/public/Makefile.in
@@ -0,0 +1,49 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Windows Search integration.
+#
+# The Initial Developer of the Original Code is
+#  Siddharth Agarwal <sid1337@gmail.com>.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH     = ../../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = mailwinsearch
+XPIDL_MODULE = mailwinsearch
+
+XPIDLSRCS = nsIMailWinSearchHelper.idl
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/mail/components/search/public/nsIMailWinSearchHelper.idl
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Windows Search integration.
+ *
+ * The Initial Developer of the Original Code is
+ *  Siddharth Agarwal <sid1337@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#include "nsISupports.idl"
+
+interface nsIFile;
+
+[scriptable, uuid(a65307b3-64f8-49fc-96a7-2cfc7d1f18ee)]
+interface nsIMailWinSearchHelper : nsISupports
+{
+  /**
+   * Whether the Windows Search service is installed and running.
+   *
+   * @exception NS_ERROR_NOT_AVAILABLE if the Windows Search service is
+   * not installed
+   */
+  readonly attribute boolean serviceRunning;
+
+  /**
+   * Whether the Mail, ImapMail, and News folders are in the crawl scope.
+   *
+   * @exception NS_ERROR_NOT_AVAILABLE if the Windows Search service is not
+   * installed or running
+   */
+  readonly attribute boolean foldersInCrawlScope;
+
+  /**
+   * Sets the File Attribute Not Content Indexed bit. For proper operation
+   * of the indexer, this bit must be set to 0/false.
+   *
+   * @param aFile the file or directory for which this bit is supposed to be set
+   * @param aBit false if the content is to be indexed, true if not
+   * @param aRecurse whether this bit is to be set recursively for all subdirectories
+   * and files inside a directory
+   */
+  void setFANCIBit(in nsIFile aFile, in boolean aBit, in boolean aRecurse);
+
+  /**
+   * Returns whether the .wdseml file association has been set to Thunderbird or not.
+   */
+  readonly attribute boolean isFileAssociationSet;
+
+  /**
+   * Sets the .wdseml file association.
+   */
+  void setFileAssociation();
+
+  /**
+   * Runs the setup application using ShellExecute, passing the profile directory as
+   * a parameter.
+   *
+   * @param aEnable true to enable, false to disable
+   */
+  void runSetup(in boolean aEnable);
+};
new file mode 100644
--- /dev/null
+++ b/mail/components/search/wsenable/Makefile.in
@@ -0,0 +1,52 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Windows Search integration.
+#
+# The Initial Developer of the Original Code is
+#  Siddharth Agarwal <sid1337@gmail.com>.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH     = ../../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+CPPSRCS = \
+  WSEnable.cpp \
+  $(NULL)
+
+PROGRAM = WSEnable$(BIN_SUFFIX)
+RCINCLUDE = WSEnable.rc
+OS_LIBS += ole32.lib shell32.lib
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/mail/components/search/wsenable/WSEnable.cpp
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Windows Search integration.
+ *
+ * The Initial Developer of the Original Code is
+ *  Siddharth Agarwal <sid1337@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <SearchAPI.h>
+#include <shellapi.h>
+#include <objbase.h>
+#include <string>
+
+static const CLSID CLSID_CSearchManager = {0x7d096c5f, 0xac08, 0x4f1f, {0xbe, 0xb7, 0x5c, 0x22, 0xc5, 0x17, 0xce, 0x39}};
+static const IID IID_ISearchManager = {0xab310581, 0xac80, 0x11d1, {0x8d, 0xf3, 0x00, 0xc0, 0x4f, 0xb6, 0xef, 0x69}};
+
+static const WCHAR* const sFoldersToIndex[] = {L"\\Mail\\", L"\\ImapMail\\", L"\\News\\"};
+
+struct RegKey
+{
+  HKEY mRoot;
+  LPWSTR mSubKey;
+  LPWSTR mName;
+  LPWSTR mValue;
+
+  RegKey(HKEY aRoot, LPWSTR aSubKey, LPWSTR aName, LPWSTR aValue)
+    : mRoot(aRoot), mSubKey(aSubKey), mName(aName), mValue(aValue) {}
+};
+
+static const RegKey* const sRegKeys[] =
+{
+  new RegKey(HKEY_LOCAL_MACHINE,
+             L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\.wdseml",
+             L"",
+             L"{5FA29220-36A1-40f9-89C6-F4B384B7642E}"),
+  new RegKey(HKEY_CLASSES_ROOT,
+             L".wdseml",
+             L"Content Type",
+             L"message/rfc822"),
+  new RegKey(HKEY_CLASSES_ROOT,
+             L".wdseml\\PersistentHandler",
+             L"",
+             L"{5645c8c4-e277-11cf-8fda-00aa00a14f93}"),
+  new RegKey(HKEY_CLASSES_ROOT,
+             L".wdseml\\shellex\\{8895B1C6-B41F-4C1C-A562-0D564250836F}",
+             L"",
+             L"{b9815375-5d7f-4ce2-9245-c9d4da436930}"),
+  new RegKey(HKEY_LOCAL_MACHINE,
+             L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\KindMap",
+             L".wdseml",
+             L"email;communication")
+};
+
+HRESULT GetCrawlScopeManager(ISearchCrawlScopeManager **aCrawlScopeManager)
+{
+  *aCrawlScopeManager = NULL;
+
+  ISearchManager* searchManager;
+  HRESULT hr = CoCreateInstance(CLSID_CSearchManager, NULL, CLSCTX_ALL, IID_ISearchManager, (void**)&searchManager);
+  if (SUCCEEDED(hr))
+  {
+    ISearchCatalogManager* catalogManager;
+    hr = searchManager->GetCatalog(L"SystemIndex", &catalogManager);
+    if (SUCCEEDED(hr))
+    {
+      hr = catalogManager->GetCrawlScopeManager(aCrawlScopeManager);
+      catalogManager->Release();
+    }
+    searchManager->Release();
+  }
+  return hr;
+}
+
+LSTATUS SetRegistryKeys()
+{
+  LSTATUS rv = ERROR_SUCCESS;
+  for (int i = 0; rv == ERROR_SUCCESS && i < _countof(sRegKeys); i++)
+  {
+    const RegKey *key = sRegKeys[i];
+    HKEY subKey;
+    // Since we're administrator, we should be able to do this just fine
+    rv = RegCreateKeyExW(key->mRoot, key->mSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
+          KEY_ALL_ACCESS, NULL, &subKey, NULL);
+    if (rv == ERROR_SUCCESS)
+      rv = RegSetValueExW(subKey, key->mName, 0, REG_SZ, (LPBYTE) key->mValue, 
+            (lstrlenW(key->mValue) + 1) * sizeof(WCHAR));
+    RegCloseKey(subKey);
+  }
+
+  return rv;
+}
+
+int APIENTRY wWinMain(HINSTANCE hInstance,
+                      HINSTANCE hPrevInstance,
+                      LPWSTR    lpCmdLine,
+                      int       nCmdShow)
+{
+  UNREFERENCED_PARAMETER(lpCmdLine);
+
+  HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+  if (SUCCEEDED(hr))
+  {
+    int argc;
+    LPWSTR *argv = CommandLineToArgvW(lpCmdLine, &argc);
+    if (argc != 2)
+      hr = E_INVALIDARG;
+    if (SUCCEEDED(hr))
+    {
+      ISearchCrawlScopeManager* crawlScopeManager;
+      hr = GetCrawlScopeManager(&crawlScopeManager);
+      if (SUCCEEDED(hr))
+      {
+        if (*argv[0] == L'1')
+        {
+          // We first add the required registry entries
+          LSTATUS rv = SetRegistryKeys();
+          if (rv != ERROR_SUCCESS)
+            hr = E_FAIL;
+
+          // Next, we add rules for each of the three folders
+          for (int i = 0; SUCCEEDED(hr) && i < _countof(sFoldersToIndex); i++)
+          {
+            std::wstring path = L"file:///";
+            path.append(argv[1]);
+            path.append(sFoldersToIndex[i]);
+            // Add only if the rule isn't already there
+            BOOL isIncluded = FALSE;
+            hr = crawlScopeManager->IncludedInCrawlScope(path.c_str(), &isIncluded);
+            if (SUCCEEDED(hr) && !isIncluded)
+              hr = crawlScopeManager->AddUserScopeRule(path.c_str(), TRUE, TRUE, TRUE);
+          }
+        }
+        else if (*argv[0] == L'0')
+        {
+          // This is simple, we just exclude the profile dir and override children
+          std::wstring path = L"file:///";
+          path.append(argv[1]);
+          path.append(L"\\*\\");
+          hr = crawlScopeManager->AddUserScopeRule(path.c_str(), FALSE, TRUE, TRUE);
+        }
+        else
+          hr = E_INVALIDARG;
+
+        if (SUCCEEDED(hr))
+        {
+          hr = crawlScopeManager->SaveAll();
+        }
+        crawlScopeManager->Release();
+      }
+    }
+    LocalFree(argv);
+  }
+
+  return hr;
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/search/wsenable/WSEnable.exe.manifest
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+        version="1.0.0.0"
+        processorArchitecture="*"
+        name="Mozilla.Thunderbird"
+        type="win32"
+/>
+<description>Mozilla Thunderbird Windows Search Integration Handler</description>
+<dependency>
+        <dependentAssembly>
+                <assemblyIdentity
+                        type="win32"
+                        name="Microsoft.Windows.Common-Controls"
+                        version="6.0.0.0"
+                        processorArchitecture="*"
+                        publicKeyToken="6595b64144ccf1df"
+                        language="*"
+                />
+        </dependentAssembly>
+</dependency>
+<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
+  <ms_asmv3:security>
+    <ms_asmv3:requestedPrivileges>
+      <ms_asmv3:requestedExecutionLevel level="requireAdministrator" uiAccess="false">
+      </ms_asmv3:requestedExecutionLevel>
+    </ms_asmv3:requestedPrivileges>
+  </ms_asmv3:security>
+</ms_asmv3:trustInfo>
+</assembly>
new file mode 100644
--- /dev/null
+++ b/mail/components/search/wsenable/WSEnable.rc
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Windows Search integration.
+ *
+ * The Initial Developer of the Original Code is
+ *  Siddharth Agarwal <sid1337@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+1 24 "WSEnable.exe.manifest"
new file mode 100644
--- /dev/null
+++ b/mail/components/search/wsenable/module.ver
@@ -0,0 +1,1 @@
+WIN32_MODULE_DESCRIPTION=@MOZ_APP_DISPLAYNAME@ Windows Search Integration Handler
--- a/mail/installer/windows/nsis/shared.nsh
+++ b/mail/installer/windows/nsis/shared.nsh
@@ -370,16 +370,17 @@
   StrCpy $1 "$\"$8$\" -osint -compose $\"%1$\""
   ${AddHandlerValues} "$0\Protocols\mailto" "$1" "$8,0" "${AppRegNameMail} URL" "true" ""
  
   ; Vista Capabilities registry keys
   WriteRegStr HKLM "$0\Capabilities" "ApplicationDescription" "$(REG_APP_DESC)"
   WriteRegStr HKLM "$0\Capabilities" "ApplicationIcon" "$8,0"
   WriteRegStr HKLM "$0\Capabilities" "ApplicationName" "${AppRegNameMail}"
   WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".eml"   "ThunderbirdEML"
+  WriteRegStr HKLM "$0\Capabilities\FileAssociations" ".wdseml" "ThunderbirdEML"
   WriteRegStr HKLM "$0\Capabilities\StartMenu" "Mail" "${ClientsRegName}"
   WriteRegStr HKLM "$0\Capabilities\URLAssociations" "mailto" "Thunderbird.Url.mailto"
 
   ; Vista Registered Application
   WriteRegStr HKLM "Software\RegisteredApplications" "${AppRegNameMail}" "$0\Capabilities"
 !macroend
 !define SetClientsMail "!insertmacro SetClientsMail"
 
--- a/mail/installer/windows/nsis/uninstaller.nsi
+++ b/mail/installer/windows/nsis/uninstaller.nsi
@@ -233,16 +233,20 @@ Section "Uninstall"
 
   ClearErrors
   ReadRegStr $R9 HKCR "ThunderbirdEML" ""
   ; Don't clean up the file handlers if the ThunderbirdEML key still exists
   ; since there could be a second installation that may be the default file
   ; handler.
   ${If} ${Errors}
     ${un.RegCleanFileHandler}  ".eml"   "ThunderbirdEML"
+    ${un.RegCleanFileHandler}  ".wdseml" "ThunderbirdEML"
+    DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\KindMap" ".wdseml"
+    ; It doesn't matter if the value didn't exist
+    ClearErrors
   ${EndIf}
 
   SetShellVarContext all  ; Set SHCTX to HKLM
   ${un.GetSecondInstallPath} "Software\Mozilla" $R9
   ${If} $R9 == "false"
     SetShellVarContext current  ; Set SHCTX to HKCU
     ${un.GetSecondInstallPath} "Software\Mozilla" $R9
   ${EndIf}
--- a/mail/installer/windows/packages-static
+++ b/mail/installer/windows/packages-static
@@ -172,16 +172,20 @@ bin\components\nsPhishingProtectionAppli
 bin\components\nsUrlClassifierListManager.js
 bin\components\nsUrlClassifierLib.js
 bin\components\url-classifier.xpt
 
 ; Address Book autocomplete
 bin\components\nsAbAutoCompleteMyDomain.js
 bin\components\nsAbAutoCompleteSearch.js
 
+; Windows Search integration
+bin\components\nsWinSearchIntegration.js
+bin\WSEnable.exe
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Base Package Files
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 ; xpconnect
 bin\components\xpconnect.xpt
 
 ; XP widgets/graphics
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/search/searchIntegrationDialogWin.dtd
@@ -0,0 +1,6 @@
+<!ENTITY searchIntegration.engineName "Windows Search">
+<!ENTITY searchIntegration.title "&searchIntegration.engineName; Integration">
+<!ENTITY searchIntegration.description "Would you like to enable &searchIntegration.engineName; to index and search through &brandShortName; mail and news messages?">
+
+<!ENTITY searchIntegration.accept "Enable &searchIntegration.engineName;">
+<!ENTITY searchIntegration.cancel "Don't Enable &searchIntegration.engineName;">
--- a/mail/locales/jar.mn
+++ b/mail/locales/jar.mn
@@ -122,16 +122,17 @@
   locale/@AB_CD@/messenger/preferences/downloadactions.dtd              (%chrome/messenger/preferences/downloadactions.dtd)
   locale/@AB_CD@/messenger/preferences/changeaction.dtd                 (%chrome/messenger/preferences/changeaction.dtd)
   locale/@AB_CD@/messenger/preferences/fonts.dtd                        (%chrome/messenger/preferences/fonts.dtd)
   locale/@AB_CD@/messenger/preferences/offline.dtd                      (%chrome/messenger/preferences/offline.dtd)
   locale/@AB_CD@/messenger/preferences/notifications.dtd                (%chrome/messenger/preferences/notifications.dtd)
   locale/@AB_CD@/messenger/preferences/preferences.properties           (%chrome/messenger/preferences/preferences.properties)
   locale/@AB_CD@/messenger/migration/migration.dtd                      (%chrome/messenger/migration/migration.dtd)
   locale/@AB_CD@/messenger/migration/migration.properties               (%chrome/messenger/migration/migration.properties)
+  locale/@AB_CD@/messenger/search/searchIntegrationDialogWin.dtd        (%chrome/messenger/search/searchIntegrationDialogWin.dtd)
 % locale messenger-mapi @AB_CD@ %locale/@AB_CD@/messenger-mapi/
   locale/@AB_CD@/messenger-mapi/mapi.properties                         (%chrome/messenger-mapi/mapi.properties)
 % locale messenger-newsblog @AB_CD@ %locale/@AB_CD@/messenger-newsblog/
   locale/@AB_CD@/messenger-newsblog/newsblog.dtd                        (%chrome/messenger-newsblog/newsblog.dtd)
   locale/@AB_CD@/messenger-newsblog/newsblog.properties                 (%chrome/messenger-newsblog/newsblog.properties)
   locale/@AB_CD@/messenger-newsblog/feed-subscriptions.dtd              (%chrome/messenger-newsblog/feed-subscriptions.dtd)
   locale/@AB_CD@/messenger-newsblog/feed-properties.dtd                 (%chrome/messenger-newsblog/feed-properties.dtd)
   locale/@AB_CD@/messenger-newsblog/am-newsblog.properties              (%chrome/messenger-newsblog/am-newsblog.properties)