LCOV - code coverage report
Current view: directory - uriloader/exthandler/unix - nsOSHelperAppService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 733 431 58.8 %
Date: 2012-06-02 Functions: 26 23 88.5 %

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

Generated by: LCOV version 1.7