LCOV - code coverage report
Current view: top level - uriloader/exthandler/unix - nsOSHelperAppService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 210 724 29.0 %
Date: 2017-07-14 16:53:18 Functions: 12 25 48.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include <sys/types.h>
       8             : #include <sys/stat.h>
       9             : 
      10             : #if defined(MOZ_ENABLE_CONTENTACTION)
      11             : #include <contentaction/contentaction.h>
      12             : #include <QString>
      13             : #endif
      14             : 
      15             : #include "nsOSHelperAppService.h"
      16             : #include "nsMIMEInfoUnix.h"
      17             : #ifdef MOZ_WIDGET_GTK
      18             : #include "nsGNOMERegistry.h"
      19             : #endif
      20             : #include "nsISupports.h"
      21             : #include "nsString.h"
      22             : #include "nsReadableUtils.h"
      23             : #include "nsUnicharUtils.h"
      24             : #include "nsXPIDLString.h"
      25             : #include "nsIURL.h"
      26             : #include "nsIFileStreams.h"
      27             : #include "nsILineInputStream.h"
      28             : #include "nsIFile.h"
      29             : #include "nsIProcess.h"
      30             : #include "nsNetCID.h"
      31             : #include "nsXPCOM.h"
      32             : #include "nsISupportsPrimitives.h"
      33             : #include "nsCRT.h"
      34             : #include "nsDirectoryServiceDefs.h"
      35             : #include "nsDirectoryServiceUtils.h"
      36             : #include "prenv.h"      // for PR_GetEnv()
      37             : #include "nsAutoPtr.h"
      38             : #include "mozilla/Preferences.h"
      39             : 
      40             : using namespace mozilla;
      41             : 
      42             : #define LOG(args) MOZ_LOG(mLog, mozilla::LogLevel::Debug, args)
      43             : #define LOG_ENABLED() MOZ_LOG_TEST(mLog, mozilla::LogLevel::Debug)
      44             : 
      45             : static nsresult
      46             : FindSemicolon(nsAString::const_iterator& aSemicolon_iter,
      47             :               const nsAString::const_iterator& aEnd_iter);
      48             : static nsresult
      49             : ParseMIMEType(const nsAString::const_iterator& aStart_iter,
      50             :               nsAString::const_iterator& aMajorTypeStart,
      51             :               nsAString::const_iterator& aMajorTypeEnd,
      52             :               nsAString::const_iterator& aMinorTypeStart,
      53             :               nsAString::const_iterator& aMinorTypeEnd,
      54             :               const nsAString::const_iterator& aEnd_iter);
      55             : 
      56             : inline bool
      57             : IsNetscapeFormat(const nsACString& aBuffer);
      58             : 
      59           3 : nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
      60             : {
      61           3 :   mode_t mask = umask(0777);
      62           3 :   umask(mask);
      63           3 :   mPermissions = 0666 & ~mask;
      64           3 : }
      65             : 
      66           0 : nsOSHelperAppService::~nsOSHelperAppService()
      67           0 : {}
      68             : 
      69             : /*
      70             :  * Take a command with all the mailcap escapes in it and unescape it
      71             :  * Ideally this needs the mime type, mime type options, and location of the
      72             :  * temporary file, but this last can't be got from here
      73             :  */
      74             : // static
      75             : nsresult
      76           0 : nsOSHelperAppService::UnescapeCommand(const nsAString& aEscapedCommand,
      77             :                                       const nsAString& aMajorType,
      78             :                                       const nsAString& aMinorType,
      79             :                                       nsACString& aUnEscapedCommand) {
      80           0 :   LOG(("-- UnescapeCommand"));
      81           0 :   LOG(("Command to escape: '%s'\n",
      82             :        NS_LossyConvertUTF16toASCII(aEscapedCommand).get()));
      83             :   //  XXX This function will need to get the mime type and various stuff like that being passed in to work properly
      84             : 
      85           0 :   LOG(("UnescapeCommand really needs some work -- it should actually do some unescaping\n"));
      86             : 
      87           0 :   CopyUTF16toUTF8(aEscapedCommand, aUnEscapedCommand);
      88           0 :   LOG(("Escaped command: '%s'\n",
      89             :        PromiseFlatCString(aUnEscapedCommand).get()));
      90           0 :   return NS_OK;
      91             : }
      92             : 
      93             : /* Put aSemicolon_iter at the first non-escaped semicolon after
      94             :  * aStart_iter but before aEnd_iter
      95             :  */
      96             : 
      97             : static nsresult
      98           0 : FindSemicolon(nsAString::const_iterator& aSemicolon_iter,
      99             :               const nsAString::const_iterator& aEnd_iter) {
     100           0 :   bool semicolonFound = false;
     101           0 :   while (aSemicolon_iter != aEnd_iter && !semicolonFound) {
     102           0 :     switch(*aSemicolon_iter) {
     103             :     case '\\':
     104           0 :       aSemicolon_iter.advance(2);
     105           0 :       break;
     106             :     case ';':
     107           0 :       semicolonFound = true;
     108           0 :       break;
     109             :     default:
     110           0 :       ++aSemicolon_iter;
     111           0 :       break;
     112             :     }
     113             :   }
     114           0 :   return NS_OK;
     115             : }
     116             : 
     117             : static nsresult
     118           2 : ParseMIMEType(const nsAString::const_iterator& aStart_iter,
     119             :               nsAString::const_iterator& aMajorTypeStart,
     120             :               nsAString::const_iterator& aMajorTypeEnd,
     121             :               nsAString::const_iterator& aMinorTypeStart,
     122             :               nsAString::const_iterator& aMinorTypeEnd,
     123             :               const nsAString::const_iterator& aEnd_iter) {
     124           2 :   nsAString::const_iterator iter(aStart_iter);
     125             : 
     126             :   // skip leading whitespace
     127           2 :   while (iter != aEnd_iter && nsCRT::IsAsciiSpace(*iter)) {
     128           0 :     ++iter;
     129             :   }
     130             : 
     131           2 :   if (iter == aEnd_iter) {
     132           0 :     return NS_ERROR_INVALID_ARG;
     133             :   }
     134             : 
     135           2 :   aMajorTypeStart = iter;
     136             : 
     137             :   // find major/minor separator ('/')
     138          46 :   while (iter != aEnd_iter && *iter != '/') {
     139          22 :     ++iter;
     140             :   }
     141             : 
     142           2 :   if (iter == aEnd_iter) {
     143           0 :     return NS_ERROR_INVALID_ARG;
     144             :   }
     145             : 
     146           2 :   aMajorTypeEnd = iter;
     147             : 
     148             :   // skip '/'
     149           2 :   ++iter;
     150             : 
     151           2 :   if (iter == aEnd_iter) {
     152           0 :     return NS_ERROR_INVALID_ARG;
     153             :   }
     154             : 
     155           2 :   aMinorTypeStart = iter;
     156             : 
     157             :   // find end of minor type, delimited by whitespace or ';'
     158          14 :   while (iter != aEnd_iter && !nsCRT::IsAsciiSpace(*iter) && *iter != ';') {
     159           6 :     ++iter;
     160             :   }
     161             : 
     162           2 :   aMinorTypeEnd = iter;
     163             : 
     164           2 :   return NS_OK;
     165             : }
     166             : 
     167             : // static
     168             : nsresult
     169           6 : nsOSHelperAppService::GetFileLocation(const char* aPrefName,
     170             :                                       const char* aEnvVarName,
     171             :                                       nsAString& aFileLocation) {
     172           6 :   LOG(("-- GetFileLocation.  Pref: '%s'  EnvVar: '%s'\n",
     173             :        aPrefName,
     174             :        aEnvVarName));
     175           6 :   NS_PRECONDITION(aPrefName, "Null pref name passed; don't do that!");
     176             : 
     177           6 :   aFileLocation.Truncate();
     178             :   /* The lookup order is:
     179             :      1) user pref
     180             :      2) env var
     181             :      3) pref
     182             :   */
     183           6 :   NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
     184             : 
     185             :   /*
     186             :     If we have an env var we should check whether the pref is a user
     187             :     pref.  If we do not, we don't care.
     188             :   */
     189           6 :   if (Preferences::HasUserValue(aPrefName) &&
     190           0 :       NS_SUCCEEDED(Preferences::GetString(aPrefName, &aFileLocation))) {
     191           0 :     return NS_OK;
     192             :   }
     193             : 
     194           6 :   if (aEnvVarName && *aEnvVarName) {
     195           2 :     char* prefValue = PR_GetEnv(aEnvVarName);
     196           2 :     if (prefValue && *prefValue) {
     197             :       // the pref is in the system charset and it's a filepath... The
     198             :       // natural way to do the charset conversion is by just initing
     199             :       // an nsIFile with the native path and asking it for the Unicode
     200             :       // version.
     201             :       nsresult rv;
     202           0 :       nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
     203           0 :       NS_ENSURE_SUCCESS(rv, rv);
     204             : 
     205           0 :       rv = file->InitWithNativePath(nsDependentCString(prefValue));
     206           0 :       NS_ENSURE_SUCCESS(rv, rv);
     207             : 
     208           0 :       rv = file->GetPath(aFileLocation);
     209           0 :       NS_ENSURE_SUCCESS(rv, rv);
     210             : 
     211           0 :       return NS_OK;
     212             :     }
     213             :   }
     214             : 
     215           6 :   return Preferences::GetString(aPrefName, &aFileLocation);
     216             : }
     217             : 
     218             : 
     219             : /* Get the mime.types file names from prefs and look up info in them
     220             :    based on extension */
     221             : // static
     222             : nsresult
     223           0 : nsOSHelperAppService::LookUpTypeAndDescription(const nsAString& aFileExtension,
     224             :                                                nsAString& aMajorType,
     225             :                                                nsAString& aMinorType,
     226             :                                                nsAString& aDescription,
     227             :                                                bool aUserData) {
     228           0 :   LOG(("-- LookUpTypeAndDescription for extension '%s'\n",
     229             :        NS_LossyConvertUTF16toASCII(aFileExtension).get()));
     230           0 :   nsresult rv = NS_OK;
     231           0 :   nsAutoString mimeFileName;
     232             : 
     233           0 :   const char* filenamePref = aUserData ?
     234           0 :     "helpers.private_mime_types_file" : "helpers.global_mime_types_file";
     235             : 
     236           0 :   rv = GetFileLocation(filenamePref, nullptr, mimeFileName);
     237           0 :   if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
     238             :     rv = GetTypeAndDescriptionFromMimetypesFile(mimeFileName,
     239             :                                                 aFileExtension,
     240             :                                                 aMajorType,
     241             :                                                 aMinorType,
     242           0 :                                                 aDescription);
     243             :   } else {
     244           0 :     rv = NS_ERROR_NOT_AVAILABLE;
     245             :   }
     246             : 
     247           0 :   return rv;
     248             : }
     249             : 
     250             : inline bool
     251           2 : IsNetscapeFormat(const nsACString& aBuffer) {
     252          10 :   return StringBeginsWith(aBuffer, NS_LITERAL_CSTRING("#--Netscape Communications Corporation MIME Information")) ||
     253           8 :          StringBeginsWith(aBuffer, NS_LITERAL_CSTRING("#--MCOM MIME Information"));
     254             : }
     255             : 
     256             : /*
     257             :  * Create a file stream and line input stream for the filename.
     258             :  * Leaves the first line of the file in aBuffer and sets the format to
     259             :  *  true for netscape files and false for normail ones
     260             :  */
     261             : // static
     262             : nsresult
     263           4 : nsOSHelperAppService::CreateInputStream(const nsAString& aFilename,
     264             :                                         nsIFileInputStream ** aFileInputStream,
     265             :                                         nsILineInputStream ** aLineInputStream,
     266             :                                         nsACString& aBuffer,
     267             :                                         bool * aNetscapeFormat,
     268             :                                         bool * aMore) {
     269           4 :   LOG(("-- CreateInputStream"));
     270           4 :   nsresult rv = NS_OK;
     271             : 
     272           8 :   nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
     273           4 :   if (NS_FAILED(rv))
     274           0 :     return rv;
     275           4 :   rv = file->InitWithPath(aFilename);
     276           4 :   if (NS_FAILED(rv))
     277           0 :     return rv;
     278             : 
     279           8 :   nsCOMPtr<nsIFileInputStream> fileStream(do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
     280           4 :   if (NS_FAILED(rv))
     281           0 :     return rv;
     282           4 :   rv = fileStream->Init(file, -1, -1, false);
     283           4 :   if (NS_FAILED(rv))
     284           2 :     return rv;
     285             : 
     286           4 :   nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
     287             : 
     288           2 :   if (NS_FAILED(rv)) {
     289           0 :     LOG(("Interface trouble in stream land!"));
     290           0 :     return rv;
     291             :   }
     292             : 
     293           2 :   rv = lineStream->ReadLine(aBuffer, aMore);
     294           2 :   if (NS_FAILED(rv)) {
     295           0 :     fileStream->Close();
     296           0 :     return rv;
     297             :   }
     298             : 
     299           2 :   *aNetscapeFormat = IsNetscapeFormat(aBuffer);
     300             : 
     301           2 :   *aFileInputStream = fileStream;
     302           2 :   NS_ADDREF(*aFileInputStream);
     303           2 :   *aLineInputStream = lineStream;
     304           2 :   NS_ADDREF(*aLineInputStream);
     305             : 
     306           2 :   return NS_OK;
     307             : }
     308             : 
     309             : /* Open the file, read the first line, decide what type of file it is,
     310             :    then get info based on extension */
     311             : // static
     312             : nsresult
     313           0 : nsOSHelperAppService::GetTypeAndDescriptionFromMimetypesFile(const nsAString& aFilename,
     314             :                                                              const nsAString& aFileExtension,
     315             :                                                              nsAString& aMajorType,
     316             :                                                              nsAString& aMinorType,
     317             :                                                              nsAString& aDescription) {
     318           0 :   LOG(("-- GetTypeAndDescriptionFromMimetypesFile\n"));
     319           0 :   LOG(("Getting type and description from types file '%s'\n",
     320             :        NS_LossyConvertUTF16toASCII(aFilename).get()));
     321           0 :   LOG(("Using extension '%s'\n",
     322             :        NS_LossyConvertUTF16toASCII(aFileExtension).get()));
     323           0 :   nsresult rv = NS_OK;
     324           0 :   nsCOMPtr<nsIFileInputStream> mimeFile;
     325           0 :   nsCOMPtr<nsILineInputStream> mimeTypes;
     326             :   bool netscapeFormat;
     327           0 :   nsAutoString buf;
     328           0 :   nsAutoCString cBuf;
     329           0 :   bool more = false;
     330           0 :   rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
     331           0 :                          cBuf, &netscapeFormat, &more);
     332             : 
     333           0 :   if (NS_FAILED(rv)) {
     334           0 :     return rv;
     335             :   }
     336             : 
     337           0 :   nsAutoString extensions;
     338           0 :   nsString entry;
     339           0 :   entry.SetCapacity(100);
     340           0 :   nsAString::const_iterator majorTypeStart, majorTypeEnd,
     341           0 :                             minorTypeStart, minorTypeEnd,
     342           0 :                             descriptionStart, descriptionEnd;
     343             : 
     344           0 :   do {
     345           0 :     CopyASCIItoUTF16(cBuf, buf);
     346             :     // read through, building up an entry.  If we finish an entry, check for
     347             :     // a match and return out of the loop if we match
     348             : 
     349             :     // skip comments and empty lines
     350           0 :     if (!buf.IsEmpty() && buf.First() != '#') {
     351           0 :       entry.Append(buf);
     352           0 :       if (entry.Last() == '\\') {
     353           0 :         entry.Truncate(entry.Length() - 1);
     354           0 :         entry.Append(char16_t(' '));  // in case there is no trailing whitespace on this line
     355             :       } else {  // we have a full entry
     356           0 :         LOG(("Current entry: '%s'\n",
     357             :              NS_LossyConvertUTF16toASCII(entry).get()));
     358           0 :         if (netscapeFormat) {
     359             :           rv = ParseNetscapeMIMETypesEntry(entry,
     360             :                                            majorTypeStart, majorTypeEnd,
     361             :                                            minorTypeStart, minorTypeEnd,
     362             :                                            extensions,
     363           0 :                                            descriptionStart, descriptionEnd);
     364           0 :           if (NS_FAILED(rv)) {
     365             :             // We sometimes get things like RealPlayer appending
     366             :             // "normal" entries to "Netscape" .mime.types files.  Try
     367             :             // to handle that.  Bug 106381.
     368           0 :             LOG(("Bogus entry; trying 'normal' mode\n"));
     369             :             rv = ParseNormalMIMETypesEntry(entry,
     370             :                                            majorTypeStart, majorTypeEnd,
     371             :                                            minorTypeStart, minorTypeEnd,
     372             :                                            extensions,
     373           0 :                                            descriptionStart, descriptionEnd);
     374             :           }
     375             :         } else {
     376             :           rv = ParseNormalMIMETypesEntry(entry,
     377             :                                          majorTypeStart, majorTypeEnd,
     378             :                                          minorTypeStart, minorTypeEnd,
     379             :                                          extensions,
     380           0 :                                          descriptionStart, descriptionEnd);
     381           0 :           if (NS_FAILED(rv)) {
     382             :             // We sometimes get things like StarOffice prepending
     383             :             // "normal" entries to "Netscape" .mime.types files.  Try
     384             :             // to handle that.  Bug 136670.
     385           0 :             LOG(("Bogus entry; trying 'Netscape' mode\n"));
     386             :             rv = ParseNetscapeMIMETypesEntry(entry,
     387             :                                              majorTypeStart, majorTypeEnd,
     388             :                                              minorTypeStart, minorTypeEnd,
     389             :                                              extensions,
     390           0 :                                              descriptionStart, descriptionEnd);
     391             :           }
     392             :         }
     393             : 
     394           0 :         if (NS_SUCCEEDED(rv)) { // entry parses
     395           0 :           nsAString::const_iterator start, end;
     396           0 :           extensions.BeginReading(start);
     397           0 :           extensions.EndReading(end);
     398           0 :           nsAString::const_iterator iter(start);
     399             : 
     400           0 :           while (start != end) {
     401           0 :             FindCharInReadable(',', iter, end);
     402           0 :             if (Substring(start, iter).Equals(aFileExtension,
     403           0 :                                               nsCaseInsensitiveStringComparator())) {
     404             :               // it's a match.  Assign the type and description and run
     405           0 :               aMajorType.Assign(Substring(majorTypeStart, majorTypeEnd));
     406           0 :               aMinorType.Assign(Substring(minorTypeStart, minorTypeEnd));
     407           0 :               aDescription.Assign(Substring(descriptionStart, descriptionEnd));
     408           0 :               mimeFile->Close();
     409           0 :               return NS_OK;
     410             :             }
     411           0 :             if (iter != end) {
     412           0 :               ++iter;
     413             :             }
     414           0 :             start = iter;
     415             :           }
     416             :         } else {
     417           0 :           LOG(("Failed to parse entry: %s\n", NS_LossyConvertUTF16toASCII(entry).get()));
     418             :         }
     419             :         // truncate the entry for the next iteration
     420           0 :         entry.Truncate();
     421             :       }
     422             :     }
     423           0 :     if (!more) {
     424           0 :       rv = NS_ERROR_NOT_AVAILABLE;
     425           0 :       break;
     426             :     }
     427             :     // read the next line
     428           0 :     rv = mimeTypes->ReadLine(cBuf, &more);
     429           0 :   } while (NS_SUCCEEDED(rv));
     430             : 
     431           0 :   mimeFile->Close();
     432           0 :   return rv;
     433             : }
     434             : 
     435             : /* Get the mime.types file names from prefs and look up info in them
     436             :    based on mimetype  */
     437             : // static
     438             : nsresult
     439           2 : nsOSHelperAppService::LookUpExtensionsAndDescription(const nsAString& aMajorType,
     440             :                                                      const nsAString& aMinorType,
     441             :                                                      nsAString& aFileExtensions,
     442             :                                                      nsAString& aDescription) {
     443           2 :   LOG(("-- LookUpExtensionsAndDescription for type '%s/%s'\n",
     444             :        NS_LossyConvertUTF16toASCII(aMajorType).get(),
     445             :        NS_LossyConvertUTF16toASCII(aMinorType).get()));
     446           2 :   nsresult rv = NS_OK;
     447           4 :   nsAutoString mimeFileName;
     448             : 
     449           2 :   rv = GetFileLocation("helpers.private_mime_types_file", nullptr, mimeFileName);
     450           2 :   if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
     451             :     rv = GetExtensionsAndDescriptionFromMimetypesFile(mimeFileName,
     452             :                                                       aMajorType,
     453             :                                                       aMinorType,
     454             :                                                       aFileExtensions,
     455           2 :                                                       aDescription);
     456             :   } else {
     457           0 :     rv = NS_ERROR_NOT_AVAILABLE;
     458             :   }
     459           2 :   if (NS_FAILED(rv) || aFileExtensions.IsEmpty()) {
     460             :     rv = GetFileLocation("helpers.global_mime_types_file",
     461           2 :                          nullptr, mimeFileName);
     462           2 :     if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
     463             :       rv = GetExtensionsAndDescriptionFromMimetypesFile(mimeFileName,
     464             :                                                         aMajorType,
     465             :                                                         aMinorType,
     466             :                                                         aFileExtensions,
     467           2 :                                                         aDescription);
     468             :     } else {
     469           0 :       rv = NS_ERROR_NOT_AVAILABLE;
     470             :     }
     471             :   }
     472           4 :   return rv;
     473             : }
     474             : 
     475             : /* Open the file, read the first line, decide what type of file it is,
     476             :    then get info based on extension */
     477             : // static
     478             : nsresult
     479           4 : nsOSHelperAppService::GetExtensionsAndDescriptionFromMimetypesFile(const nsAString& aFilename,
     480             :                                                                    const nsAString& aMajorType,
     481             :                                                                    const nsAString& aMinorType,
     482             :                                                                    nsAString& aFileExtensions,
     483             :                                                                    nsAString& aDescription) {
     484           4 :   LOG(("-- GetExtensionsAndDescriptionFromMimetypesFile\n"));
     485           4 :   LOG(("Getting extensions and description from types file '%s'\n",
     486             :        NS_LossyConvertUTF16toASCII(aFilename).get()));
     487           4 :   LOG(("Using type '%s/%s'\n",
     488             :        NS_LossyConvertUTF16toASCII(aMajorType).get(),
     489             :        NS_LossyConvertUTF16toASCII(aMinorType).get()));
     490             : 
     491           4 :   nsresult rv = NS_OK;
     492           8 :   nsCOMPtr<nsIFileInputStream> mimeFile;
     493           8 :   nsCOMPtr<nsILineInputStream> mimeTypes;
     494             :   bool netscapeFormat;
     495           8 :   nsAutoCString cBuf;
     496           8 :   nsAutoString buf;
     497           4 :   bool more = false;
     498           8 :   rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
     499           4 :                          cBuf, &netscapeFormat, &more);
     500             : 
     501           4 :   if (NS_FAILED(rv)) {
     502           2 :     return rv;
     503             :   }
     504             : 
     505           4 :   nsAutoString extensions;
     506           4 :   nsString entry;
     507           2 :   entry.SetCapacity(100);
     508           2 :   nsAString::const_iterator majorTypeStart, majorTypeEnd,
     509           2 :                             minorTypeStart, minorTypeEnd,
     510           2 :                             descriptionStart, descriptionEnd;
     511             : 
     512         192 :   do {
     513         194 :     CopyASCIItoUTF16(cBuf, buf);
     514             :     // read through, building up an entry.  If we finish an entry, check for
     515             :     // a match and return out of the loop if we match
     516             : 
     517             :     // skip comments and empty lines
     518         194 :     if (!buf.IsEmpty() && buf.First() != '#') {
     519         144 :       entry.Append(buf);
     520         144 :       if (entry.Last() == '\\') {
     521           0 :         entry.Truncate(entry.Length() - 1);
     522           0 :         entry.Append(char16_t(' '));  // in case there is no trailing whitespace on this line
     523             :       } else {  // we have a full entry
     524         144 :         LOG(("Current entry: '%s'\n",
     525             :              NS_LossyConvertUTF16toASCII(entry).get()));
     526         144 :         if (netscapeFormat) {
     527             :           rv = ParseNetscapeMIMETypesEntry(entry,
     528             :                                            majorTypeStart, majorTypeEnd,
     529             :                                            minorTypeStart, minorTypeEnd,
     530             :                                            extensions,
     531           0 :                                            descriptionStart, descriptionEnd);
     532             : 
     533           0 :           if (NS_FAILED(rv)) {
     534             :             // We sometimes get things like RealPlayer appending
     535             :             // "normal" entries to "Netscape" .mime.types files.  Try
     536             :             // to handle that.  Bug 106381.
     537           0 :             LOG(("Bogus entry; trying 'normal' mode\n"));
     538             :             rv = ParseNormalMIMETypesEntry(entry,
     539             :                                            majorTypeStart, majorTypeEnd,
     540             :                                            minorTypeStart, minorTypeEnd,
     541             :                                            extensions,
     542           0 :                                            descriptionStart, descriptionEnd);
     543             :           }
     544             :         } else {
     545             :           rv = ParseNormalMIMETypesEntry(entry,
     546             :                                          majorTypeStart, majorTypeEnd,
     547             :                                          minorTypeStart,
     548             :                                          minorTypeEnd, extensions,
     549         144 :                                          descriptionStart, descriptionEnd);
     550             : 
     551         144 :           if (NS_FAILED(rv)) {
     552             :             // We sometimes get things like StarOffice prepending
     553             :             // "normal" entries to "Netscape" .mime.types files.  Try
     554             :             // to handle that.  Bug 136670.
     555           0 :             LOG(("Bogus entry; trying 'Netscape' mode\n"));
     556             :             rv = ParseNetscapeMIMETypesEntry(entry,
     557             :                                              majorTypeStart, majorTypeEnd,
     558             :                                              minorTypeStart, minorTypeEnd,
     559             :                                              extensions,
     560           0 :                                              descriptionStart, descriptionEnd);
     561             :           }
     562             :         }
     563             : 
     564         864 :         if (NS_SUCCEEDED(rv) &&
     565         288 :             Substring(majorTypeStart,
     566         288 :                       majorTypeEnd).Equals(aMajorType,
     567        1008 :                                            nsCaseInsensitiveStringComparator())&&
     568         288 :             Substring(minorTypeStart,
     569         288 :                       minorTypeEnd).Equals(aMinorType,
     570         288 :                                            nsCaseInsensitiveStringComparator())) {
     571             :           // it's a match
     572           2 :           aFileExtensions.Assign(extensions);
     573           2 :           aDescription.Assign(Substring(descriptionStart, descriptionEnd));
     574           2 :           mimeFile->Close();
     575           2 :           return NS_OK;
     576             :         }
     577         142 :         if (NS_FAILED(rv)) {
     578           0 :           LOG(("Failed to parse entry: %s\n", NS_LossyConvertUTF16toASCII(entry).get()));
     579             :         }
     580             : 
     581         142 :         entry.Truncate();
     582             :       }
     583             :     }
     584         192 :     if (!more) {
     585           0 :       rv = NS_ERROR_NOT_AVAILABLE;
     586           0 :       break;
     587             :     }
     588             :     // read the next line
     589         192 :     rv = mimeTypes->ReadLine(cBuf, &more);
     590         192 :   } while (NS_SUCCEEDED(rv));
     591             : 
     592           0 :   mimeFile->Close();
     593           0 :   return rv;
     594             : }
     595             : 
     596             : /*
     597             :  * This parses a Netscape format mime.types entry.  There are two
     598             :  * possible formats:
     599             :  *
     600             :  * type=foo/bar; options exts="baz" description="Some type"
     601             :  *
     602             :  * and
     603             :  *
     604             :  * type=foo/bar; options description="Some type" exts="baz"
     605             :  */
     606             : // static
     607             : nsresult
     608           0 : nsOSHelperAppService::ParseNetscapeMIMETypesEntry(const nsAString& aEntry,
     609             :                                                   nsAString::const_iterator& aMajorTypeStart,
     610             :                                                   nsAString::const_iterator& aMajorTypeEnd,
     611             :                                                   nsAString::const_iterator& aMinorTypeStart,
     612             :                                                   nsAString::const_iterator& aMinorTypeEnd,
     613             :                                                   nsAString& aExtensions,
     614             :                                                   nsAString::const_iterator& aDescriptionStart,
     615             :                                                   nsAString::const_iterator& aDescriptionEnd) {
     616           0 :   LOG(("-- ParseNetscapeMIMETypesEntry\n"));
     617           0 :   NS_ASSERTION(!aEntry.IsEmpty(), "Empty Netscape MIME types entry being parsed.");
     618             : 
     619           0 :   nsAString::const_iterator start_iter, end_iter, match_start, match_end;
     620             : 
     621           0 :   aEntry.BeginReading(start_iter);
     622           0 :   aEntry.EndReading(end_iter);
     623             : 
     624             :   // skip trailing whitespace
     625           0 :   do {
     626           0 :     --end_iter;
     627           0 :   } while (end_iter != start_iter &&
     628           0 :            nsCRT::IsAsciiSpace(*end_iter));
     629             :   // if we're pointing to a quote, don't advance -- we don't want to
     630             :   // include the quote....
     631           0 :   if (*end_iter != '"')
     632           0 :     ++end_iter;
     633           0 :   match_start = start_iter;
     634           0 :   match_end = end_iter;
     635             : 
     636             :   // Get the major and minor types
     637             :   // First the major type
     638           0 :   if (! FindInReadable(NS_LITERAL_STRING("type="), match_start, match_end)) {
     639           0 :     return NS_ERROR_FAILURE;
     640             :   }
     641             : 
     642           0 :   match_start = match_end;
     643             : 
     644           0 :   while (match_end != end_iter &&
     645           0 :          *match_end != '/') {
     646           0 :     ++match_end;
     647             :   }
     648           0 :   if (match_end == end_iter) {
     649           0 :     return NS_ERROR_FAILURE;
     650             :   }
     651             : 
     652           0 :   aMajorTypeStart = match_start;
     653           0 :   aMajorTypeEnd = match_end;
     654             : 
     655             :   // now the minor type
     656           0 :   if (++match_end == end_iter) {
     657           0 :     return NS_ERROR_FAILURE;
     658             :   }
     659             : 
     660           0 :   match_start = match_end;
     661             : 
     662           0 :   while (match_end != end_iter &&
     663           0 :          !nsCRT::IsAsciiSpace(*match_end) &&
     664           0 :          *match_end != ';') {
     665           0 :     ++match_end;
     666             :   }
     667           0 :   if (match_end == end_iter) {
     668           0 :     return NS_ERROR_FAILURE;
     669             :   }
     670             : 
     671           0 :   aMinorTypeStart = match_start;
     672           0 :   aMinorTypeEnd = match_end;
     673             : 
     674             :   // ignore everything up to the end of the mime type from here on
     675           0 :   start_iter = match_end;
     676             : 
     677             :   // get the extensions
     678           0 :   match_start = match_end;
     679           0 :   match_end = end_iter;
     680           0 :   if (FindInReadable(NS_LITERAL_STRING("exts="), match_start, match_end)) {
     681           0 :     nsAString::const_iterator extStart, extEnd;
     682             : 
     683           0 :     if (match_end == end_iter ||
     684           0 :         (*match_end == '"' && ++match_end == end_iter)) {
     685           0 :       return NS_ERROR_FAILURE;
     686             :     }
     687             : 
     688           0 :     extStart = match_end;
     689           0 :     match_start = extStart;
     690           0 :     match_end = end_iter;
     691           0 :     if (FindInReadable(NS_LITERAL_STRING("desc=\""), match_start, match_end)) {
     692             :       // exts= before desc=, so we have to find the actual end of the extensions
     693           0 :       extEnd = match_start;
     694           0 :       if (extEnd == extStart) {
     695           0 :         return NS_ERROR_FAILURE;
     696             :       }
     697             : 
     698           0 :       do {
     699           0 :         --extEnd;
     700           0 :       } while (extEnd != extStart &&
     701           0 :                nsCRT::IsAsciiSpace(*extEnd));
     702             : 
     703           0 :       if (extEnd != extStart && *extEnd == '"') {
     704           0 :         --extEnd;
     705             :       }
     706             :     } else {
     707             :       // desc= before exts=, so we can use end_iter as the end of the extensions
     708           0 :       extEnd = end_iter;
     709             :     }
     710           0 :     aExtensions = Substring(extStart, extEnd);
     711             :   } else {
     712             :     // no extensions
     713           0 :     aExtensions.Truncate();
     714             :   }
     715             : 
     716             :   // get the description
     717           0 :   match_start = start_iter;
     718           0 :   match_end = end_iter;
     719           0 :   if (FindInReadable(NS_LITERAL_STRING("desc=\""), match_start, match_end)) {
     720           0 :     aDescriptionStart = match_end;
     721           0 :     match_start = aDescriptionStart;
     722           0 :     match_end = end_iter;
     723           0 :     if (FindInReadable(NS_LITERAL_STRING("exts="), match_start, match_end)) {
     724             :       // exts= after desc=, so have to find actual end of description
     725           0 :       aDescriptionEnd = match_start;
     726           0 :       if (aDescriptionEnd == aDescriptionStart) {
     727           0 :         return NS_ERROR_FAILURE;
     728             :       }
     729             : 
     730           0 :       do {
     731           0 :         --aDescriptionEnd;
     732           0 :       } while (aDescriptionEnd != aDescriptionStart &&
     733           0 :                nsCRT::IsAsciiSpace(*aDescriptionEnd));
     734             :     } else {
     735             :       // desc= after exts=, so use end_iter for the description end
     736           0 :       aDescriptionEnd = end_iter;
     737             :     }
     738             :   } else {
     739             :     // no description
     740           0 :     aDescriptionStart = start_iter;
     741           0 :     aDescriptionEnd = start_iter;
     742             :   }
     743             : 
     744           0 :   return NS_OK;
     745             : }
     746             : 
     747             : /*
     748             :  * This parses a normal format mime.types entry.  The format is:
     749             :  *
     750             :  * major/minor    ext1 ext2 ext3
     751             :  */
     752             : // static
     753             : nsresult
     754         144 : nsOSHelperAppService::ParseNormalMIMETypesEntry(const nsAString& aEntry,
     755             :                                                 nsAString::const_iterator& aMajorTypeStart,
     756             :                                                 nsAString::const_iterator& aMajorTypeEnd,
     757             :                                                 nsAString::const_iterator& aMinorTypeStart,
     758             :                                                 nsAString::const_iterator& aMinorTypeEnd,
     759             :                                                 nsAString& aExtensions,
     760             :                                                 nsAString::const_iterator& aDescriptionStart,
     761             :                                                 nsAString::const_iterator& aDescriptionEnd) {
     762         144 :   LOG(("-- ParseNormalMIMETypesEntry\n"));
     763         144 :   NS_ASSERTION(!aEntry.IsEmpty(), "Empty Normal MIME types entry being parsed.");
     764             : 
     765         144 :   nsAString::const_iterator start_iter, end_iter, iter;
     766             : 
     767         144 :   aEntry.BeginReading(start_iter);
     768         144 :   aEntry.EndReading(end_iter);
     769             : 
     770             :   // no description
     771         144 :   aDescriptionStart = start_iter;
     772         144 :   aDescriptionEnd = start_iter;
     773             : 
     774             :   // skip leading whitespace
     775         144 :   while (start_iter != end_iter && nsCRT::IsAsciiSpace(*start_iter)) {
     776           0 :     ++start_iter;
     777             :   }
     778         144 :   if (start_iter == end_iter) {
     779           0 :     return NS_ERROR_FAILURE;
     780             :   }
     781             :   // skip trailing whitespace
     782         144 :   do {
     783         144 :     --end_iter;
     784         144 :   } while (end_iter != start_iter && nsCRT::IsAsciiSpace(*end_iter));
     785             : 
     786         144 :   ++end_iter; // point to first whitespace char (or to end of string)
     787         144 :   iter = start_iter;
     788             : 
     789             :   // get the major type
     790         144 :   if (! FindCharInReadable('/', iter, end_iter))
     791           0 :     return NS_ERROR_FAILURE;
     792             : 
     793         144 :   nsAString::const_iterator equals_sign_iter(start_iter);
     794         144 :   if (FindCharInReadable('=', equals_sign_iter, iter))
     795           0 :     return NS_ERROR_FAILURE; // see bug 136670
     796             : 
     797         144 :   aMajorTypeStart = start_iter;
     798         144 :   aMajorTypeEnd = iter;
     799             : 
     800             :   // get the minor type
     801         144 :   if (++iter == end_iter) {
     802           0 :     return NS_ERROR_FAILURE;
     803             :   }
     804         144 :   start_iter = iter;
     805             : 
     806        2608 :   while (iter != end_iter && !nsCRT::IsAsciiSpace(*iter)) {
     807        1232 :     ++iter;
     808             :   }
     809         144 :   aMinorTypeStart = start_iter;
     810         144 :   aMinorTypeEnd = iter;
     811             : 
     812             :   // get the extensions
     813         144 :   aExtensions.Truncate();
     814         324 :   while (iter != end_iter) {
     815         682 :     while (iter != end_iter && nsCRT::IsAsciiSpace(*iter)) {
     816         296 :       ++iter;
     817             :     }
     818             : 
     819          90 :     start_iter = iter;
     820         734 :     while (iter != end_iter && !nsCRT::IsAsciiSpace(*iter)) {
     821         322 :       ++iter;
     822             :     }
     823          90 :     aExtensions.Append(Substring(start_iter, iter));
     824          90 :     if (iter != end_iter) { // not the last extension
     825          18 :       aExtensions.Append(char16_t(','));
     826             :     }
     827             :   }
     828             : 
     829         144 :   return NS_OK;
     830             : }
     831             : 
     832             : // static
     833             : nsresult
     834           0 : nsOSHelperAppService::LookUpHandlerAndDescription(const nsAString& aMajorType,
     835             :                                                   const nsAString& aMinorType,
     836             :                                                   nsAString& aHandler,
     837             :                                                   nsAString& aDescription,
     838             :                                                   nsAString& aMozillaFlags) {
     839             : 
     840             :   // The mailcap lookup is two-pass to handle the case of mailcap files
     841             :   // that have something like:
     842             :   //
     843             :   // text/*; emacs %s
     844             :   // text/rtf; soffice %s
     845             :   //
     846             :   // in that order.  We want to pick up "soffice" for text/rtf in such cases
     847             :   nsresult rv = DoLookUpHandlerAndDescription(aMajorType,
     848             :                                               aMinorType,
     849             :                                               aHandler,
     850             :                                               aDescription,
     851             :                                               aMozillaFlags,
     852           0 :                                               true);
     853           0 :   if (NS_FAILED(rv)) {
     854             :     rv = DoLookUpHandlerAndDescription(aMajorType,
     855             :                                        aMinorType,
     856             :                                        aHandler,
     857             :                                        aDescription,
     858             :                                        aMozillaFlags,
     859           0 :                                        false);
     860             :   }
     861             : 
     862             :   // maybe we have an entry for "aMajorType/*"?
     863           0 :   if (NS_FAILED(rv)) {
     864           0 :     rv = DoLookUpHandlerAndDescription(aMajorType,
     865           0 :                                        NS_LITERAL_STRING("*"),
     866             :                                        aHandler,
     867             :                                        aDescription,
     868             :                                        aMozillaFlags,
     869           0 :                                        true);
     870             :   }
     871             : 
     872           0 :   if (NS_FAILED(rv)) {
     873           0 :     rv = DoLookUpHandlerAndDescription(aMajorType,
     874           0 :                                        NS_LITERAL_STRING("*"),
     875             :                                        aHandler,
     876             :                                        aDescription,
     877             :                                        aMozillaFlags,
     878           0 :                                        false);
     879             :   }
     880             : 
     881           0 :   return rv;
     882             : }
     883             : 
     884             : // static
     885             : nsresult
     886           2 : nsOSHelperAppService::DoLookUpHandlerAndDescription(const nsAString& aMajorType,
     887             :                                                     const nsAString& aMinorType,
     888             :                                                     nsAString& aHandler,
     889             :                                                     nsAString& aDescription,
     890             :                                                     nsAString& aMozillaFlags,
     891             :                                                     bool aUserData) {
     892           2 :   LOG(("-- LookUpHandlerAndDescription for type '%s/%s'\n",
     893             :        NS_LossyConvertUTF16toASCII(aMajorType).get(),
     894             :        NS_LossyConvertUTF16toASCII(aMinorType).get()));
     895           2 :   nsresult rv = NS_OK;
     896           4 :   nsAutoString mailcapFileName;
     897             : 
     898           2 :   const char * filenamePref = aUserData ?
     899           2 :     "helpers.private_mailcap_file" : "helpers.global_mailcap_file";
     900           2 :   const char * filenameEnvVar = aUserData ?
     901           2 :     "PERSONAL_MAILCAP" : "MAILCAP";
     902             : 
     903           2 :   rv = GetFileLocation(filenamePref, filenameEnvVar, mailcapFileName);
     904           2 :   if (NS_SUCCEEDED(rv) && !mailcapFileName.IsEmpty()) {
     905             :     rv = GetHandlerAndDescriptionFromMailcapFile(mailcapFileName,
     906             :                                                  aMajorType,
     907             :                                                  aMinorType,
     908             :                                                  aHandler,
     909             :                                                  aDescription,
     910           2 :                                                  aMozillaFlags);
     911             :   } else {
     912           0 :     rv = NS_ERROR_NOT_AVAILABLE;
     913             :   }
     914             : 
     915           4 :   return rv;
     916             : }
     917             : 
     918             : // static
     919             : nsresult
     920           2 : nsOSHelperAppService::GetHandlerAndDescriptionFromMailcapFile(const nsAString& aFilename,
     921             :                                                               const nsAString& aMajorType,
     922             :                                                               const nsAString& aMinorType,
     923             :                                                               nsAString& aHandler,
     924             :                                                               nsAString& aDescription,
     925             :                                                               nsAString& aMozillaFlags) {
     926             : 
     927           2 :   LOG(("-- GetHandlerAndDescriptionFromMailcapFile\n"));
     928           2 :   LOG(("Getting handler and description from mailcap file '%s'\n",
     929             :        NS_LossyConvertUTF16toASCII(aFilename).get()));
     930           2 :   LOG(("Using type '%s/%s'\n",
     931             :        NS_LossyConvertUTF16toASCII(aMajorType).get(),
     932             :        NS_LossyConvertUTF16toASCII(aMinorType).get()));
     933             : 
     934           2 :   nsresult rv = NS_OK;
     935           2 :   bool more = false;
     936             : 
     937           4 :   nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
     938           2 :   if (NS_FAILED(rv))
     939           0 :     return rv;
     940           2 :   rv = file->InitWithPath(aFilename);
     941           2 :   if (NS_FAILED(rv))
     942           0 :     return rv;
     943             : 
     944           4 :   nsCOMPtr<nsIFileInputStream> mailcapFile(do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
     945           2 :   if (NS_FAILED(rv))
     946           0 :     return rv;
     947           2 :   rv = mailcapFile->Init(file, -1, -1, false);
     948           2 :   if (NS_FAILED(rv))
     949           2 :     return rv;
     950             : 
     951           0 :   nsCOMPtr<nsILineInputStream> mailcap (do_QueryInterface(mailcapFile, &rv));
     952             : 
     953           0 :   if (NS_FAILED(rv)) {
     954           0 :     LOG(("Interface trouble in stream land!"));
     955           0 :     return rv;
     956             :   }
     957             : 
     958           0 :   nsString entry, buffer;
     959           0 :   nsAutoCString cBuffer;
     960           0 :   entry.SetCapacity(128);
     961           0 :   cBuffer.SetCapacity(80);
     962           0 :   rv = mailcap->ReadLine(cBuffer, &more);
     963           0 :   if (NS_FAILED(rv)) {
     964           0 :     mailcapFile->Close();
     965           0 :     return rv;
     966             :   }
     967             : 
     968           0 :   do {  // return on end-of-file in the loop
     969             : 
     970           0 :     CopyASCIItoUTF16(cBuffer, buffer);
     971           0 :     if (!buffer.IsEmpty() && buffer.First() != '#') {
     972           0 :       entry.Append(buffer);
     973           0 :       if (entry.Last() == '\\') {  // entry continues on next line
     974           0 :         entry.Truncate(entry.Length()-1);
     975           0 :         entry.Append(char16_t(' ')); // in case there is no trailing whitespace on this line
     976             :       } else {  // we have a full entry in entry.  Check it for the type
     977           0 :         LOG(("Current entry: '%s'\n",
     978             :              NS_LossyConvertUTF16toASCII(entry).get()));
     979             : 
     980           0 :         nsAString::const_iterator semicolon_iter,
     981           0 :                                   start_iter, end_iter,
     982           0 :                                   majorTypeStart, majorTypeEnd,
     983           0 :                                   minorTypeStart, minorTypeEnd;
     984           0 :         entry.BeginReading(start_iter);
     985           0 :         entry.EndReading(end_iter);
     986           0 :         semicolon_iter = start_iter;
     987           0 :         FindSemicolon(semicolon_iter, end_iter);
     988           0 :         if (semicolon_iter != end_iter) { // we have something resembling a valid entry
     989           0 :           rv = ParseMIMEType(start_iter, majorTypeStart, majorTypeEnd,
     990             :                              minorTypeStart, minorTypeEnd, semicolon_iter);
     991           0 :           if (NS_SUCCEEDED(rv) &&
     992           0 :               Substring(majorTypeStart,
     993           0 :                         majorTypeEnd).Equals(aMajorType,
     994           0 :                                              nsCaseInsensitiveStringComparator()) &&
     995           0 :               Substring(minorTypeStart,
     996           0 :                         minorTypeEnd).Equals(aMinorType,
     997           0 :                                              nsCaseInsensitiveStringComparator())) { // we have a match
     998           0 :             bool match = true;
     999           0 :             ++semicolon_iter;             // point at the first char past the semicolon
    1000           0 :             start_iter = semicolon_iter;  // handler string starts here
    1001           0 :             FindSemicolon(semicolon_iter, end_iter);
    1002           0 :             while (start_iter != semicolon_iter &&
    1003           0 :                    nsCRT::IsAsciiSpace(*start_iter)) {
    1004           0 :               ++start_iter;
    1005             :             }
    1006             : 
    1007           0 :             LOG(("The real handler is: '%s'\n",
    1008             :                  NS_LossyConvertUTF16toASCII(Substring(start_iter,
    1009             :                                                       semicolon_iter)).get()));
    1010             : 
    1011             :             // XXX ugly hack.  Just grab the executable name
    1012           0 :             nsAString::const_iterator end_handler_iter = semicolon_iter;
    1013           0 :             nsAString::const_iterator end_executable_iter = start_iter;
    1014           0 :             while (end_executable_iter != end_handler_iter &&
    1015           0 :                    !nsCRT::IsAsciiSpace(*end_executable_iter)) {
    1016           0 :               ++end_executable_iter;
    1017             :             }
    1018             :             // XXX End ugly hack
    1019             : 
    1020           0 :             aHandler = Substring(start_iter, end_executable_iter);
    1021             : 
    1022           0 :             nsAString::const_iterator start_option_iter, end_optionname_iter, equal_sign_iter;
    1023             :             bool equalSignFound;
    1024           0 :             while (match &&
    1025           0 :                    semicolon_iter != end_iter &&
    1026           0 :                    ++semicolon_iter != end_iter) { // there are options left and we still match
    1027           0 :               start_option_iter = semicolon_iter;
    1028             :               // skip over leading whitespace
    1029           0 :               while (start_option_iter != end_iter &&
    1030           0 :                      nsCRT::IsAsciiSpace(*start_option_iter)) {
    1031           0 :                 ++start_option_iter;
    1032             :               }
    1033           0 :               if (start_option_iter == end_iter) { // nothing actually here
    1034           0 :                 break;
    1035             :               }
    1036           0 :               semicolon_iter = start_option_iter;
    1037           0 :               FindSemicolon(semicolon_iter, end_iter);
    1038           0 :               equal_sign_iter = start_option_iter;
    1039           0 :               equalSignFound = false;
    1040           0 :               while (equal_sign_iter != semicolon_iter && !equalSignFound) {
    1041           0 :                 switch(*equal_sign_iter) {
    1042             :                 case '\\':
    1043           0 :                   equal_sign_iter.advance(2);
    1044           0 :                   break;
    1045             :                 case '=':
    1046           0 :                   equalSignFound = true;
    1047           0 :                   break;
    1048             :                 default:
    1049           0 :                   ++equal_sign_iter;
    1050           0 :                   break;
    1051             :                 }
    1052             :               }
    1053           0 :               end_optionname_iter = start_option_iter;
    1054             :               // find end of option name
    1055           0 :               while (end_optionname_iter != equal_sign_iter &&
    1056           0 :                      !nsCRT::IsAsciiSpace(*end_optionname_iter)) {
    1057           0 :                 ++end_optionname_iter;
    1058             :               }
    1059           0 :               nsDependentSubstring optionName(start_option_iter, end_optionname_iter);
    1060           0 :               if (equalSignFound) {
    1061             :                 // This is an option that has a name and value
    1062           0 :                 if (optionName.EqualsLiteral("description")) {
    1063           0 :                   aDescription = Substring(++equal_sign_iter, semicolon_iter);
    1064           0 :                 } else if (optionName.EqualsLiteral("x-mozilla-flags")) {
    1065           0 :                   aMozillaFlags = Substring(++equal_sign_iter, semicolon_iter);
    1066           0 :                 } else if (optionName.EqualsLiteral("test")) {
    1067           0 :                   nsAutoCString testCommand;
    1068           0 :                   rv = UnescapeCommand(Substring(++equal_sign_iter, semicolon_iter),
    1069             :                                        aMajorType,
    1070             :                                        aMinorType,
    1071             :                                        testCommand);
    1072           0 :                   if (NS_FAILED(rv))
    1073           0 :                     continue;
    1074           0 :                   nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID, &rv);
    1075           0 :                   if (NS_FAILED(rv))
    1076           0 :                     continue;
    1077           0 :                   nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
    1078           0 :                   if (NS_FAILED(rv))
    1079           0 :                     continue;
    1080           0 :                   rv = file->InitWithNativePath(NS_LITERAL_CSTRING("/bin/sh"));
    1081           0 :                   if (NS_FAILED(rv))
    1082           0 :                     continue;
    1083           0 :                   rv = process->Init(file);
    1084           0 :                   if (NS_FAILED(rv))
    1085           0 :                     continue;
    1086           0 :                   const char *args[] = { "-c", testCommand.get() };
    1087           0 :                   LOG(("Running Test: %s\n", testCommand.get()));
    1088           0 :                   rv = process->Run(true, args, 2);
    1089           0 :                   if (NS_FAILED(rv))
    1090           0 :                     continue;
    1091             :                   int32_t exitValue;
    1092           0 :                   rv = process->GetExitValue(&exitValue);
    1093           0 :                   if (NS_FAILED(rv))
    1094           0 :                     continue;
    1095           0 :                   LOG(("Exit code: %d\n", exitValue));
    1096           0 :                   if (exitValue) {
    1097           0 :                     match = false;
    1098             :                   }
    1099             :                 }
    1100             :               } else {
    1101             :                 // This is an option that just has a name but no value (eg "copiousoutput")
    1102           0 :                 if (optionName.EqualsLiteral("needsterminal")) {
    1103           0 :                   match = false;
    1104             :                 }
    1105             :               }
    1106             :             }
    1107             : 
    1108             : 
    1109           0 :             if (match) { // we did not fail any test clauses; all is good
    1110             :               // get out of here
    1111           0 :               mailcapFile->Close();
    1112           0 :               return NS_OK;
    1113             :             }
    1114             :             // pretend that this match never happened
    1115           0 :             aDescription.Truncate();
    1116           0 :             aMozillaFlags.Truncate();
    1117           0 :             aHandler.Truncate();
    1118             :           }
    1119             :         }
    1120             :         // zero out the entry for the next cycle
    1121           0 :         entry.Truncate();
    1122             :       }
    1123             :     }
    1124           0 :     if (!more) {
    1125           0 :       rv = NS_ERROR_NOT_AVAILABLE;
    1126           0 :       break;
    1127             :     }
    1128           0 :     rv = mailcap->ReadLine(cBuffer, &more);
    1129           0 :   } while (NS_SUCCEEDED(rv));
    1130           0 :   mailcapFile->Close();
    1131           0 :   return rv;
    1132             : }
    1133             : 
    1134           0 : nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists)
    1135             : {
    1136           0 :   LOG(("-- nsOSHelperAppService::OSProtocolHandlerExists for '%s'\n",
    1137             :        aProtocolScheme));
    1138           0 :   *aHandlerExists = false;
    1139             : 
    1140             : #if defined(MOZ_ENABLE_CONTENTACTION)
    1141             :   // libcontentaction requires character ':' after scheme
    1142             :   ContentAction::Action action =
    1143             :     ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
    1144             : 
    1145             :   if (action.isValid())
    1146             :     *aHandlerExists = true;
    1147             : #endif
    1148             : 
    1149             : #ifdef MOZ_WIDGET_GTK
    1150             :   // Check the GNOME registry for a protocol handler
    1151           0 :   *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
    1152             : #endif
    1153             : 
    1154           0 :   return NS_OK;
    1155             : }
    1156             : 
    1157           0 : NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
    1158             : {
    1159             : #ifdef MOZ_WIDGET_GTK
    1160           0 :   nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
    1161           0 :   return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
    1162             : #else
    1163             :   return NS_ERROR_NOT_AVAILABLE;
    1164             : #endif
    1165             : }
    1166             : 
    1167           0 : nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * platformAppPath, nsIFile ** aFile)
    1168             : {
    1169           0 :   LOG(("-- nsOSHelperAppService::GetFileTokenForPath: '%s'\n",
    1170             :        NS_LossyConvertUTF16toASCII(platformAppPath).get()));
    1171           0 :   if (! *platformAppPath) { // empty filename--return error
    1172           0 :     NS_WARNING("Empty filename passed in.");
    1173           0 :     return NS_ERROR_INVALID_ARG;
    1174             :   }
    1175             : 
    1176             :   // first check if the base class implementation finds anything
    1177           0 :   nsresult rv = nsExternalHelperAppService::GetFileTokenForPath(platformAppPath, aFile);
    1178           0 :   if (NS_SUCCEEDED(rv))
    1179           0 :     return rv;
    1180             :   // If the reason for failure was that the file doesn't exist, return too
    1181             :   // (because it means the path was absolute, and so that we shouldn't search in
    1182             :   // the path)
    1183           0 :   if (rv == NS_ERROR_FILE_NOT_FOUND)
    1184           0 :     return rv;
    1185             : 
    1186             :   // If we get here, we really should have a relative path.
    1187           0 :   NS_ASSERTION(*platformAppPath != char16_t('/'), "Unexpected absolute path");
    1188             : 
    1189           0 :   nsCOMPtr<nsIFile> localFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
    1190             : 
    1191           0 :   if (!localFile) return NS_ERROR_NOT_INITIALIZED;
    1192             : 
    1193           0 :   bool exists = false;
    1194             :   // ugly hack.  Walk the PATH variable...
    1195           0 :   char* unixpath = PR_GetEnv("PATH");
    1196           0 :   nsAutoCString path(unixpath);
    1197             : 
    1198           0 :   const char* start_iter = path.BeginReading(start_iter);
    1199           0 :   const char* colon_iter = start_iter;
    1200           0 :   const char* end_iter = path.EndReading(end_iter);
    1201             : 
    1202           0 :   while (start_iter != end_iter && !exists) {
    1203           0 :     while (colon_iter != end_iter && *colon_iter != ':') {
    1204           0 :       ++colon_iter;
    1205             :     }
    1206           0 :     localFile->InitWithNativePath(Substring(start_iter, colon_iter));
    1207           0 :     rv = localFile->AppendRelativePath(nsDependentString(platformAppPath));
    1208             :     // Failing AppendRelativePath is a bad thing - it should basically always
    1209             :     // succeed given a relative path. Show a warning if it does fail.
    1210             :     // To prevent infinite loops when it does fail, return at this point.
    1211           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1212           0 :     localFile->Exists(&exists);
    1213           0 :     if (!exists) {
    1214           0 :       if (colon_iter == end_iter) {
    1215           0 :         break;
    1216             :       }
    1217           0 :       ++colon_iter;
    1218           0 :       start_iter = colon_iter;
    1219             :     }
    1220             :   }
    1221             : 
    1222           0 :   if (exists) {
    1223           0 :     rv = NS_OK;
    1224             :   } else {
    1225           0 :     rv = NS_ERROR_NOT_AVAILABLE;
    1226             :   }
    1227             : 
    1228           0 :   *aFile = localFile;
    1229           0 :   NS_IF_ADDREF(*aFile);
    1230             : 
    1231           0 :   return rv;
    1232             : }
    1233             : 
    1234             : already_AddRefed<nsMIMEInfoBase>
    1235           0 : nsOSHelperAppService::GetFromExtension(const nsCString& aFileExt) {
    1236             :   // if the extension is empty, return immediately
    1237           0 :   if (aFileExt.IsEmpty())
    1238           0 :     return nullptr;
    1239             : 
    1240           0 :   LOG(("Here we do an extension lookup for '%s'\n", aFileExt.get()));
    1241             : 
    1242           0 :   nsAutoString majorType, minorType,
    1243           0 :                mime_types_description, mailcap_description,
    1244           0 :                handler, mozillaFlags;
    1245             : 
    1246           0 :   nsresult rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
    1247             :                                          majorType,
    1248             :                                          minorType,
    1249             :                                          mime_types_description,
    1250           0 :                                          true);
    1251             : 
    1252           0 :   if (NS_FAILED(rv) || majorType.IsEmpty()) {
    1253             : 
    1254             : #ifdef MOZ_WIDGET_GTK
    1255           0 :     LOG(("Looking in GNOME registry\n"));
    1256             :     RefPtr<nsMIMEInfoBase> gnomeInfo =
    1257           0 :       nsGNOMERegistry::GetFromExtension(aFileExt);
    1258           0 :     if (gnomeInfo) {
    1259           0 :       LOG(("Got MIMEInfo from GNOME registry\n"));
    1260           0 :       return gnomeInfo.forget();
    1261             :     }
    1262             : #endif
    1263             : 
    1264           0 :     rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
    1265             :                                   majorType,
    1266             :                                   minorType,
    1267             :                                   mime_types_description,
    1268           0 :                                   false);
    1269             :   }
    1270             : 
    1271           0 :   if (NS_FAILED(rv))
    1272           0 :     return nullptr;
    1273             : 
    1274           0 :   NS_LossyConvertUTF16toASCII asciiMajorType(majorType);
    1275           0 :   NS_LossyConvertUTF16toASCII asciiMinorType(minorType);
    1276             : 
    1277           0 :   LOG(("Type/Description results:  majorType='%s', minorType='%s', description='%s'\n",
    1278             :           asciiMajorType.get(),
    1279             :           asciiMinorType.get(),
    1280             :           NS_LossyConvertUTF16toASCII(mime_types_description).get()));
    1281             : 
    1282           0 :   if (majorType.IsEmpty() && minorType.IsEmpty()) {
    1283             :     // we didn't get a type mapping, so we can't do anything useful
    1284           0 :     return nullptr;
    1285             :   }
    1286             : 
    1287           0 :   nsAutoCString mimeType(asciiMajorType + NS_LITERAL_CSTRING("/") + asciiMinorType);
    1288           0 :   RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix(mimeType);
    1289             : 
    1290           0 :   mimeInfo->AppendExtension(aFileExt);
    1291             :   rv = LookUpHandlerAndDescription(majorType, minorType,
    1292             :                                    handler, mailcap_description,
    1293           0 :                                    mozillaFlags);
    1294           0 :   LOG(("Handler/Description results:  handler='%s', description='%s', mozillaFlags='%s'\n",
    1295             :           NS_LossyConvertUTF16toASCII(handler).get(),
    1296             :           NS_LossyConvertUTF16toASCII(mailcap_description).get(),
    1297             :           NS_LossyConvertUTF16toASCII(mozillaFlags).get()));
    1298           0 :   mailcap_description.Trim(" \t\"");
    1299           0 :   mozillaFlags.Trim(" \t");
    1300           0 :   if (!mime_types_description.IsEmpty()) {
    1301           0 :     mimeInfo->SetDescription(mime_types_description);
    1302             :   } else {
    1303           0 :     mimeInfo->SetDescription(mailcap_description);
    1304             :   }
    1305             : 
    1306           0 :   if (NS_SUCCEEDED(rv) && handler.IsEmpty()) {
    1307           0 :     rv = NS_ERROR_NOT_AVAILABLE;
    1308             :   }
    1309             : 
    1310           0 :   if (NS_SUCCEEDED(rv)) {
    1311           0 :     nsCOMPtr<nsIFile> handlerFile;
    1312           0 :     rv = GetFileTokenForPath(handler.get(), getter_AddRefs(handlerFile));
    1313             : 
    1314           0 :     if (NS_SUCCEEDED(rv)) {
    1315           0 :       mimeInfo->SetDefaultApplication(handlerFile);
    1316           0 :       mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
    1317           0 :       mimeInfo->SetDefaultDescription(handler);
    1318             :     }
    1319             :   }
    1320             : 
    1321           0 :   if (NS_FAILED(rv)) {
    1322           0 :     mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
    1323             :   }
    1324             : 
    1325           0 :   return mimeInfo.forget();
    1326             : }
    1327             : 
    1328             : already_AddRefed<nsMIMEInfoBase>
    1329           2 : nsOSHelperAppService::GetFromType(const nsCString& aMIMEType) {
    1330             :   // if the type is empty, return immediately
    1331           2 :   if (aMIMEType.IsEmpty())
    1332           0 :     return nullptr;
    1333             : 
    1334           2 :   LOG(("Here we do a mimetype lookup for '%s'\n", aMIMEType.get()));
    1335             : 
    1336             :   // extract the major and minor types
    1337           4 :   NS_ConvertASCIItoUTF16 mimeType(aMIMEType);
    1338           2 :   nsAString::const_iterator start_iter, end_iter,
    1339           2 :                             majorTypeStart, majorTypeEnd,
    1340           2 :                             minorTypeStart, minorTypeEnd;
    1341             : 
    1342           2 :   mimeType.BeginReading(start_iter);
    1343           2 :   mimeType.EndReading(end_iter);
    1344             : 
    1345             :   // XXX FIXME: add typeOptions parsing in here
    1346             :   nsresult rv = ParseMIMEType(start_iter, majorTypeStart, majorTypeEnd,
    1347           2 :                               minorTypeStart, minorTypeEnd, end_iter);
    1348             : 
    1349           2 :   if (NS_FAILED(rv)) {
    1350           0 :     return nullptr;
    1351             :   }
    1352             : 
    1353           4 :   nsDependentSubstring majorType(majorTypeStart, majorTypeEnd);
    1354           4 :   nsDependentSubstring minorType(minorTypeStart, minorTypeEnd);
    1355             : 
    1356             :   // First check the user's private mailcap file
    1357           4 :   nsAutoString mailcap_description, handler, mozillaFlags;
    1358             :   DoLookUpHandlerAndDescription(majorType,
    1359             :                                 minorType,
    1360             :                                 handler,
    1361             :                                 mailcap_description,
    1362             :                                 mozillaFlags,
    1363           2 :                                 true);
    1364             : 
    1365           2 :   LOG(("Private Handler/Description results:  handler='%s', description='%s'\n",
    1366             :           NS_LossyConvertUTF16toASCII(handler).get(),
    1367             :           NS_LossyConvertUTF16toASCII(mailcap_description).get()));
    1368             : 
    1369             :   // Now look up our extensions
    1370           4 :   nsAutoString extensions, mime_types_description;
    1371             :   LookUpExtensionsAndDescription(majorType,
    1372             :                                  minorType,
    1373             :                                  extensions,
    1374           2 :                                  mime_types_description);
    1375             : 
    1376             : #ifdef MOZ_WIDGET_GTK
    1377           2 :   if (handler.IsEmpty()) {
    1378           2 :     RefPtr<nsMIMEInfoBase> gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
    1379           2 :     if (gnomeInfo) {
    1380           2 :       LOG(("Got MIMEInfo from GNOME registry without extensions; setting them "
    1381             :            "to %s\n", NS_LossyConvertUTF16toASCII(extensions).get()));
    1382             : 
    1383           2 :       NS_ASSERTION(!gnomeInfo->HasExtensions(), "How'd that happen?");
    1384           2 :       gnomeInfo->SetFileExtensions(NS_ConvertUTF16toUTF8(extensions));
    1385           2 :       return gnomeInfo.forget();
    1386             :     }
    1387             :   }
    1388             : #endif
    1389             : 
    1390           0 :   if (handler.IsEmpty()) {
    1391             :     DoLookUpHandlerAndDescription(majorType,
    1392             :                                   minorType,
    1393             :                                   handler,
    1394             :                                   mailcap_description,
    1395             :                                   mozillaFlags,
    1396           0 :                                   false);
    1397             :   }
    1398             : 
    1399           0 :   if (handler.IsEmpty()) {
    1400           0 :     DoLookUpHandlerAndDescription(majorType,
    1401           0 :                                   NS_LITERAL_STRING("*"),
    1402             :                                   handler,
    1403             :                                   mailcap_description,
    1404             :                                   mozillaFlags,
    1405           0 :                                   true);
    1406             :   }
    1407             : 
    1408           0 :   if (handler.IsEmpty()) {
    1409           0 :     DoLookUpHandlerAndDescription(majorType,
    1410           0 :                                   NS_LITERAL_STRING("*"),
    1411             :                                   handler,
    1412             :                                   mailcap_description,
    1413             :                                   mozillaFlags,
    1414           0 :                                   false);
    1415             :   }
    1416             : 
    1417           0 :   LOG(("Handler/Description results:  handler='%s', description='%s', mozillaFlags='%s'\n",
    1418             :           NS_LossyConvertUTF16toASCII(handler).get(),
    1419             :           NS_LossyConvertUTF16toASCII(mailcap_description).get(),
    1420             :           NS_LossyConvertUTF16toASCII(mozillaFlags).get()));
    1421             : 
    1422           0 :   mailcap_description.Trim(" \t\"");
    1423           0 :   mozillaFlags.Trim(" \t");
    1424             : 
    1425           0 :   if (handler.IsEmpty() && extensions.IsEmpty() &&
    1426           0 :       mailcap_description.IsEmpty() && mime_types_description.IsEmpty()) {
    1427             :     // No real useful info
    1428           0 :     return nullptr;
    1429             :   }
    1430             : 
    1431           0 :   RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix(aMIMEType);
    1432             : 
    1433           0 :   mimeInfo->SetFileExtensions(NS_ConvertUTF16toUTF8(extensions));
    1434           0 :   if (! mime_types_description.IsEmpty()) {
    1435           0 :     mimeInfo->SetDescription(mime_types_description);
    1436             :   } else {
    1437           0 :     mimeInfo->SetDescription(mailcap_description);
    1438             :   }
    1439             : 
    1440           0 :   rv = NS_ERROR_NOT_AVAILABLE;
    1441           0 :   nsCOMPtr<nsIFile> handlerFile;
    1442           0 :   if (!handler.IsEmpty()) {
    1443           0 :     rv = GetFileTokenForPath(handler.get(), getter_AddRefs(handlerFile));
    1444             :   }
    1445             : 
    1446           0 :   if (NS_SUCCEEDED(rv)) {
    1447           0 :     mimeInfo->SetDefaultApplication(handlerFile);
    1448           0 :     mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
    1449           0 :     mimeInfo->SetDefaultDescription(handler);
    1450             :   } else {
    1451           0 :     mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
    1452             :   }
    1453             : 
    1454           0 :   return mimeInfo.forget();
    1455             : }
    1456             : 
    1457             : 
    1458             : already_AddRefed<nsIMIMEInfo>
    1459           2 : nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aType,
    1460             :                                         const nsACString& aFileExt,
    1461             :                                         bool       *aFound) {
    1462           2 :   *aFound = true;
    1463           4 :   RefPtr<nsMIMEInfoBase> retval = GetFromType(PromiseFlatCString(aType));
    1464           2 :   bool hasDefault = false;
    1465           2 :   if (retval)
    1466           2 :     retval->GetHasDefaultHandler(&hasDefault);
    1467           2 :   if (!retval || !hasDefault) {
    1468           0 :     RefPtr<nsMIMEInfoBase> miByExt = GetFromExtension(PromiseFlatCString(aFileExt));
    1469             :     // If we had no extension match, but a type match, use that
    1470           0 :     if (!miByExt && retval)
    1471           0 :       return retval.forget();
    1472             :     // If we had an extension match but no type match, set the mimetype and use
    1473             :     // it
    1474           0 :     if (!retval && miByExt) {
    1475           0 :       if (!aType.IsEmpty())
    1476           0 :         miByExt->SetMIMEType(aType);
    1477           0 :       miByExt.swap(retval);
    1478             : 
    1479           0 :       return retval.forget();
    1480             :     }
    1481             :     // If we got nothing, make a new mimeinfo
    1482           0 :     if (!retval) {
    1483           0 :       *aFound = false;
    1484           0 :       retval = new nsMIMEInfoUnix(aType);
    1485           0 :       if (retval) {
    1486           0 :         if (!aFileExt.IsEmpty())
    1487           0 :           retval->AppendExtension(aFileExt);
    1488             :       }
    1489             : 
    1490           0 :       return retval.forget();
    1491             :     }
    1492             : 
    1493             :     // Copy the attributes of retval (mimeinfo from type) onto miByExt, to
    1494             :     // return it
    1495             :     // but reset to just collected mDefaultAppDescription (from ext)
    1496           0 :     nsAutoString byExtDefault;
    1497           0 :     miByExt->GetDefaultDescription(byExtDefault);
    1498           0 :     retval->SetDefaultDescription(byExtDefault);
    1499           0 :     retval->CopyBasicDataTo(miByExt);
    1500             : 
    1501           0 :     miByExt.swap(retval);
    1502             :   }
    1503           2 :   return retval.forget();
    1504             : }
    1505             : 
    1506             : NS_IMETHODIMP
    1507           0 : nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme,
    1508             :                                                    bool *found,
    1509             :                                                    nsIHandlerInfo **_retval)
    1510             : {
    1511           0 :   NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
    1512             : 
    1513           0 :   nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(),
    1514           0 :                                         found);
    1515           0 :   if (NS_FAILED(rv))
    1516           0 :     return rv;
    1517             : 
    1518             :   nsMIMEInfoUnix *handlerInfo =
    1519           0 :     new nsMIMEInfoUnix(aScheme, nsMIMEInfoBase::eProtocolInfo);
    1520           0 :   NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
    1521           0 :   NS_ADDREF(*_retval = handlerInfo);
    1522             : 
    1523           0 :   if (!*found) {
    1524             :     // Code that calls this requires an object regardless if the OS has
    1525             :     // something for us, so we return the empty object.
    1526           0 :     return NS_OK;
    1527             :   }
    1528             : 
    1529           0 :   nsAutoString desc;
    1530           0 :   GetApplicationDescription(aScheme, desc);
    1531           0 :   handlerInfo->SetDefaultDescription(desc);
    1532             : 
    1533           0 :   return NS_OK;
    1534             : }

Generated by: LCOV version 1.13