Back to index

lightning-sunbird  0.9+nobinonly
nsOSHelperAppService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Scott MacGregor <mscott@netscape.com>
00025  *   Boris Zbarsky <bzbarsky@mit.edu>  (Added mailcap and mime.types support)
00026  *   Peter Weilbacher <mozilla@Weilbacher.org>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsOSHelperAppService.h"
00043 #include "nsISupports.h"
00044 #include "nsString.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsUnicharUtils.h"
00047 #include "nsXPIDLString.h"
00048 #include "nsIURL.h"
00049 #include "nsNetCID.h"
00050 #include "nsIFileStreams.h"
00051 #include "nsILineInputStream.h"
00052 #include "nsILocalFile.h"
00053 #include "nsEscape.h"
00054 #include "nsIProcess.h"
00055 #include "nsIPrefService.h"
00056 #include "nsIPrefBranch.h"
00057 #include "nsXPCOM.h"
00058 #include "nsISupportsPrimitives.h"
00059 #include "nsHashtable.h"
00060 #include "nsCRT.h"
00061 #include "prenv.h"      // for PR_GetEnv()
00062 #include "nsMIMEInfoOS2.h"
00063 #include "nsAutoPtr.h"
00064 #include <stdlib.h>         // for system()
00065 
00066 #include "nsIPref.h" // XX Need to convert Handler code to new pref stuff
00067 static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID); // XXX need to convert to contract id
00068 
00069 #define INCL_DOSMISC
00070 #define INCL_DOSERRORS
00071 #define INCL_WINSHELLDATA
00072 #include <os2.h>
00073 
00074 #define MAXINIPARAMLENGTH 1024 // max length of OS/2 INI key for application parameters
00075 
00076 #define LOG(args) PR_LOG(mLog, PR_LOG_DEBUG, args)
00077 #define LOG_ENABLED() PR_LOG_TEST(mLog, PR_LOG_DEBUG)
00078 
00079 static nsresult
00080 FindSemicolon(nsAString::const_iterator& aSemicolon_iter,
00081               const nsAString::const_iterator& aEnd_iter);
00082 static nsresult
00083 ParseMIMEType(const nsAString::const_iterator& aStart_iter,
00084               nsAString::const_iterator& aMajorTypeStart,
00085               nsAString::const_iterator& aMajorTypeEnd,
00086               nsAString::const_iterator& aMinorTypeStart,
00087               nsAString::const_iterator& aMinorTypeEnd,
00088               const nsAString::const_iterator& aEnd_iter);
00089 
00090 inline PRBool
00091 IsNetscapeFormat(const nsACString& aBuffer);
00092 
00093 nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
00094 {
00095 }
00096 
00097 nsOSHelperAppService::~nsOSHelperAppService()
00098 {}
00099 
00100 /*
00101  * Take a command with all the mailcap escapes in it and unescape it
00102  * Ideally this needs the mime type, mime type options, and location of the
00103  * temporary file, but this last can't be got from here
00104  */
00105 // static
00106 nsresult
00107 nsOSHelperAppService::UnescapeCommand(const nsAString& aEscapedCommand,
00108                                       const nsAString& aMajorType,
00109                                       const nsAString& aMinorType,
00110                                       nsHashtable& aTypeOptions,
00111                                       nsACString& aUnEscapedCommand) {
00112   LOG(("-- UnescapeCommand"));
00113   LOG(("Command to escape: '%s'\n",
00114        NS_LossyConvertUCS2toASCII(aEscapedCommand).get()));
00115   //  XXX This function will need to get the mime type and various stuff like that being passed in to work properly
00116   
00117   LOG(("UnescapeCommand really needs some work -- it should actually do some unescaping\n"));
00118 
00119   CopyUTF16toUTF8(aEscapedCommand, aUnEscapedCommand);
00120   LOG(("Escaped command: '%s'\n",
00121        PromiseFlatCString(aUnEscapedCommand).get()));
00122   return NS_OK;
00123 }
00124 
00125 /* Put aSemicolon_iter at the first non-escaped semicolon after
00126  * aStart_iter but before aEnd_iter
00127  */
00128 
00129 static nsresult
00130 FindSemicolon(nsAString::const_iterator& aSemicolon_iter,
00131               const nsAString::const_iterator& aEnd_iter) {
00132   PRBool semicolonFound = PR_FALSE;
00133   while (aSemicolon_iter != aEnd_iter && !semicolonFound) {
00134     switch(*aSemicolon_iter) {
00135     case '\\':
00136       aSemicolon_iter.advance(2);
00137       break;
00138     case ';':
00139       semicolonFound = PR_TRUE;
00140       break;
00141     default:
00142       ++aSemicolon_iter;
00143       break;
00144     }
00145   }
00146   return NS_OK;
00147 }
00148 
00149 static nsresult
00150 ParseMIMEType(const nsAString::const_iterator& aStart_iter,
00151               nsAString::const_iterator& aMajorTypeStart,
00152               nsAString::const_iterator& aMajorTypeEnd,
00153               nsAString::const_iterator& aMinorTypeStart,
00154               nsAString::const_iterator& aMinorTypeEnd,
00155               const nsAString::const_iterator& aEnd_iter) {
00156   nsAString::const_iterator iter(aStart_iter);
00157   
00158   // skip leading whitespace
00159   while (iter != aEnd_iter && nsCRT::IsAsciiSpace(*iter)) {
00160     ++iter;
00161   }
00162 
00163   if (iter == aEnd_iter) {
00164     return NS_ERROR_INVALID_ARG;
00165   }
00166   
00167   aMajorTypeStart = iter;
00168 
00169   // find major/minor separator ('/')
00170   while (iter != aEnd_iter && *iter != '/') {
00171     ++iter;
00172   }
00173   
00174   if (iter == aEnd_iter) {
00175     return NS_ERROR_INVALID_ARG;
00176   }
00177 
00178   aMajorTypeEnd = iter;
00179   
00180   // skip '/'
00181   ++iter;
00182 
00183   if (iter == aEnd_iter) {
00184     return NS_ERROR_INVALID_ARG;
00185   }
00186 
00187   aMinorTypeStart = iter;
00188 
00189   // find end of minor type, delimited by whitespace or ';'
00190   while (iter != aEnd_iter && !nsCRT::IsAsciiSpace(*iter) && *iter != ';') {
00191     ++iter;
00192   }
00193 
00194   aMinorTypeEnd = iter;
00195 
00196   return NS_OK;
00197 }
00198 
00199 // static
00200 nsresult
00201 nsOSHelperAppService::GetFileLocation(const char* aPrefName,
00202                                       const char* aEnvVarName,
00203                                       PRUnichar** aFileLocation) {
00204   LOG(("-- GetFileLocation.  Pref: '%s'  EnvVar: '%s'\n",
00205        aPrefName,
00206        aEnvVarName));
00207   NS_PRECONDITION(aPrefName, "Null pref name passed; don't do that!");
00208   
00209   nsresult rv;
00210   *aFileLocation = nsnull;
00211   /* The lookup order is:
00212      1) user pref
00213      2) env var
00214      3) pref
00215   */
00216   nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00217   NS_ENSURE_SUCCESS(rv, rv);
00218   nsCOMPtr<nsIPrefBranch> prefBranch;
00219   rv = prefService->GetBranch(nsnull, getter_AddRefs(prefBranch));
00220   NS_ENSURE_SUCCESS(rv, rv);
00221 
00222   /*
00223     If we have an env var we should check whether the pref is a user
00224     pref.  If we do not, we don't care.
00225   */
00226   nsCOMPtr<nsISupportsString> prefFileName;
00227   PRBool isUserPref = PR_FALSE;
00228   prefBranch->PrefHasUserValue(aPrefName, &isUserPref);
00229   if (isUserPref) {
00230     rv = prefBranch->GetComplexValue(aPrefName,
00231                                      NS_GET_IID(nsISupportsString),
00232                                      getter_AddRefs(prefFileName));
00233     if (NS_SUCCEEDED(rv)) {
00234       return prefFileName->ToString(aFileLocation);
00235     }
00236   }
00237 
00238   if (aEnvVarName && *aEnvVarName) {
00239     char* prefValue = PR_GetEnv(aEnvVarName);
00240     if (prefValue && *prefValue) {
00241       // the pref is in the system charset and it's a filepath... The
00242       // natural way to do the charset conversion is by just initing
00243       // an nsIFile with the native path and asking it for the Unicode
00244       // version.
00245       nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
00246       NS_ENSURE_SUCCESS(rv, rv);
00247 
00248       rv = file->InitWithNativePath(nsDependentCString(prefValue));
00249       NS_ENSURE_SUCCESS(rv, rv);
00250 
00251       nsAutoString unicodePath;
00252       rv = file->GetPath(unicodePath);
00253       NS_ENSURE_SUCCESS(rv, rv);
00254       
00255       *aFileLocation = ToNewUnicode(unicodePath);
00256       if (!*aFileLocation)
00257         return NS_ERROR_OUT_OF_MEMORY;
00258       return NS_OK;
00259     }
00260   }
00261   
00262   rv = prefBranch->GetComplexValue(aPrefName,
00263                                    NS_GET_IID(nsISupportsString),
00264                                    getter_AddRefs(prefFileName));
00265   if (NS_SUCCEEDED(rv)) {
00266     return prefFileName->ToString(aFileLocation);
00267   }
00268   
00269   return rv;
00270 }
00271 
00272 
00273 /* Get the mime.types file names from prefs and look up info in them
00274    based on extension */
00275 // static
00276 nsresult
00277 nsOSHelperAppService::LookUpTypeAndDescription(const nsAString& aFileExtension,
00278                                                nsAString& aMajorType,
00279                                                nsAString& aMinorType,
00280                                                nsAString& aDescription) {
00281   LOG(("-- LookUpTypeAndDescription for extension '%s'\n",
00282        NS_LossyConvertUCS2toASCII(aFileExtension).get()));
00283   nsresult rv = NS_OK;
00284   nsXPIDLString mimeFileName;
00285 
00286   rv = GetFileLocation("helpers.private_mime_types_file",
00287                        nsnull,
00288                        getter_Copies(mimeFileName));
00289   if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
00290     rv = GetTypeAndDescriptionFromMimetypesFile(mimeFileName,
00291                                                 aFileExtension,
00292                                                 aMajorType,
00293                                                 aMinorType,
00294                                                 aDescription);
00295   } else {
00296     rv = NS_ERROR_NOT_AVAILABLE;
00297   }
00298   if (NS_FAILED(rv) || aMajorType.IsEmpty()) {
00299     rv = GetFileLocation("helpers.global_mime_types_file",
00300                          nsnull,
00301                          getter_Copies(mimeFileName));
00302     if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
00303       rv = GetTypeAndDescriptionFromMimetypesFile(mimeFileName,
00304                                                   aFileExtension,
00305                                                   aMajorType,
00306                                                   aMinorType,
00307                                                   aDescription);
00308     } else {
00309       rv = NS_ERROR_NOT_AVAILABLE;
00310     }
00311   }
00312   return rv;
00313 }
00314 
00315 inline PRBool
00316 IsNetscapeFormat(const nsACString& aBuffer) {
00317   return StringBeginsWith(aBuffer, NS_LITERAL_CSTRING("#--Netscape Communications Corporation MIME Information")) ||
00318          StringBeginsWith(aBuffer, NS_LITERAL_CSTRING("#--MCOM MIME Information"));
00319 }
00320 
00321 /*
00322  * Create a file stream and line input stream for the filename.
00323  * Leaves the first line of the file in aBuffer and sets the format to
00324  *  PR_TRUE for netscape files and false for normail ones
00325  */
00326 // static
00327 nsresult
00328 nsOSHelperAppService::CreateInputStream(const nsAString& aFilename,
00329                                         nsIFileInputStream ** aFileInputStream,
00330                                         nsILineInputStream ** aLineInputStream,
00331                                         nsACString& aBuffer,
00332                                         PRBool * aNetscapeFormat,
00333                                         PRBool * aMore) {
00334   LOG(("-- CreateInputStream"));
00335   nsresult rv = NS_OK;
00336 
00337   nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
00338   if (NS_FAILED(rv))
00339     return rv;
00340   rv = file->InitWithPath(aFilename);
00341   if (NS_FAILED(rv))
00342     return rv;
00343 
00344   nsCOMPtr<nsIFileInputStream> fileStream(do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
00345   if (NS_FAILED(rv))
00346     return rv;
00347   rv = fileStream->Init(file, -1, -1, PR_FALSE);
00348   if (NS_FAILED(rv))
00349     return rv;
00350 
00351   nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
00352 
00353   if (NS_FAILED(rv)) {
00354     LOG(("Interface trouble in stream land!"));
00355     return rv;
00356   }
00357 
00358   rv = lineStream->ReadLine(aBuffer, aMore);
00359   if (NS_FAILED(rv)) {
00360     fileStream->Close();
00361     return rv;
00362   }
00363 
00364   *aNetscapeFormat = IsNetscapeFormat(aBuffer);
00365 
00366   *aFileInputStream = fileStream;
00367   NS_ADDREF(*aFileInputStream);
00368   *aLineInputStream = lineStream;
00369   NS_ADDREF(*aLineInputStream);
00370 
00371   return NS_OK;
00372 }
00373 
00374 /* Open the file, read the first line, decide what type of file it is,
00375    then get info based on extension */
00376 // static
00377 nsresult
00378 nsOSHelperAppService::GetTypeAndDescriptionFromMimetypesFile(const nsAString& aFilename,
00379                                                              const nsAString& aFileExtension,
00380                                                              nsAString& aMajorType,
00381                                                              nsAString& aMinorType,
00382                                                              nsAString& aDescription) {
00383   LOG(("-- GetTypeAndDescriptionFromMimetypesFile\n"));
00384   LOG(("Getting type and description from types file '%s'\n",
00385        NS_LossyConvertUCS2toASCII(aFilename).get()));
00386   LOG(("Using extension '%s'\n",
00387        NS_LossyConvertUCS2toASCII(aFileExtension).get()));
00388   nsresult rv = NS_OK;
00389   nsCOMPtr<nsIFileInputStream> mimeFile;
00390   nsCOMPtr<nsILineInputStream> mimeTypes;
00391   PRBool netscapeFormat;
00392   nsAutoString buf;
00393   nsCAutoString cBuf;
00394   PRBool more = PR_FALSE;
00395   rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
00396                          cBuf, &netscapeFormat, &more);
00397 
00398   if (NS_FAILED(rv)) {
00399     return rv;
00400   }
00401   
00402 
00403   nsAutoString extensions;
00404   nsString entry;
00405   entry.SetCapacity(100);
00406   nsAString::const_iterator majorTypeStart, majorTypeEnd,
00407                             minorTypeStart, minorTypeEnd,
00408                             descriptionStart, descriptionEnd;
00409 
00410   do {
00411     CopyASCIItoUTF16(cBuf, buf);
00412     // read through, building up an entry.  If we finish an entry, check for
00413     // a match and return out of the loop if we match
00414 
00415     // skip comments and empty lines
00416     if (!buf.IsEmpty() && buf.First() != '#') {
00417       entry.Append(buf);
00418       if (entry.Last() == '\\') {
00419         entry.Truncate(entry.Length() - 1);
00420         entry.Append(PRUnichar(' '));  // in case there is no trailing whitespace on this line
00421       } else {  // we have a full entry
00422         LOG(("Current entry: '%s'\n",
00423              NS_LossyConvertUCS2toASCII(entry).get()));
00424         if (netscapeFormat) {
00425           rv = ParseNetscapeMIMETypesEntry(entry,
00426                                            majorTypeStart, majorTypeEnd,
00427                                            minorTypeStart, minorTypeEnd,
00428                                            extensions,
00429                                            descriptionStart, descriptionEnd);
00430           if (NS_FAILED(rv)) {
00431             // We sometimes get things like RealPlayer appending
00432             // "normal" entries to "Netscape" .mime.types files.  Try
00433             // to handle that.  Bug 106381.
00434             LOG(("Bogus entry; trying 'normal' mode\n"));
00435             rv = ParseNormalMIMETypesEntry(entry,
00436                                            majorTypeStart, majorTypeEnd,
00437                                            minorTypeStart, minorTypeEnd,
00438                                            extensions,
00439                                            descriptionStart, descriptionEnd);
00440           }
00441         } else {
00442           rv = ParseNormalMIMETypesEntry(entry,
00443                                          majorTypeStart, majorTypeEnd,
00444                                          minorTypeStart, minorTypeEnd,
00445                                          extensions,
00446                                          descriptionStart, descriptionEnd);
00447           if (NS_FAILED(rv)) {
00448             // We sometimes get things like StarOffice prepending
00449             // "normal" entries to "Netscape" .mime.types files.  Try
00450             // to handle that.  Bug 136670.
00451             LOG(("Bogus entry; trying 'Netscape' mode\n"));
00452             rv = ParseNetscapeMIMETypesEntry(entry,
00453                                              majorTypeStart, majorTypeEnd,
00454                                              minorTypeStart, minorTypeEnd,
00455                                              extensions,
00456                                              descriptionStart, descriptionEnd);
00457           }
00458         }
00459 
00460         if (NS_SUCCEEDED(rv)) { // entry parses
00461           nsAString::const_iterator start, end;
00462           extensions.BeginReading(start);
00463           extensions.EndReading(end);
00464           nsAString::const_iterator iter(start);
00465 
00466           while (start != end) {
00467             FindCharInReadable(',', iter, end);
00468             if (Substring(start, iter).Equals(aFileExtension,
00469                                               nsCaseInsensitiveStringComparator())) {
00470               // it's a match.  Assign the type and description and run
00471               aMajorType.Assign(Substring(majorTypeStart, majorTypeEnd));
00472               aMinorType.Assign(Substring(minorTypeStart, minorTypeEnd));
00473               aDescription.Assign(Substring(descriptionStart, descriptionEnd));
00474               mimeFile->Close();
00475               return NS_OK;
00476             }
00477             if (iter != end) {
00478               ++iter;
00479             }
00480             start = iter;
00481           }
00482         } else {
00483           LOG(("Failed to parse entry: %s\n", NS_LossyConvertUCS2toASCII(entry).get()));
00484         }
00485         // truncate the entry for the next iteration
00486         entry.Truncate();
00487       }
00488     }
00489     if (!more) {
00490       rv = NS_ERROR_NOT_AVAILABLE;
00491       break;
00492     }
00493     // read the next line
00494     rv = mimeTypes->ReadLine(cBuf, &more);
00495   } while (NS_SUCCEEDED(rv));
00496 
00497   mimeFile->Close();
00498   return rv;
00499 }
00500 
00501 /* Get the mime.types file names from prefs and look up info in them
00502    based on mimetype  */
00503 // static
00504 nsresult
00505 nsOSHelperAppService::LookUpExtensionsAndDescription(const nsAString& aMajorType,
00506                                                      const nsAString& aMinorType,
00507                                                      nsAString& aFileExtensions,
00508                                                      nsAString& aDescription) {
00509   LOG(("-- LookUpExtensionsAndDescription for type '%s/%s'\n",
00510        NS_LossyConvertUCS2toASCII(aMajorType).get(),
00511        NS_LossyConvertUCS2toASCII(aMinorType).get()));
00512   nsresult rv = NS_OK;
00513   nsXPIDLString mimeFileName;
00514 
00515   rv = GetFileLocation("helpers.private_mime_types_file",
00516                        nsnull,
00517                        getter_Copies(mimeFileName));
00518   if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
00519     rv = GetExtensionsAndDescriptionFromMimetypesFile(mimeFileName,
00520                                                       aMajorType,
00521                                                       aMinorType,
00522                                                       aFileExtensions,
00523                                                       aDescription);
00524   } else {
00525     rv = NS_ERROR_NOT_AVAILABLE;
00526   }
00527   if (NS_FAILED(rv) || aFileExtensions.IsEmpty()) {
00528     rv = GetFileLocation("helpers.global_mime_types_file",
00529                          nsnull,
00530                          getter_Copies(mimeFileName));
00531     if (NS_SUCCEEDED(rv) && !mimeFileName.IsEmpty()) {
00532       rv = GetExtensionsAndDescriptionFromMimetypesFile(mimeFileName,
00533                                                         aMajorType,
00534                                                         aMinorType,
00535                                                         aFileExtensions,
00536                                                         aDescription);
00537     } else {
00538       rv = NS_ERROR_NOT_AVAILABLE;
00539     }
00540   }
00541   return rv;
00542 }
00543 
00544 /* Open the file, read the first line, decide what type of file it is,
00545    then get info based on extension */
00546 // static
00547 nsresult
00548 nsOSHelperAppService::GetExtensionsAndDescriptionFromMimetypesFile(const nsAString& aFilename,
00549                                                                    const nsAString& aMajorType,
00550                                                                    const nsAString& aMinorType,
00551                                                                    nsAString& aFileExtensions,
00552                                                                    nsAString& aDescription) {
00553   LOG(("-- GetExtensionsAndDescriptionFromMimetypesFile\n"));
00554   LOG(("Getting extensions and description from types file '%s'\n",
00555        NS_LossyConvertUCS2toASCII(aFilename).get()));
00556   LOG(("Using type '%s/%s'\n",
00557        NS_LossyConvertUCS2toASCII(aMajorType).get(),
00558        NS_LossyConvertUCS2toASCII(aMinorType).get()));
00559 
00560   nsresult rv = NS_OK;
00561   nsCOMPtr<nsIFileInputStream> mimeFile;
00562   nsCOMPtr<nsILineInputStream> mimeTypes;
00563   PRBool netscapeFormat;
00564   nsAutoString buf;
00565   nsCAutoString cBuf;
00566   PRBool more = PR_FALSE;
00567   rv = CreateInputStream(aFilename, getter_AddRefs(mimeFile), getter_AddRefs(mimeTypes),
00568                          cBuf, &netscapeFormat, &more);
00569 
00570   if (NS_FAILED(rv)) {
00571     return rv;
00572   }
00573   
00574   nsAutoString extensions;
00575   nsString entry;
00576   entry.SetCapacity(100);
00577   nsAString::const_iterator majorTypeStart, majorTypeEnd,
00578                             minorTypeStart, minorTypeEnd,
00579                             descriptionStart, descriptionEnd;
00580   
00581   do {
00582     CopyASCIItoUTF16(cBuf, buf);
00583     // read through, building up an entry.  If we finish an entry, check for
00584     // a match and return out of the loop if we match
00585 
00586     // skip comments and empty lines
00587     if (!buf.IsEmpty() && buf.First() != '#') {
00588       entry.Append(buf);
00589       if (entry.Last() == '\\') {
00590         entry.Truncate(entry.Length() - 1);
00591         entry.Append(PRUnichar(' '));  // in case there is no trailing whitespace on this line
00592       } else {  // we have a full entry
00593         LOG(("Current entry: '%s'\n",
00594              NS_LossyConvertUCS2toASCII(entry).get()));
00595         if (netscapeFormat) {
00596           rv = ParseNetscapeMIMETypesEntry(entry,
00597                                            majorTypeStart, majorTypeEnd,
00598                                            minorTypeStart, minorTypeEnd,
00599                                            extensions,
00600                                            descriptionStart, descriptionEnd);
00601           
00602           if (NS_FAILED(rv)) {
00603             // We sometimes get things like RealPlayer appending
00604             // "normal" entries to "Netscape" .mime.types files.  Try
00605             // to handle that.  Bug 106381.
00606             LOG(("Bogus entry; trying 'normal' mode\n"));
00607             rv = ParseNormalMIMETypesEntry(entry,
00608                                            majorTypeStart, majorTypeEnd,
00609                                            minorTypeStart, minorTypeEnd,
00610                                            extensions,
00611                                            descriptionStart, descriptionEnd);
00612           }
00613         } else {
00614           rv = ParseNormalMIMETypesEntry(entry,
00615                                          majorTypeStart, majorTypeEnd,
00616                                          minorTypeStart,
00617                                          minorTypeEnd, extensions,
00618                                          descriptionStart, descriptionEnd);
00619           
00620           if (NS_FAILED(rv)) {
00621             // We sometimes get things like StarOffice prepending
00622             // "normal" entries to "Netscape" .mime.types files.  Try
00623             // to handle that.  Bug 136670.
00624             LOG(("Bogus entry; trying 'Netscape' mode\n"));
00625             rv = ParseNetscapeMIMETypesEntry(entry,
00626                                              majorTypeStart, majorTypeEnd,
00627                                              minorTypeStart, minorTypeEnd,
00628                                              extensions,
00629                                              descriptionStart, descriptionEnd);
00630           }
00631         }
00632         
00633         if (NS_SUCCEEDED(rv) &&
00634             Substring(majorTypeStart,
00635                       majorTypeEnd).Equals(aMajorType,
00636                                            nsCaseInsensitiveStringComparator())&&
00637             Substring(minorTypeStart,
00638                       minorTypeEnd).Equals(aMinorType,
00639                                            nsCaseInsensitiveStringComparator())) {
00640           // it's a match
00641           aFileExtensions.Assign(extensions);
00642           aDescription.Assign(Substring(descriptionStart, descriptionEnd));
00643           mimeFile->Close();
00644           return NS_OK;
00645         } else if (NS_FAILED(rv)) {
00646           LOG(("Failed to parse entry: %s\n", NS_LossyConvertUCS2toASCII(entry).get()));
00647         }
00648         
00649         entry.Truncate();
00650       }
00651     }
00652     if (!more) {
00653       rv = NS_ERROR_NOT_AVAILABLE;
00654       break;
00655     }
00656     // read the next line
00657     rv = mimeTypes->ReadLine(cBuf, &more);
00658   } while (NS_SUCCEEDED(rv));
00659 
00660   mimeFile->Close();
00661   return rv;
00662 }
00663 
00664 /*
00665  * This parses a Netscape format mime.types entry.  There are two
00666  * possible formats:
00667  *
00668  * type=foo/bar; options exts="baz" description="Some type"
00669  *
00670  * and
00671  *  
00672  * type=foo/bar; options description="Some type" exts="baz"
00673  */
00674 // static
00675 nsresult
00676 nsOSHelperAppService::ParseNetscapeMIMETypesEntry(const nsAString& aEntry,
00677                                                   nsAString::const_iterator& aMajorTypeStart,
00678                                                   nsAString::const_iterator& aMajorTypeEnd,
00679                                                   nsAString::const_iterator& aMinorTypeStart,
00680                                                   nsAString::const_iterator& aMinorTypeEnd,
00681                                                   nsAString& aExtensions,
00682                                                   nsAString::const_iterator& aDescriptionStart,
00683                                                   nsAString::const_iterator& aDescriptionEnd) {
00684   LOG(("-- ParseNetscapeMIMETypesEntry\n"));
00685   NS_ASSERTION(!aEntry.IsEmpty(), "Empty Netscape MIME types entry being parsed.");
00686   
00687   nsAString::const_iterator start_iter, end_iter, match_start, match_end;
00688 
00689   aEntry.BeginReading(start_iter);
00690   aEntry.EndReading(end_iter);
00691   
00692   // skip trailing whitespace
00693   do {
00694     --end_iter;
00695   } while (end_iter != start_iter &&
00696            nsCRT::IsAsciiSpace(*end_iter));
00697   // if we're pointing to a quote, don't advance -- we don't want to
00698   // include the quote....
00699   if (*end_iter != '"')
00700     ++end_iter;
00701   match_start = start_iter;
00702   match_end = end_iter;
00703   
00704   // Get the major and minor types
00705   // First the major type
00706   if (! FindInReadable(NS_LITERAL_STRING("type="), match_start, match_end)) {
00707     return NS_ERROR_FAILURE;
00708   }
00709   
00710   match_start = match_end;
00711   
00712   while (match_end != end_iter &&
00713          *match_end != '/') {
00714     ++match_end;
00715   }
00716   if (match_end == end_iter) {
00717     return NS_ERROR_FAILURE;
00718   }
00719   
00720   aMajorTypeStart = match_start;
00721   aMajorTypeEnd = match_end;
00722 
00723   // now the minor type
00724   if (++match_end == end_iter) {
00725     return NS_ERROR_FAILURE;
00726   }
00727   
00728   match_start = match_end;
00729   
00730   while (match_end != end_iter &&
00731          !nsCRT::IsAsciiSpace(*match_end) &&
00732          *match_end != ';') {
00733     ++match_end;
00734   }
00735   if (match_end == end_iter) {
00736     return NS_ERROR_FAILURE;
00737   }
00738   
00739   aMinorTypeStart = match_start;
00740   aMinorTypeEnd = match_end;
00741   
00742   // ignore everything up to the end of the mime type from here on
00743   start_iter = match_end;
00744   
00745   // get the extensions
00746   match_start = match_end;
00747   match_end = end_iter;
00748   if (FindInReadable(NS_LITERAL_STRING("exts="), match_start, match_end)) {
00749     nsAString::const_iterator extStart, extEnd;
00750 
00751     if (match_end == end_iter ||
00752         (*match_end == '"' && ++match_end == end_iter)) {
00753       return NS_ERROR_FAILURE;
00754     }
00755   
00756     extStart = match_end;
00757     match_start = extStart;
00758     match_end = end_iter;
00759     if (FindInReadable(NS_LITERAL_STRING("desc=\""), match_start, match_end)) {
00760       // exts= before desc=, so we have to find the actual end of the extensions
00761       extEnd = match_start;
00762       if (extEnd == extStart) {
00763         return NS_ERROR_FAILURE;
00764       }
00765     
00766       do {
00767         --extEnd;
00768       } while (extEnd != extStart &&
00769                nsCRT::IsAsciiSpace(*extEnd));
00770       
00771       if (extEnd != extStart && *extEnd == '"') {
00772         --extEnd;
00773       }
00774     } else {
00775       // desc= before exts=, so we can use end_iter as the end of the extensions
00776       extEnd = end_iter;
00777     }
00778     aExtensions = Substring(extStart, extEnd);
00779   } else {
00780     // no extensions
00781     aExtensions.Truncate();
00782   }
00783 
00784   // get the description
00785   match_start = start_iter;
00786   match_end = end_iter;
00787   if (FindInReadable(NS_LITERAL_STRING("desc=\""), match_start, match_end)) {
00788     aDescriptionStart = match_end;
00789     match_start = aDescriptionStart;
00790     match_end = end_iter;
00791     if (FindInReadable(NS_LITERAL_STRING("exts="), match_start, match_end)) {
00792       // exts= after desc=, so have to find actual end of description
00793       aDescriptionEnd = match_start;
00794       if (aDescriptionEnd == aDescriptionStart) {
00795         return NS_ERROR_FAILURE;
00796       }
00797       
00798       do {
00799         --aDescriptionEnd;
00800       } while (aDescriptionEnd != aDescriptionStart &&
00801                nsCRT::IsAsciiSpace(*aDescriptionEnd));
00802       
00803       if (aDescriptionStart != aDescriptionStart && *aDescriptionEnd == '"') {
00804         --aDescriptionEnd;
00805       }
00806     } else {
00807       // desc= after exts=, so use end_iter for the description end
00808       aDescriptionEnd = end_iter;
00809     }
00810   } else {
00811     // no description
00812     aDescriptionStart = start_iter;
00813     aDescriptionEnd = start_iter;
00814   }
00815 
00816   return NS_OK;
00817 }
00818 
00819 /*
00820  * This parses a normal format mime.types entry.  The format is:
00821  *
00822  * major/minor    ext1 ext2 ext3
00823  */
00824 // static
00825 nsresult
00826 nsOSHelperAppService::ParseNormalMIMETypesEntry(const nsAString& aEntry,
00827                                                 nsAString::const_iterator& aMajorTypeStart,
00828                                                 nsAString::const_iterator& aMajorTypeEnd,
00829                                                 nsAString::const_iterator& aMinorTypeStart,
00830                                                 nsAString::const_iterator& aMinorTypeEnd,
00831                                                 nsAString& aExtensions,
00832                                                 nsAString::const_iterator& aDescriptionStart,
00833                                                 nsAString::const_iterator& aDescriptionEnd) {
00834   LOG(("-- ParseNormalMIMETypesEntry\n"));
00835   NS_ASSERTION(!aEntry.IsEmpty(), "Empty Normal MIME types entry being parsed.");
00836 
00837   nsAString::const_iterator start_iter, end_iter, iter;
00838   
00839   aEntry.BeginReading(start_iter);
00840   aEntry.EndReading(end_iter);
00841 
00842   // no description
00843   aDescriptionStart = start_iter;
00844   aDescriptionEnd = start_iter;
00845 
00846   // skip leading whitespace
00847   while (start_iter != end_iter && nsCRT::IsAsciiSpace(*start_iter)) {
00848     ++start_iter;
00849   }
00850   if (start_iter == end_iter) {
00851     return NS_ERROR_FAILURE;
00852   }
00853   // skip trailing whitespace
00854   do {
00855     --end_iter;
00856   } while (end_iter != start_iter && nsCRT::IsAsciiSpace(*end_iter));
00857            
00858   ++end_iter; // point to first whitespace char (or to end of string)
00859   iter = start_iter;
00860 
00861   // get the major type
00862   if (! FindCharInReadable('/', iter, end_iter))
00863     return NS_ERROR_FAILURE;
00864 
00865   nsAString::const_iterator equals_sign_iter(start_iter);
00866   if (FindCharInReadable('=', equals_sign_iter, iter))
00867     return NS_ERROR_FAILURE; // see bug 136670
00868   
00869   aMajorTypeStart = start_iter;
00870   aMajorTypeEnd = iter;
00871   
00872   // get the minor type
00873   if (++iter == end_iter) {
00874     return NS_ERROR_FAILURE;
00875   }
00876   start_iter = iter;
00877 
00878   while (iter != end_iter && !nsCRT::IsAsciiSpace(*iter)) { 
00879     ++iter;
00880   }
00881   aMinorTypeStart = start_iter;
00882   aMinorTypeEnd = iter;
00883 
00884   // get the extensions
00885   aExtensions.Truncate();
00886   while (iter != end_iter) {
00887     while (iter != end_iter && nsCRT::IsAsciiSpace(*iter)) {
00888       ++iter;
00889     }
00890 
00891     start_iter = iter;
00892     while (iter != end_iter && !nsCRT::IsAsciiSpace(*iter)) {
00893       ++iter;
00894     }
00895     aExtensions.Append(Substring(start_iter, iter));
00896     if (iter != end_iter) { // not the last extension
00897       aExtensions.Append(PRUnichar(','));
00898     }
00899   }
00900 
00901   return NS_OK;
00902 }
00903 
00904 // static
00905 nsresult
00906 nsOSHelperAppService::LookUpHandlerAndDescription(const nsAString& aMajorType,
00907                                                   const nsAString& aMinorType,
00908                                                   nsHashtable& aTypeOptions,
00909                                                   nsAString& aHandler,
00910                                                   nsAString& aDescription,
00911                                                   nsAString& aMozillaFlags) {
00912   LOG(("-- LookUpHandlerAndDescription for type '%s/%s'\n",
00913        NS_LossyConvertUCS2toASCII(aMajorType).get(),
00914        NS_LossyConvertUCS2toASCII(aMinorType).get()));
00915   nsresult rv = NS_OK;
00916   nsXPIDLString mailcapFileName;
00917 
00918   rv = GetFileLocation("helpers.private_mailcap_file",
00919                        "PERSONAL_MAILCAP",
00920                        getter_Copies(mailcapFileName));
00921   if (NS_SUCCEEDED(rv) && !mailcapFileName.IsEmpty()) {
00922     rv = GetHandlerAndDescriptionFromMailcapFile(mailcapFileName,
00923                                                  aMajorType,
00924                                                  aMinorType,
00925                                                  aTypeOptions,
00926                                                  aHandler,
00927                                                  aDescription,
00928                                                  aMozillaFlags);
00929   } else {
00930     rv = NS_ERROR_NOT_AVAILABLE;
00931   }
00932   if (NS_FAILED(rv) || aHandler.IsEmpty()) {
00933     rv = GetFileLocation("helpers.global_mailcap_file",
00934                          "MAILCAP",
00935                          getter_Copies(mailcapFileName));
00936     if (NS_SUCCEEDED(rv) && !mailcapFileName.IsEmpty()) {
00937       rv = GetHandlerAndDescriptionFromMailcapFile(mailcapFileName,
00938                                                    aMajorType,
00939                                                    aMinorType,
00940                                                    aTypeOptions,
00941                                                    aHandler,
00942                                                    aDescription,
00943                                                    aMozillaFlags);
00944     } else {
00945       rv = NS_ERROR_NOT_AVAILABLE;
00946     }
00947   }
00948   return rv;
00949 }
00950 
00951 // static
00952 nsresult
00953 nsOSHelperAppService::GetHandlerAndDescriptionFromMailcapFile(const nsAString& aFilename,
00954                                                               const nsAString& aMajorType,
00955                                                               const nsAString& aMinorType,
00956                                                               nsHashtable& aTypeOptions,
00957                                                               nsAString& aHandler,
00958                                                               nsAString& aDescription,
00959                                                               nsAString& aMozillaFlags) {
00960 
00961   LOG(("-- GetHandlerAndDescriptionFromMailcapFile\n"));
00962   LOG(("Getting handler and description from mailcap file '%s'\n",
00963        NS_LossyConvertUCS2toASCII(aFilename).get()));
00964   LOG(("Using type '%s/%s'\n",
00965        NS_LossyConvertUCS2toASCII(aMajorType).get(),
00966        NS_LossyConvertUCS2toASCII(aMinorType).get()));
00967 
00968   nsresult rv = NS_OK;
00969   PRBool more = PR_FALSE;
00970   
00971   nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
00972   if (NS_FAILED(rv))
00973     return rv;
00974   rv = file->InitWithPath(aFilename);
00975   if (NS_FAILED(rv))
00976     return rv;
00977 
00978   nsCOMPtr<nsIFileInputStream> mailcapFile(do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
00979   if (NS_FAILED(rv))
00980     return rv;
00981   rv = mailcapFile->Init(file, -1, -1, PR_FALSE);
00982   if (NS_FAILED(rv))
00983     return rv;
00984 
00985   nsCOMPtr<nsILineInputStream> mailcap (do_QueryInterface(mailcapFile, &rv));
00986 
00987   if (NS_FAILED(rv)) {
00988     LOG(("Interface trouble in stream land!"));
00989     return rv;
00990   }
00991 
00992   nsString entry, buffer;
00993   nsCAutoString cBuffer;
00994   entry.SetCapacity(128);
00995   cBuffer.SetCapacity(80);
00996   rv = mailcap->ReadLine(cBuffer, &more);
00997   if (NS_FAILED(rv)) {
00998     mailcapFile->Close();
00999     return rv;
01000   }
01001 
01002   do {  // return on end-of-file in the loop
01003 
01004     CopyASCIItoUTF16(cBuffer, buffer);
01005     if (!buffer.IsEmpty() && buffer.First() != '#') {
01006       entry.Append(buffer);
01007       if (entry.Last() == '\\') {  // entry continues on next line
01008         entry.Truncate(entry.Length()-1);
01009         entry.Append(PRUnichar(' ')); // in case there is no trailing whitespace on this line
01010       } else {  // we have a full entry in entry.  Check it for the type
01011         LOG(("Current entry: '%s'\n",
01012              NS_LossyConvertUCS2toASCII(entry).get()));
01013 
01014         nsAString::const_iterator semicolon_iter,
01015                                   start_iter, end_iter,
01016                                   majorTypeStart, majorTypeEnd,
01017                                   minorTypeStart, minorTypeEnd;
01018         entry.BeginReading(start_iter);
01019         entry.EndReading(end_iter);
01020         semicolon_iter = start_iter;
01021         FindSemicolon(semicolon_iter, end_iter);
01022         if (semicolon_iter != end_iter) { // we have something resembling a valid entry
01023           rv = ParseMIMEType(start_iter, majorTypeStart, majorTypeEnd,
01024                              minorTypeStart, minorTypeEnd, semicolon_iter);
01025           if (NS_SUCCEEDED(rv) &&
01026               Substring(majorTypeStart,
01027                         majorTypeEnd).Equals(aMajorType,
01028                                              nsCaseInsensitiveStringComparator()) &&
01029               Substring(minorTypeStart,
01030                         minorTypeEnd).Equals(aMinorType,
01031                                              nsCaseInsensitiveStringComparator())) { // we have a match
01032             PRBool match = PR_TRUE;
01033             ++semicolon_iter;             // point at the first char past the semicolon
01034             start_iter = semicolon_iter;  // handler string starts here
01035             FindSemicolon(semicolon_iter, end_iter);
01036             while (start_iter != semicolon_iter &&
01037                    nsCRT::IsAsciiSpace(*start_iter)) {
01038               ++start_iter;
01039             }
01040 
01041             LOG(("The real handler is: '%s'\n",
01042                  NS_LossyConvertUCS2toASCII(Substring(start_iter,
01043                                                       semicolon_iter)).get()));
01044               
01045             // XXX ugly hack.  Just grab the executable name
01046             nsAString::const_iterator end_handler_iter = semicolon_iter;
01047             nsAString::const_iterator end_executable_iter = start_iter;
01048             while (end_executable_iter != end_handler_iter &&
01049                    !nsCRT::IsAsciiSpace(*end_executable_iter)) {
01050               ++end_executable_iter;
01051             }
01052             // XXX End ugly hack
01053             
01054             aHandler = Substring(start_iter, end_executable_iter);
01055             
01056             nsAString::const_iterator start_option_iter, end_optionname_iter, equal_sign_iter;
01057             PRBool equalSignFound;
01058             while (match &&
01059                    semicolon_iter != end_iter &&
01060                    ++semicolon_iter != end_iter) { // there are options left and we still match
01061               start_option_iter = semicolon_iter;
01062               // skip over leading whitespace
01063               while (start_option_iter != end_iter &&
01064                      nsCRT::IsAsciiSpace(*start_option_iter)) {
01065                 ++start_option_iter;
01066               }
01067               if (start_option_iter == end_iter) { // nothing actually here
01068                 break;
01069               }
01070               semicolon_iter = start_option_iter;
01071               FindSemicolon(semicolon_iter, end_iter);
01072               equal_sign_iter = start_option_iter;
01073               equalSignFound = PR_FALSE;
01074               while (equal_sign_iter != semicolon_iter && !equalSignFound) {
01075                 switch(*equal_sign_iter) {
01076                 case '\\':
01077                   equal_sign_iter.advance(2);
01078                   break;
01079                 case '=':
01080                   equalSignFound = PR_TRUE;
01081                   break;
01082                 default:
01083                   ++equal_sign_iter;
01084                   break;
01085                 }
01086               }
01087               end_optionname_iter = start_option_iter;
01088               // find end of option name
01089               while (end_optionname_iter != equal_sign_iter &&
01090                      !nsCRT::IsAsciiSpace(*end_optionname_iter)) {
01091                 ++end_optionname_iter;
01092               }                     
01093               nsDependentSubstring optionName(start_option_iter, end_optionname_iter);
01094               if (equalSignFound) {
01095                 // This is an option that has a name and value
01096                 if (optionName.EqualsLiteral("description")) {
01097                   aDescription = Substring(++equal_sign_iter, semicolon_iter);
01098                 } else if (optionName.EqualsLiteral("x-mozilla-flags")) {
01099                   aMozillaFlags = Substring(++equal_sign_iter, semicolon_iter);
01100                 } else if (optionName.EqualsLiteral("test")) {
01101                   nsCAutoString testCommand;
01102                   rv = UnescapeCommand(Substring(++equal_sign_iter, semicolon_iter),
01103                                        aMajorType,
01104                                        aMinorType,
01105                                        aTypeOptions,
01106                                        testCommand);
01107                   LOG(("Running Test: %s\n", testCommand.get()));
01108                   // XXX this should not use system(), since that can block the UI thread!
01109                   if (NS_SUCCEEDED(rv) && system(testCommand.get()) != 0) {
01110                     match = PR_FALSE;
01111                   }
01112                 }
01113               } else {
01114                 // This is an option that just has a name but no value (eg "copiousoutput")
01115               }
01116             }
01117             
01118 
01119             if (match) { // we did not fail any test clauses; all is good
01120               // get out of here
01121               mailcapFile->Close();
01122               return NS_OK;
01123             } else { // pretend that this match never happened
01124               aDescription.Truncate();
01125               aMozillaFlags.Truncate();
01126               aHandler.Truncate();
01127             }
01128           }
01129         }
01130         // zero out the entry for the next cycle
01131         entry.Truncate();
01132       }    
01133     }
01134     if (!more) {
01135       rv = NS_ERROR_NOT_AVAILABLE;
01136       break;
01137     }
01138     rv = mailcap->ReadLine(cBuffer, &more);
01139   } while (NS_SUCCEEDED(rv));
01140   mailcapFile->Close();
01141   return rv;
01142 }
01143 
01144 // Check OS/2 INI for application and parameters for the protocol
01145 // return NS_OK, if application exists for protocol in INI and is not empty
01146 nsresult
01147 nsOSHelperAppService::GetApplicationAndParametersFromINI(const nsACString& aProtocol,
01148                                                          char * app, ULONG appLength,
01149                                                          char * param, ULONG paramLength)
01150 {
01151   /* initialize app to '\0' for later check */
01152   *app = '\0';
01153 
01154   /* http or https */
01155   if ((aProtocol == NS_LITERAL_CSTRING("http")) ||
01156       (aProtocol == NS_LITERAL_CSTRING("https"))) {
01157     PrfQueryProfileString(HINI_USER,
01158                           "WPURLDEFAULTSETTINGS",
01159                           "DefaultBrowserExe",
01160                           "",
01161                           app,
01162                           appLength);
01163     PrfQueryProfileString(HINI_USER,
01164                           "WPURLDEFAULTSETTINGS",
01165                           "DefaultParameters",
01166                           "",
01167                           param,
01168                           paramLength);
01169   }
01170   /* mailto: */
01171   else if (aProtocol == NS_LITERAL_CSTRING("mailto")) {
01172     PrfQueryProfileString(HINI_USER,
01173                           "WPURLDEFAULTSETTINGS",
01174                           "DefaultMailExe",
01175                           "",
01176                           app,
01177                           appLength);
01178     PrfQueryProfileString(HINI_USER,
01179                           "WPURLDEFAULTSETTINGS",
01180                           "DefaultMailParameters",
01181                           "",
01182                           param,
01183                           paramLength);
01184   }
01185   /* ftp */
01186   else if (aProtocol == NS_LITERAL_CSTRING("ftp")) {
01187     PrfQueryProfileString(HINI_USER,
01188                           "WPURLDEFAULTSETTINGS",
01189                           "DefaultFTPExe",
01190                           "",
01191                           app,
01192                           appLength);
01193     PrfQueryProfileString(HINI_USER,
01194                           "WPURLDEFAULTSETTINGS",
01195                           "DefaultFTPParameters",
01196                           "",
01197                           param,
01198                           paramLength);
01199   }
01200   /* news: or snews: */
01201   else if ((aProtocol == NS_LITERAL_CSTRING("news")) ||
01202            (aProtocol == NS_LITERAL_CSTRING("snews"))) {
01203     PrfQueryProfileString(HINI_USER,
01204                           "WPURLDEFAULTSETTINGS",
01205                           "DefaultNewsExe",
01206                           "",
01207                           app,
01208                           appLength);
01209     PrfQueryProfileString(HINI_USER,
01210                           "WPURLDEFAULTSETTINGS",
01211                           "DefaultNewsParameters",
01212                           "",
01213                           param,
01214                           paramLength);
01215   }
01216   /* irc: */
01217   else if (aProtocol == NS_LITERAL_CSTRING("irc")) {
01218     PrfQueryProfileString(HINI_USER,
01219                           "WPURLDEFAULTSETTINGS",
01220                           "DefaultIRCExe",
01221                           "",
01222                           app,
01223                           appLength);
01224     PrfQueryProfileString(HINI_USER,
01225                           "WPURLDEFAULTSETTINGS",
01226                           "DefaultIRCParameters",
01227                           "",
01228                           param,
01229                           paramLength);
01230   }
01231   else {
01232     NS_WARNING("GetApplicationAndParametersFromINI(): unsupported protocol scheme");
01233     return NS_ERROR_FAILURE;
01234   }
01235 
01236   /* application string in INI was empty */
01237   if (app[0] == '\0')
01238     return NS_ERROR_FAILURE;
01239 
01240   return NS_OK;
01241 }
01242 
01243 NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
01244 {
01245   LOG(("-- nsOSHelperAppService::ExternalProtocolHandlerExists for '%s'\n",
01246        aProtocolScheme));
01247   *aHandlerExists = PR_FALSE;
01248 
01249   /* if applications.protocol is in prefs, then we have an external protocol handler */
01250   nsresult rv;
01251   nsCAutoString prefName;
01252   prefName = NS_LITERAL_CSTRING("applications.") + nsDependentCString(aProtocolScheme);
01253 
01254   nsCOMPtr<nsIPref> thePrefsService(do_GetService(NS_PREF_CONTRACTID));
01255   if (thePrefsService) {
01256     nsXPIDLCString prefString;
01257     rv = thePrefsService->CopyCharPref(prefName.get(), getter_Copies(prefString));
01258     *aHandlerExists = NS_SUCCEEDED(rv) && !prefString.IsEmpty();
01259     if (*aHandlerExists) {
01260       return NS_OK;
01261     }
01262   }
01263   /* Check the OS/2 INI for the protocol */
01264   char szAppFromINI[CCHMAXPATH];
01265   char szParamsFromINI[MAXINIPARAMLENGTH];
01266   rv = GetApplicationAndParametersFromINI(nsDependentCString(aProtocolScheme),
01267                                           szAppFromINI, sizeof(szAppFromINI),
01268                                           szParamsFromINI, sizeof(szParamsFromINI));
01269   if (NS_SUCCEEDED(rv)) {
01270     *aHandlerExists = PR_TRUE;
01271     return NS_OK;
01272   }
01273 
01274   return NS_ERROR_FAILURE;
01275 }
01276 
01277 nsresult nsOSHelperAppService::LoadUriInternal(nsIURI * aURL)
01278 {
01279   LOG(("-- nsOSHelperAppService::LoadUriInternal\n"));
01280   nsCOMPtr<nsIPref> thePrefsService(do_GetService(NS_PREF_CONTRACTID));
01281   if (!thePrefsService) {
01282     return NS_ERROR_FAILURE;
01283   }
01284 
01285   /* Convert SimpleURI to StandardURL */
01286   nsresult rv;
01287   nsCOMPtr<nsIURI> uri = do_CreateInstance(kStandardURLCID, &rv);
01288   if (NS_FAILED(rv)) {
01289     return NS_ERROR_FAILURE;
01290   }
01291   nsCAutoString urlSpec;
01292   aURL->GetSpec(urlSpec);
01293   uri->SetSpec(urlSpec);
01294 
01295   /* Get the protocol so we can look up the preferences */
01296   nsCAutoString uProtocol;
01297   uri->GetScheme(uProtocol);
01298 
01299   nsCAutoString prefName;
01300   prefName = NS_LITERAL_CSTRING("applications.") + uProtocol;
01301   nsXPIDLCString prefString;
01302 
01303   nsCAutoString applicationName;
01304   nsCAutoString parameters;
01305 
01306   rv = thePrefsService->CopyCharPref(prefName.get(), getter_Copies(prefString));
01307   if (NS_FAILED(rv) || prefString.IsEmpty()) {
01308     char szAppFromINI[CCHMAXPATH];
01309     char szParamsFromINI[MAXINIPARAMLENGTH];
01310     /* did OS2.INI contain application? */
01311     rv = GetApplicationAndParametersFromINI(uProtocol,
01312                                             szAppFromINI, sizeof(szAppFromINI),
01313                                             szParamsFromINI, sizeof(szParamsFromINI));
01314     if (NS_SUCCEEDED(rv)) {
01315       applicationName = szAppFromINI;
01316       parameters = szParamsFromINI;
01317     } else {
01318       return NS_ERROR_FAILURE;
01319     }
01320   }
01321 
01322   // Dissect the URI
01323   nsCAutoString uURL, uUsername, uPassword, uHost, uPort, uPath;
01324   nsCAutoString uEmail, uGroup;
01325   PRInt32 iPort;
01326 
01327   // when passing to OS/2 apps later, we need ASCII URLs,
01328   // UTF-8 would probably not get handled correctly
01329   aURL->GetAsciiSpec(uURL);
01330   uri->GetAsciiHost(uHost);
01331   uri->GetUsername(uUsername);
01332   NS_UnescapeURL(uUsername);
01333   uri->GetPassword(uPassword);
01334   NS_UnescapeURL(uPassword);
01335   uri->GetPort(&iPort);
01336   /* GetPort returns -1 if there is no port in the URI */
01337   if (iPort != -1)
01338     uPort.AppendInt(iPort);
01339   uri->GetPath(uPath);
01340   NS_UnescapeURL(uPath);
01341 
01342   // One could use nsIMailtoUrl to get email and newsgroup,
01343   // but it is probably easier to do that quickly by hand here
01344   // uEmail is both email address and message id  for news
01345   uEmail = uUsername + NS_LITERAL_CSTRING("@") + uHost;
01346   // uPath can almost be used as newsgroup and as channel for IRC
01347   // but strip leading "/"
01348   uGroup = Substring(uPath, 1, uPath.Length());
01349 
01350   NS_NAMED_LITERAL_CSTRING(url, "%url%");
01351   NS_NAMED_LITERAL_CSTRING(username, "%username%");
01352   NS_NAMED_LITERAL_CSTRING(password, "%password%");
01353   NS_NAMED_LITERAL_CSTRING(host, "%host%");
01354   NS_NAMED_LITERAL_CSTRING(port, "%port%");
01355   NS_NAMED_LITERAL_CSTRING(email, "%email%");
01356   NS_NAMED_LITERAL_CSTRING(group, "%group%");
01357   NS_NAMED_LITERAL_CSTRING(msgid, "%msgid%");
01358   NS_NAMED_LITERAL_CSTRING(channel, "%channel%");
01359 
01360   PRBool replaced = PR_FALSE;
01361   if (applicationName.IsEmpty() && parameters.IsEmpty()) {
01362     /* Put application name in parameters */
01363     applicationName.Append(prefString);
01364 
01365     prefName.Append(".");
01366     nsCOMPtr<nsIPrefBranch> prefBranch;
01367     rv = thePrefsService->GetBranch(prefName.get(), getter_AddRefs(prefBranch));
01368     if (NS_SUCCEEDED(rv) && prefBranch) {
01369       rv = prefBranch->GetCharPref("parameters", getter_Copies(prefString));
01370       /* If parameters have been specified, use them instead of the separate entities */
01371       if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
01372         parameters.Append(" ");
01373         parameters.Append(prefString);
01374 
01375         PRInt32 pos = parameters.Find(url.get());
01376         if (pos != kNotFound) {
01377           nsCAutoString uURL;
01378           aURL->GetSpec(uURL);
01379           NS_UnescapeURL(uURL);
01380           uURL.Cut(0, uProtocol.Length()+1);
01381           parameters.Replace(pos, url.Length(), uURL);
01382           replaced = PR_TRUE;
01383         }
01384       } else {
01385         /* port */
01386         if (!uPort.IsEmpty()) {
01387           rv = prefBranch->GetCharPref("port", getter_Copies(prefString));
01388           if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
01389             parameters.Append(" ");
01390             parameters.Append(prefString);
01391           }
01392         }
01393         /* username */
01394         if (!uUsername.IsEmpty()) {
01395           rv = prefBranch->GetCharPref("username", getter_Copies(prefString));
01396           if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
01397             parameters.Append(" ");
01398             parameters.Append(prefString);
01399           }
01400         }
01401         /* password */
01402         if (!uPassword.IsEmpty()) {
01403           rv = prefBranch->GetCharPref("password", getter_Copies(prefString));
01404           if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
01405             parameters.Append(" ");
01406             parameters.Append(prefString);
01407           }
01408         }
01409         /* host */
01410         if (!uHost.IsEmpty()) {
01411           rv = prefBranch->GetCharPref("host", getter_Copies(prefString));
01412           if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
01413             parameters.Append(" ");
01414             parameters.Append(prefString);
01415           }
01416         }
01417       }
01418     }
01419   }
01420 
01421 #ifdef DEBUG_peter
01422   printf("uURL=%s\n", uURL.get());
01423   printf("uUsername=%s\n", uUsername.get());
01424   printf("uPassword=%s\n", uPassword.get());
01425   printf("uHost=%s\n", uHost.get());
01426   printf("uPort=%s\n", uPort.get());
01427   printf("uPath=%s\n", uPath.get());
01428   printf("uEmail=%s\n", uEmail.get());
01429   printf("uGroup=%s\n", uGroup.get());
01430 #endif
01431 
01432   PRInt32 pos;
01433   pos = parameters.Find(url.get());
01434   if (pos != kNotFound) {
01435     replaced = PR_TRUE;
01436     parameters.Replace(pos, url.Length(), uURL);
01437   }
01438   pos = parameters.Find(username.get());
01439   if (pos != kNotFound) {
01440     replaced = PR_TRUE;
01441     parameters.Replace(pos, username.Length(), uUsername);
01442   }
01443   pos = parameters.Find(password.get());
01444   if (pos != kNotFound) {
01445     replaced = PR_TRUE;
01446     parameters.Replace(pos, password.Length(), uPassword);
01447   }
01448   pos = parameters.Find(host.get());
01449   if (pos != kNotFound) {
01450     replaced = PR_TRUE;
01451     parameters.Replace(pos, host.Length(), uHost);
01452   }
01453   pos = parameters.Find(port.get());
01454   if (pos != kNotFound) {
01455     replaced = PR_TRUE;
01456     parameters.Replace(pos, port.Length(), uPort);
01457   }
01458   pos = parameters.Find(email.get());
01459   if (pos != kNotFound) {
01460     replaced = PR_TRUE;
01461     parameters.Replace(pos, email.Length(), uEmail);
01462   }
01463   pos = parameters.Find(group.get());
01464   if (pos != kNotFound) {
01465     replaced = PR_TRUE;
01466     parameters.Replace(pos, group.Length(), uGroup);
01467   }
01468   pos = parameters.Find(msgid.get());
01469   if (pos != kNotFound) {
01470     replaced = PR_TRUE;
01471     parameters.Replace(pos, msgid.Length(), uEmail);
01472   }
01473   pos = parameters.Find(channel.get());
01474   if (pos != kNotFound) {
01475     replaced = PR_TRUE;
01476     parameters.Replace(pos, channel.Length(), uGroup);
01477   }
01478   // If no replacement variable was used, the user most likely uses the WPS URL
01479   // object and does not know about the replacement variables.
01480   // Just append the full URL.
01481   if (!replaced) {
01482     parameters.Append(" ");
01483     parameters.Append(uURL);
01484   }
01485 
01486   const char *params[3];
01487   params[0] = parameters.get();
01488 #ifdef DEBUG_peter
01489   printf("params[0]=%s\n", params[0]);
01490 #endif
01491   PRInt32 numParams = 1;
01492 
01493   nsCOMPtr<nsILocalFile> application;
01494   rv = NS_NewNativeLocalFile(nsDependentCString(applicationName.get()), PR_FALSE, getter_AddRefs(application));
01495   if (NS_FAILED(rv)) {
01496      /* Maybe they didn't qualify the name - search path */
01497      char szAppPath[CCHMAXPATH];
01498      APIRET rc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT,
01499                                "PATH", applicationName.get(),
01500                                szAppPath, sizeof(szAppPath));
01501      if (rc == NO_ERROR) {
01502        rv = NS_NewNativeLocalFile(nsDependentCString(szAppPath), PR_FALSE, getter_AddRefs(application));
01503      }
01504      if (NS_FAILED(rv) || (rc != NO_ERROR)) {
01505        /* Try just launching it with COMSPEC */
01506        rv = NS_NewNativeLocalFile(nsDependentCString(getenv("COMSPEC")), PR_FALSE, getter_AddRefs(application));
01507        if (NS_FAILED(rv)) {
01508          return rv;
01509        }
01510 
01511        params[0] = "/c";
01512        params[1] = applicationName.get();
01513        params[2] = parameters.get();
01514        numParams = 3;
01515      }
01516   }
01517 
01518   nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID);
01519 
01520   if (NS_FAILED(rv = process->Init(application)))
01521      return rv;
01522 
01523   PRUint32 pid;
01524   if (NS_FAILED(rv = process->Run(PR_FALSE, params, numParams, &pid)))
01525     return rv;
01526 
01527   return NS_OK;
01528 }
01529 
01530 already_AddRefed<nsMIMEInfoOS2>
01531 nsOSHelperAppService::GetFromExtension(const nsCString& aFileExt) {
01532   // if the extension is empty, return immediately
01533   if (aFileExt.IsEmpty())
01534     return nsnull;
01535   
01536   LOG(("Here we do an extension lookup for '%s'\n", aFileExt.get()));
01537 
01538   nsresult rv;
01539 
01540   nsAutoString majorType, minorType,
01541                mime_types_description, mailcap_description,
01542                handler, mozillaFlags;
01543   
01544   rv = LookUpTypeAndDescription(NS_ConvertUTF8toUCS2(aFileExt),
01545                                 majorType,
01546                                 minorType,
01547                                 mime_types_description);
01548   if (NS_FAILED(rv))
01549     return nsnull;
01550 
01551   NS_LossyConvertUTF16toASCII asciiMajorType(majorType);
01552   NS_LossyConvertUTF16toASCII asciiMinorType(minorType);
01553 
01554   LOG(("Type/Description results:  majorType='%s', minorType='%s', description='%s'\n",
01555           asciiMajorType.get(),
01556           asciiMinorType.get(),
01557           NS_LossyConvertUCS2toASCII(mime_types_description).get()));
01558 
01559   if (majorType.IsEmpty() && minorType.IsEmpty()) {
01560     // we didn't get a type mapping, so we can't do anything useful
01561     return nsnull;
01562   }
01563 
01564   nsCAutoString mimeType(asciiMajorType + NS_LITERAL_CSTRING("/") + asciiMinorType);
01565   nsMIMEInfoOS2* mimeInfo = new nsMIMEInfoOS2(mimeType);
01566   if (!mimeInfo)
01567     return nsnull;
01568   NS_ADDREF(mimeInfo);
01569   
01570   mimeInfo->AppendExtension(aFileExt);
01571   nsHashtable typeOptions; // empty hash table
01572   // The mailcap lookup is two-pass to handle the case of mailcap files
01573   // that have something like:
01574   //
01575   // text/*; emacs %s
01576   // text/rtf; soffice %s
01577   //
01578   // in that order.  We want to pick up "soffice" for text/rtf in such cases
01579   rv = LookUpHandlerAndDescription(majorType, minorType, typeOptions,
01580                                    handler, mailcap_description,
01581                                    mozillaFlags);
01582   if (NS_FAILED(rv)) {
01583     // maybe we have an entry for "majorType/*"?
01584     rv = LookUpHandlerAndDescription(majorType, NS_LITERAL_STRING("*"),
01585                                      typeOptions, handler, mailcap_description,
01586                                      mozillaFlags);
01587   }
01588   LOG(("Handler/Description results:  handler='%s', description='%s', mozillaFlags='%s'\n",
01589           NS_LossyConvertUCS2toASCII(handler).get(),
01590           NS_LossyConvertUCS2toASCII(mailcap_description).get(),
01591           NS_LossyConvertUCS2toASCII(mozillaFlags).get()));
01592   mailcap_description.Trim(" \t\"");
01593   mozillaFlags.Trim(" \t");
01594   if (!mime_types_description.IsEmpty()) {
01595     mimeInfo->SetDescription(mime_types_description);
01596   } else {
01597     mimeInfo->SetDescription(mailcap_description);
01598   }
01599   if (NS_SUCCEEDED(rv) && !handler.IsEmpty()) {
01600     nsCOMPtr<nsIFile> handlerFile;
01601     rv = GetFileTokenForPath(handler.get(), getter_AddRefs(handlerFile));
01602     
01603     if (NS_SUCCEEDED(rv)) {
01604       mimeInfo->SetDefaultApplication(handlerFile);
01605       mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
01606       mimeInfo->SetDefaultDescription(handler);
01607     }
01608   } else {
01609     mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
01610   }
01611 
01612   return mimeInfo;
01613 }
01614 
01615 already_AddRefed<nsMIMEInfoOS2>
01616 nsOSHelperAppService::GetFromType(const nsCString& aMIMEType) {
01617   // if the extension is empty, return immediately
01618   if (aMIMEType.IsEmpty())
01619     return nsnull;
01620   
01621   LOG(("Here we do a mimetype lookup for '%s'\n", aMIMEType.get()));
01622   nsresult rv;
01623   nsAutoString extensions,
01624     mime_types_description, mailcap_description,
01625     handler, mozillaFlags;
01626 
01627   nsHashtable typeOptions;
01628   
01629   // extract the major and minor types
01630   NS_ConvertASCIItoUTF16 mimeType(aMIMEType);
01631   nsAString::const_iterator start_iter, end_iter,
01632                             majorTypeStart, majorTypeEnd,
01633                             minorTypeStart, minorTypeEnd;
01634 
01635   mimeType.BeginReading(start_iter);
01636   mimeType.EndReading(end_iter);
01637 
01638   // XXX FIXME: add typeOptions parsing in here
01639   rv = ParseMIMEType(start_iter, majorTypeStart, majorTypeEnd,
01640                      minorTypeStart, minorTypeEnd, end_iter);
01641 
01642   if (NS_FAILED(rv)) {
01643     return nsnull;
01644   }
01645 
01646   nsDependentSubstring majorType(majorTypeStart, majorTypeEnd);
01647   nsDependentSubstring minorType(minorTypeStart, minorTypeEnd);
01648   // The mailcap lookup is two-pass to handle the case of mailcap files
01649   // that have something like:
01650   //
01651   // text/*; emacs %s
01652   // text/rtf; soffice %s
01653   //
01654   // in that order.  We want to pick up "soffice" for text/rtf in such cases
01655   rv = LookUpHandlerAndDescription(majorType,
01656                                    minorType,
01657                                    typeOptions,
01658                                    handler,
01659                                    mailcap_description,
01660                                    mozillaFlags);
01661   if (NS_FAILED(rv)) {
01662     // maybe we have an entry for "majorType/*"?
01663     rv = LookUpHandlerAndDescription(majorType,
01664                                      NS_LITERAL_STRING("*"),
01665                                      typeOptions,
01666                                      handler,
01667                                      mailcap_description,
01668                                      mozillaFlags);
01669   }
01670   LOG(("Handler/Description results:  handler='%s', description='%s', mozillaFlags='%s'\n",
01671           NS_LossyConvertUCS2toASCII(handler).get(),
01672           NS_LossyConvertUCS2toASCII(mailcap_description).get(),
01673           NS_LossyConvertUCS2toASCII(mozillaFlags).get()));
01674   
01675   if (handler.IsEmpty()) {
01676     // we have no useful info....
01677     return nsnull;
01678   }
01679   
01680   mailcap_description.Trim(" \t\"");
01681   mozillaFlags.Trim(" \t");
01682   LookUpExtensionsAndDescription(majorType,
01683                                  minorType,
01684                                  extensions,
01685                                  mime_types_description);
01686 
01687   nsMIMEInfoOS2* mimeInfo = new nsMIMEInfoOS2(aMIMEType);
01688   if (!mimeInfo)
01689     return nsnull;
01690   NS_ADDREF(mimeInfo);
01691 
01692   mimeInfo->SetFileExtensions(NS_ConvertUCS2toUTF8(extensions));
01693   if (! mime_types_description.IsEmpty()) {
01694     mimeInfo->SetDescription(mime_types_description);
01695   } else {
01696     mimeInfo->SetDescription(mailcap_description);
01697   }
01698 
01699   nsCOMPtr<nsIFile> handlerFile;
01700   rv = GetFileTokenForPath(handler.get(), getter_AddRefs(handlerFile));
01701   
01702   if (NS_SUCCEEDED(rv)) {
01703     mimeInfo->SetDefaultApplication(handlerFile);
01704     mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
01705     mimeInfo->SetDefaultDescription(handler);
01706   } else {
01707     mimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
01708   }
01709 
01710   return mimeInfo;
01711 }
01712 
01713 
01714 already_AddRefed<nsIMIMEInfo>
01715 nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aType,
01716                                         const nsACString& aFileExt,
01717                                         PRBool     *aFound) {
01718   *aFound = PR_TRUE;
01719   nsMIMEInfoOS2* retval = GetFromType(PromiseFlatCString(aType)).get();
01720   PRBool hasDefault = PR_FALSE;
01721   if (retval)
01722     retval->GetHasDefaultHandler(&hasDefault);
01723   if (!retval || !hasDefault) {
01724     nsRefPtr<nsMIMEInfoOS2> miByExt = GetFromExtension(PromiseFlatCString(aFileExt));
01725     // If we had no extension match, but a type match, use that
01726     if (!miByExt && retval)
01727       return retval;
01728     // If we had an extension match but no type match, set the mimetype and use
01729     // it
01730     if (!retval && miByExt) {
01731       if (!aType.IsEmpty())
01732         miByExt->SetMIMEType(aType);
01733       miByExt.swap(retval);
01734 
01735       return retval;
01736     }
01737     // If we got nothing, make a new mimeinfo
01738     if (!retval) {
01739       *aFound = PR_FALSE;
01740       retval = new nsMIMEInfoOS2(aType);
01741       if (retval) {
01742         NS_ADDREF(retval);
01743         if (!aFileExt.IsEmpty())
01744           retval->AppendExtension(aFileExt);
01745       }
01746       
01747       return retval;
01748     }
01749 
01750     // Copy the attributes of retval onto miByExt, to return it
01751     retval->CopyBasicDataTo(miByExt);
01752 
01753     miByExt.swap(retval);
01754   }
01755   return retval;
01756 }
01757 
01758 
01759 NS_IMETHODIMP
01760 nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
01761 {
01762   nsCOMPtr<nsIPref> thePrefsService(do_GetService(NS_PREF_CONTRACTID));
01763   if (!thePrefsService) {
01764     return NS_ERROR_FAILURE;
01765   }
01766   nsCAutoString prefName = NS_LITERAL_CSTRING("applications.") + aScheme;
01767   nsXPIDLCString prefString;
01768   nsCAutoString applicationName;
01769 
01770   nsresult rv = thePrefsService->CopyCharPref(prefName.get(), getter_Copies(prefString));
01771   if (NS_FAILED(rv) || prefString.IsEmpty()) {
01772     char szAppFromINI[CCHMAXPATH];
01773     char szParamsFromINI[MAXINIPARAMLENGTH];
01774     /* did OS2.INI contain application? */
01775     rv = GetApplicationAndParametersFromINI(aScheme,
01776                                             szAppFromINI, sizeof(szAppFromINI),
01777                                             szParamsFromINI, sizeof(szParamsFromINI));
01778     if (NS_SUCCEEDED(rv)) {
01779       applicationName = szAppFromINI;
01780     } else {
01781       return NS_ERROR_NOT_AVAILABLE;
01782     }
01783   } else {
01784     applicationName.Append(prefString);
01785   }
01786 
01787 
01788   nsCOMPtr<nsILocalFile> application;
01789   rv = NS_NewNativeLocalFile(nsDependentCString(applicationName.get()),
01790                              PR_FALSE,
01791                              getter_AddRefs(application));
01792   if (NS_FAILED(rv)) {
01793     char szAppPath[CCHMAXPATH];
01794     APIRET rc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT,
01795                               "PATH",
01796                               applicationName.get(),
01797                               szAppPath,
01798                               sizeof(szAppPath));
01799     /* if that worked, we can use the full pathname */
01800     if (rc == NO_ERROR) {
01801       _retval.Assign(NS_ConvertUTF8toUTF16(nsDependentCString(szAppPath)));
01802       return NS_OK;
01803     }
01804   }
01805   /* if the full path is given or not, use what we have */
01806   _retval.Assign(NS_ConvertUTF8toUTF16(applicationName));
01807   return NS_OK;
01808 }
01809