uriloader/exthandler/win/nsMIMEInfoWin.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsArrayEnumerator.h"
     8 #include "nsCOMArray.h"
     9 #include "nsIFile.h"
    10 #include "nsIVariant.h"
    11 #include "nsMIMEInfoWin.h"
    12 #include "nsNetUtil.h"
    13 #include <windows.h>
    14 #include <shellapi.h>
    15 #include "nsAutoPtr.h"
    16 #include "nsIMutableArray.h"
    17 #include "nsTArray.h"
    18 #include "shlobj.h"
    19 #include "windows.h"
    20 #include "nsIWindowsRegKey.h"
    21 #include "nsIProcess.h"
    22 #include "nsOSHelperAppService.h"
    23 #include "nsUnicharUtils.h"
    24 #include "nsITextToSubURI.h"
    26 #define RUNDLL32_EXE L"\\rundll32.exe"
    29 NS_IMPL_ISUPPORTS_INHERITED(nsMIMEInfoWin, nsMIMEInfoBase, nsIPropertyBag)
    31 nsMIMEInfoWin::~nsMIMEInfoWin()
    32 {
    33 }
    35 nsresult
    36 nsMIMEInfoWin::LaunchDefaultWithFile(nsIFile* aFile)
    37 {
    38   // Launch the file, unless it is an executable.
    39   bool executable = true;
    40   aFile->IsExecutable(&executable);
    41   if (executable)
    42     return NS_ERROR_FAILURE;
    44   return aFile->Launch();
    45 }
    47 NS_IMETHODIMP
    48 nsMIMEInfoWin::LaunchWithFile(nsIFile* aFile)
    49 {
    50   nsresult rv;
    52   // it doesn't make any sense to call this on protocol handlers
    53   NS_ASSERTION(mClass == eMIMEInfo,
    54                "nsMIMEInfoBase should have mClass == eMIMEInfo");
    56   if (mPreferredAction == useSystemDefault) {
    57     return LaunchDefaultWithFile(aFile);
    58   }
    60   if (mPreferredAction == useHelperApp) {
    61     if (!mPreferredApplication)
    62       return NS_ERROR_FILE_NOT_FOUND;
    64     // at the moment, we only know how to hand files off to local handlers
    65     nsCOMPtr<nsILocalHandlerApp> localHandler = 
    66       do_QueryInterface(mPreferredApplication, &rv);
    67     NS_ENSURE_SUCCESS(rv, rv);
    69     nsCOMPtr<nsIFile> executable;
    70     rv = localHandler->GetExecutable(getter_AddRefs(executable));
    71     NS_ENSURE_SUCCESS(rv, rv);
    73     nsAutoString path;
    74     aFile->GetPath(path);
    76     // Deal with local dll based handlers
    77     nsCString filename;
    78     executable->GetNativeLeafName(filename);
    79     if (filename.Length() > 4) {
    80       nsCString extension(Substring(filename, filename.Length() - 4, 4));
    82       if (extension.LowerCaseEqualsLiteral(".dll")) {
    83         nsAutoString args;
    85         // executable is rundll32, everything else is a list of parameters, 
    86         // including the dll handler.
    87         if (!GetDllLaunchInfo(executable, aFile, args, false))
    88           return NS_ERROR_INVALID_ARG;
    90         WCHAR rundll32Path[MAX_PATH + sizeof(RUNDLL32_EXE) / sizeof(WCHAR) + 1] = {L'\0'};
    91         if (!GetSystemDirectoryW(rundll32Path, MAX_PATH)) {
    92           return NS_ERROR_FILE_NOT_FOUND;
    93         }
    94         lstrcatW(rundll32Path, RUNDLL32_EXE);
    96         SHELLEXECUTEINFOW seinfo;
    97         memset(&seinfo, 0, sizeof(seinfo));
    98         seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
    99         seinfo.fMask  = 0;
   100         seinfo.hwnd   = nullptr;
   101         seinfo.lpVerb = nullptr;
   102         seinfo.lpFile = rundll32Path;
   103         seinfo.lpParameters =  args.get();
   104         seinfo.lpDirectory  = nullptr;
   105         seinfo.nShow  = SW_SHOWNORMAL;
   106         if (ShellExecuteExW(&seinfo))
   107           return NS_OK;
   109         switch ((LONG_PTR)seinfo.hInstApp) {
   110           case 0:
   111           case SE_ERR_OOM:
   112             return NS_ERROR_OUT_OF_MEMORY;
   113           case SE_ERR_ACCESSDENIED:
   114             return NS_ERROR_FILE_ACCESS_DENIED;
   115           case SE_ERR_ASSOCINCOMPLETE:
   116           case SE_ERR_NOASSOC:
   117             return NS_ERROR_UNEXPECTED;
   118           case SE_ERR_DDEBUSY:
   119           case SE_ERR_DDEFAIL:
   120           case SE_ERR_DDETIMEOUT:
   121             return NS_ERROR_NOT_AVAILABLE;
   122           case SE_ERR_DLLNOTFOUND:
   123             return NS_ERROR_FAILURE;
   124           case SE_ERR_SHARE:
   125             return NS_ERROR_FILE_IS_LOCKED;
   126           default:
   127             switch(GetLastError()) {
   128               case ERROR_FILE_NOT_FOUND:
   129                 return NS_ERROR_FILE_NOT_FOUND;
   130               case ERROR_PATH_NOT_FOUND:
   131                 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
   132               case ERROR_BAD_FORMAT:
   133                 return NS_ERROR_FILE_CORRUPTED;
   134             }
   136         }
   137         return NS_ERROR_FILE_EXECUTION_FAILED;
   138       }
   139     }
   140     return LaunchWithIProcess(executable, path);
   141   }
   143   return NS_ERROR_INVALID_ARG;
   144 }
   146 NS_IMETHODIMP
   147 nsMIMEInfoWin::GetHasDefaultHandler(bool * _retval)
   148 {
   149   // We have a default application if we have a description
   150   // We can ShellExecute anything; however, callers are probably interested if
   151   // there is really an application associated with this type of file
   152   *_retval = !mDefaultAppDescription.IsEmpty();
   153   return NS_OK;
   154 }
   156 NS_IMETHODIMP
   157 nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator* *_retval)
   158 {
   159   nsCOMArray<nsIVariant> properties;
   161   nsCOMPtr<nsIVariant> variant;
   162   GetProperty(NS_LITERAL_STRING("defaultApplicationIconURL"), getter_AddRefs(variant));
   163   if (variant)
   164     properties.AppendObject(variant);
   166   GetProperty(NS_LITERAL_STRING("customApplicationIconURL"), getter_AddRefs(variant));
   167   if (variant)
   168     properties.AppendObject(variant);
   170   return NS_NewArrayEnumerator(_retval, properties);
   171 }
   173 static nsresult GetIconURLVariant(nsIFile* aApplication, nsIVariant* *_retval)
   174 {
   175   nsresult rv = CallCreateInstance("@mozilla.org/variant;1", _retval);
   176   if (NS_FAILED(rv))
   177     return rv;
   178   nsAutoCString fileURLSpec;
   179   NS_GetURLSpecFromFile(aApplication, fileURLSpec);
   180   nsAutoCString iconURLSpec; iconURLSpec.AssignLiteral("moz-icon://");
   181   iconURLSpec += fileURLSpec;
   182   nsCOMPtr<nsIWritableVariant> writable(do_QueryInterface(*_retval));
   183   writable->SetAsAUTF8String(iconURLSpec);
   184   return NS_OK;
   185 }
   187 NS_IMETHODIMP
   188 nsMIMEInfoWin::GetProperty(const nsAString& aName, nsIVariant* *_retval)
   189 {
   190   nsresult rv;
   191   if (mDefaultApplication && aName.EqualsLiteral(PROPERTY_DEFAULT_APP_ICON_URL)) {
   192     rv = GetIconURLVariant(mDefaultApplication, _retval);
   193     NS_ENSURE_SUCCESS(rv, rv);    
   194   } else if (mPreferredApplication && 
   195              aName.EqualsLiteral(PROPERTY_CUSTOM_APP_ICON_URL)) {
   196     nsCOMPtr<nsILocalHandlerApp> localHandler =
   197       do_QueryInterface(mPreferredApplication, &rv);
   198     NS_ENSURE_SUCCESS(rv, rv);
   200     nsCOMPtr<nsIFile> executable;
   201     rv = localHandler->GetExecutable(getter_AddRefs(executable));
   202     NS_ENSURE_SUCCESS(rv, rv);
   204     rv = GetIconURLVariant(executable, _retval);
   205     NS_ENSURE_SUCCESS(rv, rv);
   206   }
   208   return NS_OK;
   209 }
   211 // this implementation was pretty much copied verbatime from 
   212 // Tony Robinson's code in nsExternalProtocolWin.cpp
   213 nsresult
   214 nsMIMEInfoWin::LoadUriInternal(nsIURI * aURL)
   215 {
   216   nsresult rv = NS_OK;
   218   // 1. Find the default app for this protocol
   219   // 2. Set up the command line
   220   // 3. Launch the app.
   222   // For now, we'll just cheat essentially, check for the command line
   223   // then just call ShellExecute()!
   225   if (aURL)
   226   {
   227     // extract the url spec from the url
   228     nsAutoCString urlSpec;
   229     aURL->GetAsciiSpec(urlSpec);
   231     // Unescape non-ASCII characters in the URL
   232     nsAutoCString urlCharset;
   233     nsAutoString utf16Spec;
   234     rv = aURL->GetOriginCharset(urlCharset);
   235     NS_ENSURE_SUCCESS(rv, rv);
   237     nsCOMPtr<nsITextToSubURI> textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
   238     NS_ENSURE_SUCCESS(rv, rv);
   240     rv = textToSubURI->UnEscapeNonAsciiURI(urlCharset, urlSpec, utf16Spec);
   241     NS_ENSURE_SUCCESS(rv, rv);
   243     static const wchar_t cmdVerb[] = L"open";
   244     SHELLEXECUTEINFOW sinfo;
   245     memset(&sinfo, 0, sizeof(sinfo));
   246     sinfo.cbSize   = sizeof(sinfo);
   247     sinfo.fMask    = SEE_MASK_FLAG_DDEWAIT |
   248       SEE_MASK_FLAG_NO_UI;
   249     sinfo.hwnd     = nullptr;
   250     sinfo.lpVerb   = (LPWSTR)&cmdVerb;
   251     sinfo.nShow    = SW_SHOWNORMAL;
   253     LPITEMIDLIST pidl = nullptr;
   254     SFGAOF sfgao;
   256     // Bug 394974
   257     if (SUCCEEDED(SHParseDisplayName(utf16Spec.get(), nullptr,
   258                                      &pidl, 0, &sfgao))) {
   259       sinfo.lpIDList = pidl;
   260       sinfo.fMask |= SEE_MASK_INVOKEIDLIST;
   261     } else {
   262       // SHParseDisplayName failed. Bailing out as work around for
   263       // Microsoft Security Bulletin MS07-061
   264       rv = NS_ERROR_FAILURE;
   265     }
   266     if (NS_SUCCEEDED(rv)) {
   267       BOOL result = ShellExecuteExW(&sinfo);
   268       if (!result || ((LONG_PTR)sinfo.hInstApp) < 32)
   269         rv = NS_ERROR_FAILURE;
   270     }
   271     if (pidl)
   272       CoTaskMemFree(pidl);
   273   }
   275   return rv;
   276 }
   278 // Given a path to a local file, return its nsILocalHandlerApp instance.
   279 bool nsMIMEInfoWin::GetLocalHandlerApp(const nsAString& aCommandHandler,
   280                                          nsCOMPtr<nsILocalHandlerApp>& aApp)
   281 {
   282   nsCOMPtr<nsIFile> locfile;
   283   nsresult rv = 
   284     NS_NewLocalFile(aCommandHandler, true, getter_AddRefs(locfile));
   285   if (NS_FAILED(rv))
   286     return false;
   288   aApp = do_CreateInstance("@mozilla.org/uriloader/local-handler-app;1");
   289   if (!aApp) 
   290     return false;
   292   aApp->SetExecutable(locfile);
   293   return true;
   294 }
   296 // Return the cleaned up file path associated with a command verb 
   297 // located in root/Applications.
   298 bool nsMIMEInfoWin::GetAppsVerbCommandHandler(const nsAString& appExeName,
   299                                                 nsAString& applicationPath,
   300                                                 bool edit)
   301 {
   302   nsCOMPtr<nsIWindowsRegKey> appKey = 
   303     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   304   if (!appKey) 
   305     return false; 
   307   // HKEY_CLASSES_ROOT\Applications\iexplore.exe
   308   nsAutoString applicationsPath;
   309   applicationsPath.AppendLiteral("Applications\\");
   310   applicationsPath.Append(appExeName);
   312   nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   313                              applicationsPath,
   314                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   315   if (NS_FAILED(rv)) 
   316     return false;
   318   // Check for the NoOpenWith flag, if it exists
   319   uint32_t value;
   320   if (NS_SUCCEEDED(appKey->ReadIntValue(
   321       NS_LITERAL_STRING("NoOpenWith"), &value)) &&
   322       value == 1)
   323     return false;
   325   nsAutoString dummy;
   326   if (NS_SUCCEEDED(appKey->ReadStringValue(
   327         NS_LITERAL_STRING("NoOpenWith"), dummy)))
   328     return false;
   330   appKey->Close();
   332   // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
   333   applicationsPath.AssignLiteral("Applications\\");
   334   applicationsPath.Append(appExeName);
   335   if (!edit)
   336     applicationsPath.AppendLiteral("\\shell\\open\\command");
   337   else
   338     applicationsPath.AppendLiteral("\\shell\\edit\\command");
   341   rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   342                     applicationsPath,
   343                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   344   if (NS_FAILED(rv)) 
   345     return false;
   347   nsAutoString appFilesystemCommand;
   348   if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), 
   349                                            appFilesystemCommand))) {
   351     // Expand environment vars, clean up any misc.
   352     if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
   353       return false;
   355     applicationPath = appFilesystemCommand;
   356     return true;
   357   }
   358   return false;
   359 }
   361 // Return a fully populated command string based on
   362 // passing information. Used in launchWithFile to trace
   363 // back to the full handler path based on the dll.
   364 // (dll, targetfile, return args, open/edit)
   365 bool nsMIMEInfoWin::GetDllLaunchInfo(nsIFile * aDll,
   366                                        nsIFile * aFile,
   367                                        nsAString& args,
   368                                        bool edit)
   369 {
   370   if (!aDll || !aFile) 
   371     return false;
   373   nsString appExeName;
   374   aDll->GetLeafName(appExeName);
   376   nsCOMPtr<nsIWindowsRegKey> appKey = 
   377     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   378   if (!appKey) 
   379     return false; 
   381   // HKEY_CLASSES_ROOT\Applications\iexplore.exe
   382   nsAutoString applicationsPath;
   383   applicationsPath.AppendLiteral("Applications\\");
   384   applicationsPath.Append(appExeName);
   386   nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   387                              applicationsPath,
   388                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   389   if (NS_FAILED(rv))
   390     return false;
   392   // Check for the NoOpenWith flag, if it exists
   393   uint32_t value;
   394   rv = appKey->ReadIntValue(NS_LITERAL_STRING("NoOpenWith"), &value);
   395   if (NS_SUCCEEDED(rv) && value == 1)
   396     return false;
   398   nsAutoString dummy;
   399   if (NS_SUCCEEDED(appKey->ReadStringValue(NS_LITERAL_STRING("NoOpenWith"), 
   400                                            dummy)))
   401     return false;
   403   appKey->Close();
   405   // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
   406   applicationsPath.AssignLiteral("Applications\\");
   407   applicationsPath.Append(appExeName);
   408   if (!edit)
   409     applicationsPath.AppendLiteral("\\shell\\open\\command");
   410   else
   411     applicationsPath.AppendLiteral("\\shell\\edit\\command");
   413   rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   414                     applicationsPath,
   415                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   416   if (NS_FAILED(rv))
   417     return false;
   419   nsAutoString appFilesystemCommand;
   420   if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(),
   421                                            appFilesystemCommand))) {
   422     // Replace embedded environment variables.
   423     uint32_t bufLength = 
   424       ::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
   425                                   L"", 0);
   426     if (bufLength == 0) // Error
   427       return false;
   429     nsAutoArrayPtr<wchar_t> destination(new wchar_t[bufLength]);
   430     if (!destination)
   431       return false;
   432     if (!::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
   433                                      destination,
   434                                      bufLength))
   435       return false;
   437     appFilesystemCommand = static_cast<const wchar_t*>(destination);
   439     // C:\Windows\System32\rundll32.exe "C:\Program Files\Windows 
   440     // Photo Gallery\PhotoViewer.dll", ImageView_Fullscreen %1
   441     nsAutoString params;
   442     NS_NAMED_LITERAL_STRING(rundllSegment, "rundll32.exe ");
   443     int32_t index = appFilesystemCommand.Find(rundllSegment);
   444     if (index > kNotFound) {
   445       params.Append(Substring(appFilesystemCommand,
   446                     index + rundllSegment.Length()));
   447     } else {
   448       params.Append(appFilesystemCommand);
   449     }
   451     // check to make sure we have a %1 and fill it
   452     NS_NAMED_LITERAL_STRING(percentOneParam, "%1");
   453     index = params.Find(percentOneParam);
   454     if (index == kNotFound) // no parameter
   455       return false;
   457     nsString target;
   458     aFile->GetTarget(target);
   459     params.Replace(index, 2, target);
   461     args = params;
   463     return true;
   464   }
   465   return false;
   466 }
   468 // Return the cleaned up file path associated with a progid command 
   469 // verb located in root.
   470 bool nsMIMEInfoWin::GetProgIDVerbCommandHandler(const nsAString& appProgIDName,
   471                                                   nsAString& applicationPath,
   472                                                   bool edit)
   473 {
   474   nsCOMPtr<nsIWindowsRegKey> appKey =
   475     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   476   if (!appKey) 
   477     return false; 
   479   nsAutoString appProgId(appProgIDName);
   481   // HKEY_CLASSES_ROOT\Windows.XPSReachViewer\shell\open\command
   482   if (!edit)
   483     appProgId.AppendLiteral("\\shell\\open\\command");
   484   else
   485     appProgId.AppendLiteral("\\shell\\edit\\command");
   487   nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   488                              appProgId,
   489                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   490   if (NS_FAILED(rv))
   491     return false;
   493   nsAutoString appFilesystemCommand;
   494   if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), appFilesystemCommand))) {
   496     // Expand environment vars, clean up any misc.
   497     if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
   498       return false;
   500     applicationPath = appFilesystemCommand;
   501     return true;
   502   }
   503   return false;
   504 }
   506 // Helper routine used in tracking app lists. Converts path
   507 // entries to lower case and stores them in the trackList array.
   508 void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
   509                                 nsTArray<nsString>& trackList,
   510                                 const nsAString& appFilesystemCommand)
   511 {
   512   nsAutoString lower(appFilesystemCommand);
   513   ToLowerCase(lower);
   515   // Don't include firefox.exe in the list
   516   WCHAR exe[MAX_PATH+1];
   517   uint32_t len = GetModuleFileNameW(nullptr, exe, MAX_PATH);
   518   if (len < MAX_PATH && len != 0) {
   519     uint32_t index = lower.Find(exe);
   520     if (index != -1)
   521       return;
   522   }
   524   nsCOMPtr<nsILocalHandlerApp> aApp;
   525   if (!GetLocalHandlerApp(appFilesystemCommand, aApp))
   526     return;
   528   // Save in our main tracking arrays
   529   appList->AppendElement(aApp, false);
   530   trackList.AppendElement(lower);
   531 }
   533 // Helper routine that handles a compare between a path
   534 // and an array of paths.
   535 static bool IsPathInList(nsAString& appPath,
   536                            nsTArray<nsString>& trackList)
   537 {
   538   // trackList data is always lowercase, see ProcessPath
   539   // above.
   540   nsAutoString tmp(appPath);
   541   ToLowerCase(tmp);
   543   for (uint32_t i = 0; i < trackList.Length(); i++) {
   544     if (tmp.Equals(trackList[i]))
   545       return true;
   546   }
   547   return false;
   548 }
   550 /** 
   551  * Returns a list of nsILocalHandlerApp objects containing local 
   552  * handlers associated with this mimeinfo. Implemented per 
   553  * platform using information in this object to generate the
   554  * best list. Typically used for an "open with" style user 
   555  * option.
   556  * 
   557  * @return nsIArray of nsILocalHandlerApp
   558  */
   559 NS_IMETHODIMP
   560 nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray **_retval)
   561 {
   562   nsresult rv;
   564   *_retval = nullptr;
   566   nsCOMPtr<nsIMutableArray> appList =
   567     do_CreateInstance("@mozilla.org/array;1");
   569   if (!appList)
   570     return NS_ERROR_FAILURE;
   572   nsTArray<nsString> trackList;
   574   nsAutoCString fileExt;
   575   GetPrimaryExtension(fileExt);
   577   nsCOMPtr<nsIWindowsRegKey> regKey =
   578     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   579   if (!regKey) 
   580     return NS_ERROR_FAILURE; 
   581   nsCOMPtr<nsIWindowsRegKey> appKey =
   582     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   583   if (!appKey) 
   584     return NS_ERROR_FAILURE; 
   586   nsAutoString workingRegistryPath;
   588   bool extKnown = false;
   589   if (fileExt.IsEmpty()) {
   590     extKnown = true;
   591     // Mime type discovery is possible in some cases, through 
   592     // HKEY_CLASSES_ROOT\MIME\Database\Content Type, however, a number
   593     // of file extensions related to mime type are simply not defined,
   594     // (application/rss+xml & application/atom+xml are good examples)
   595     // in which case we can only provide a generic list.
   596     nsAutoCString mimeType;
   597     GetMIMEType(mimeType);
   598     if (!mimeType.IsEmpty()) {
   599       workingRegistryPath.AppendLiteral("MIME\\Database\\Content Type\\");
   600       workingRegistryPath.Append(NS_ConvertASCIItoUTF16(mimeType));
   602       rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   603                         workingRegistryPath,
   604                         nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   605       if(NS_SUCCEEDED(rv)) {
   606         nsAutoString mimeFileExt;
   607         if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), mimeFileExt))) {
   608           CopyUTF16toUTF8(mimeFileExt, fileExt);
   609           extKnown = false;
   610         }
   611       }
   612     }
   613   }
   615   nsAutoString fileExtToUse;
   616   if (fileExt.First() != '.')
   617     fileExtToUse = char16_t('.');
   618   fileExtToUse.Append(NS_ConvertUTF8toUTF16(fileExt));
   620   // Note, the order in which these occur has an effect on the 
   621   // validity of the resulting display list.
   623   if (!extKnown) {
   624     // 1) Get the default handler if it exists
   625     workingRegistryPath = fileExtToUse;
   627     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   628                       workingRegistryPath,
   629                       nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   630     if (NS_SUCCEEDED(rv)) {
   631       nsAutoString appProgId;
   632       if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), appProgId))) {
   633         // Bug 358297 - ignore the embedded internet explorer handler
   634         if (appProgId != NS_LITERAL_STRING("XPSViewer.Document")) {
   635           nsAutoString appFilesystemCommand;
   636           if (GetProgIDVerbCommandHandler(appProgId,
   637                                           appFilesystemCommand,
   638                                           false) &&
   639               !IsPathInList(appFilesystemCommand, trackList)) {
   640             ProcessPath(appList, trackList, appFilesystemCommand);
   641           }
   642         }
   643       }
   644       regKey->Close();
   645     }
   648     // 2) list HKEY_CLASSES_ROOT\.ext\OpenWithList
   650     workingRegistryPath = fileExtToUse;
   651     workingRegistryPath.AppendLiteral("\\OpenWithList");
   653     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   654                       workingRegistryPath,
   655                       nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   656     if (NS_SUCCEEDED(rv)) {
   657       uint32_t count = 0;
   658       if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   659         for (uint32_t index = 0; index < count; index++) {
   660           nsAutoString appName;
   661           if (NS_FAILED(regKey->GetValueName(index, appName)))
   662             continue;
   664           // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
   665           nsAutoString appFilesystemCommand;
   666           if (!GetAppsVerbCommandHandler(appName,
   667                                          appFilesystemCommand,
   668                                          false) ||
   669               IsPathInList(appFilesystemCommand, trackList))
   670             continue;
   671           ProcessPath(appList, trackList, appFilesystemCommand);
   672         }
   673       }
   674       regKey->Close();
   675     }
   678     // 3) List HKEY_CLASSES_ROOT\.ext\OpenWithProgids, with the
   679     // different step of resolving the progids for the command handler.
   681     workingRegistryPath = fileExtToUse;
   682     workingRegistryPath.AppendLiteral("\\OpenWithProgids");
   684     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   685                       workingRegistryPath,
   686                       nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   687     if (NS_SUCCEEDED(rv)) {
   688       uint32_t count = 0;
   689       if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   690         for (uint32_t index = 0; index < count; index++) {
   691           // HKEY_CLASSES_ROOT\.ext\OpenWithProgids\Windows.XPSReachViewer
   692           nsAutoString appProgId;
   693           if (NS_FAILED(regKey->GetValueName(index, appProgId)))
   694             continue;
   696           nsAutoString appFilesystemCommand;
   697           if (!GetProgIDVerbCommandHandler(appProgId,
   698                                            appFilesystemCommand,
   699                                            false) ||
   700               IsPathInList(appFilesystemCommand, trackList))
   701             continue;
   702           ProcessPath(appList, trackList, appFilesystemCommand);
   703         }
   704       }
   705       regKey->Close();
   706     }
   709     // 4) Add any non configured applications located in the MRU list
   711     // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion
   712     // \Explorer\FileExts\.ext\OpenWithList
   713     workingRegistryPath =
   714       NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
   715     workingRegistryPath += fileExtToUse;
   716     workingRegistryPath.AppendLiteral("\\OpenWithList");
   718     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
   719                       workingRegistryPath,
   720                       nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   721     if (NS_SUCCEEDED(rv)) {
   722       uint32_t count = 0;
   723       if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   724         for (uint32_t index = 0; index < count; index++) {
   725           nsAutoString appName, appValue;
   726           if (NS_FAILED(regKey->GetValueName(index, appName)))
   727             continue;
   728           if (appName.EqualsLiteral("MRUList"))
   729             continue;
   730           if (NS_FAILED(regKey->ReadStringValue(appName, appValue)))
   731             continue;
   733           // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
   734           nsAutoString appFilesystemCommand;
   735           if (!GetAppsVerbCommandHandler(appValue,
   736                                          appFilesystemCommand,
   737                                          false) ||
   738               IsPathInList(appFilesystemCommand, trackList))
   739             continue;
   740           ProcessPath(appList, trackList, appFilesystemCommand);
   741         }
   742       }
   743     }
   746     // 5) Add any non configured progids in the MRU list, with the
   747     // different step of resolving the progids for the command handler.
   749     // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion
   750     // \Explorer\FileExts\.ext\OpenWithProgids
   751     workingRegistryPath =
   752       NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
   753     workingRegistryPath += fileExtToUse;
   754     workingRegistryPath.AppendLiteral("\\OpenWithProgids");
   756     regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
   757                  workingRegistryPath,
   758                  nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   759     if (NS_SUCCEEDED(rv)) {
   760       uint32_t count = 0;
   761       if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   762         for (uint32_t index = 0; index < count; index++) {
   763           nsAutoString appIndex, appProgId;
   764           if (NS_FAILED(regKey->GetValueName(index, appProgId)))
   765             continue;
   767           nsAutoString appFilesystemCommand;
   768           if (!GetProgIDVerbCommandHandler(appProgId,
   769                                            appFilesystemCommand,
   770                                            false) ||
   771               IsPathInList(appFilesystemCommand, trackList))
   772             continue;
   773           ProcessPath(appList, trackList, appFilesystemCommand);
   774         }
   775       }
   776       regKey->Close();
   777     }
   780     // 6) Check the perceived type value, and use this to lookup the perceivedtype
   781     // open with list.
   782     // http://msdn2.microsoft.com/en-us/library/aa969373.aspx
   784     workingRegistryPath = fileExtToUse;
   786     regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   787                  workingRegistryPath,
   788                  nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   789     if (NS_SUCCEEDED(rv)) {
   790       nsAutoString perceivedType;
   791       rv = regKey->ReadStringValue(NS_LITERAL_STRING("PerceivedType"),
   792                                    perceivedType);
   793       if (NS_SUCCEEDED(rv)) {
   794         nsAutoString openWithListPath(NS_LITERAL_STRING("SystemFileAssociations\\"));
   795         openWithListPath.Append(perceivedType); // no period
   796         openWithListPath.Append(NS_LITERAL_STRING("\\OpenWithList"));
   798         nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   799                                    openWithListPath,
   800                                    nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   801         if (NS_SUCCEEDED(rv)) {
   802           uint32_t count = 0;
   803           if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   804             for (uint32_t index = 0; index < count; index++) {
   805               nsAutoString appName;
   806               if (NS_FAILED(regKey->GetValueName(index, appName)))
   807                 continue;
   809               // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
   810               nsAutoString appFilesystemCommand;
   811               if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, 
   812                                              false) ||
   813                   IsPathInList(appFilesystemCommand, trackList))
   814                 continue;
   815               ProcessPath(appList, trackList, appFilesystemCommand);
   816             }
   817           }
   818         }
   819       }
   820     }
   821   } // extKnown == false
   824   // 7) list global HKEY_CLASSES_ROOT\*\OpenWithList
   825   // Listing general purpose handlers, not specific to a mime type or file extension
   827   workingRegistryPath = NS_LITERAL_STRING("*\\OpenWithList");
   829   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   830                     workingRegistryPath,
   831                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   832   if (NS_SUCCEEDED(rv)) {
   833     uint32_t count = 0;
   834     if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
   835       for (uint32_t index = 0; index < count; index++) {
   836         nsAutoString appName;
   837         if (NS_FAILED(regKey->GetValueName(index, appName)))
   838           continue;
   840         // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
   841         nsAutoString appFilesystemCommand;
   842         if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
   843                                        false) ||
   844             IsPathInList(appFilesystemCommand, trackList))
   845           continue;
   846         ProcessPath(appList, trackList, appFilesystemCommand);
   847       }
   848     }
   849     regKey->Close();
   850   }
   853   // 8) General application's list - not file extension specific on windows
   854   workingRegistryPath = NS_LITERAL_STRING("Applications");
   856   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
   857                     workingRegistryPath,
   858                     nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS|
   859                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   860   if (NS_SUCCEEDED(rv)) {
   861     uint32_t count = 0;
   862     if (NS_SUCCEEDED(regKey->GetChildCount(&count)) && count > 0) {
   863       for (uint32_t index = 0; index < count; index++) {
   864         nsAutoString appName;
   865         if (NS_FAILED(regKey->GetChildName(index, appName)))
   866           continue;
   868         // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
   869         nsAutoString appFilesystemCommand;
   870         if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
   871                                        false) ||
   872             IsPathInList(appFilesystemCommand, trackList))
   873           continue;
   874         ProcessPath(appList, trackList, appFilesystemCommand);
   875       }
   876     }
   877   }
   879   // Return to the caller
   880   *_retval = appList;
   881   NS_ADDREF(*_retval);
   883   return NS_OK;
   884 }

mercurial