summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/search/nsMailWinSearchHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/search/nsMailWinSearchHelper.cpp')
-rw-r--r--comm/mail/components/search/nsMailWinSearchHelper.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/comm/mail/components/search/nsMailWinSearchHelper.cpp b/comm/mail/components/search/nsMailWinSearchHelper.cpp
new file mode 100644
index 0000000000..9cfdc40cc0
--- /dev/null
+++ b/comm/mail/components/search/nsMailWinSearchHelper.cpp
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsMailWinSearchHelper.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsString.h"
+#include "nsIDirectoryEnumerator.h"
+#include "mozilla/ArrayUtils.h"
+
+#ifdef _WIN32_WINNT
+# undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+#include <SearchAPI.h>
+#include <winsvc.h>
+#include <ShellAPI.h>
+#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_ISUPPORTS(nsMailWinSearchHelper, nsIMailWinSearchHelper)
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetFoldersInCrawlScope(bool* aResult) {
+ *aResult = false;
+ NS_ENSURE_ARG_POINTER(mProfD);
+
+ // If the service isn't present or running, we shouldn't proceed.
+ bool 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
+ RefPtr<ISearchManager> searchManager;
+ HRESULT hr =
+ CoCreateInstance(CLSID_CSearchManager, NULL, CLSCTX_ALL,
+ IID_ISearchManager, getter_AddRefs(searchManager));
+ if (FAILED(hr)) return NS_ERROR_FAILURE;
+
+ RefPtr<ISearchCatalogManager> catalogManager;
+ hr =
+ searchManager->GetCatalog(L"SystemIndex", getter_AddRefs(catalogManager));
+ if (FAILED(hr)) return NS_ERROR_FAILURE;
+
+ RefPtr<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 (uint32_t i = 0; i < MOZ_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(u"file:///"_ns);
+ subdirURL.Append(subdirPath);
+ subdirURL.Append('\\');
+
+ 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 = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetServiceRunning(bool* aResult) {
+ *aResult = false;
+ SC_HANDLE hSCManager =
+ OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASEW, SERVICE_QUERY_STATUS);
+ if (!hSCManager) return NS_ERROR_FAILURE;
+
+ SC_HANDLE hService =
+ OpenServiceW(hSCManager, L"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, bool aBit,
+ bool aRecurse) {
+ NS_ENSURE_ARG_POINTER(aFile);
+
+ bool 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
+ bool isDirectory;
+ rv = aFile->IsDirectory(&isDirectory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (aRecurse && isDirectory) {
+ nsCOMPtr<nsIDirectoryEnumerator> children;
+ rv = aFile->GetDirectoryEntries(getter_AddRefs(children));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool hasMore = false;
+ while (NS_SUCCEEDED(children->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsIFile> childFile;
+ rv = children->GetNextFile(getter_AddRefs(childFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = SetFANCIBit(childFile, aBit, aRecurse);
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::GetIsFileAssociationSet(bool* aResult) {
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ // We'll use the Vista method here
+ RefPtr<IApplicationAssociationRegistration> pAAR;
+ HRESULT hr = CoCreateInstance(
+ CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC,
+ IID_IApplicationAssociationRegistration, getter_AddRefs(pAAR));
+
+ BOOL res = false;
+ if (SUCCEEDED(hr))
+ pAAR->QueryAppIsDefault(L".wdseml", AT_FILEEXTENSION, AL_EFFECTIVE,
+ APP_REG_NAME_MAIL, &res);
+ *aResult = res;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMailWinSearchHelper::SetFileAssociation() {
+ RefPtr<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(bool aEnable) {
+ nsresult rv;
+ if (!mCurProcD) {
+ rv = NS_GetSpecialDirectory("CurProcD", getter_AddRefs(mCurProcD));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = mCurProcD->Append(u"WSEnable.exe"_ns);
+ 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 ? u"1 \""_ns : u"0 \""_ns);
+ nsAutoString profDPath;
+ rv = mProfD->GetPath(profDPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+ params.Append(profDPath);
+ params.Append(u"\""_ns);
+
+ // 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 = ERROR_SUCCESS;
+
+ 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;
+}