uriloader/exthandler/unix/nsOSHelperAppService.cpp

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

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

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

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

mercurial