1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,436 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsMIMEInfoImpl.h" 1.11 +#include "nsXPIDLString.h" 1.12 +#include "nsReadableUtils.h" 1.13 +#include "nsStringEnumerator.h" 1.14 +#include "nsIFile.h" 1.15 +#include "nsIFileURL.h" 1.16 +#include "nsEscape.h" 1.17 +#include "nsNetUtil.h" 1.18 +#include "nsIURILoader.h" 1.19 +#include "nsCURILoader.h" 1.20 + 1.21 +// nsISupports methods 1.22 +NS_IMPL_ADDREF(nsMIMEInfoBase) 1.23 +NS_IMPL_RELEASE(nsMIMEInfoBase) 1.24 + 1.25 +NS_INTERFACE_MAP_BEGIN(nsMIMEInfoBase) 1.26 + NS_INTERFACE_MAP_ENTRY(nsIHandlerInfo) 1.27 + // This is only an nsIMIMEInfo if it's a MIME handler. 1.28 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMIMEInfo, mClass == eMIMEInfo) 1.29 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHandlerInfo) 1.30 +NS_INTERFACE_MAP_END_THREADSAFE 1.31 + 1.32 +// nsMIMEInfoImpl methods 1.33 + 1.34 +// Constructors for a MIME handler. 1.35 +nsMIMEInfoBase::nsMIMEInfoBase(const char *aMIMEType) : 1.36 + mSchemeOrType(aMIMEType), 1.37 + mClass(eMIMEInfo), 1.38 + mPreferredAction(nsIMIMEInfo::saveToDisk), 1.39 + mAlwaysAskBeforeHandling(true) 1.40 +{ 1.41 +} 1.42 + 1.43 +nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aMIMEType) : 1.44 + mSchemeOrType(aMIMEType), 1.45 + mClass(eMIMEInfo), 1.46 + mPreferredAction(nsIMIMEInfo::saveToDisk), 1.47 + mAlwaysAskBeforeHandling(true) 1.48 +{ 1.49 +} 1.50 + 1.51 +// Constructor for a handler that lets the caller specify whether this is a 1.52 +// MIME handler or a protocol handler. In the long run, these will be distinct 1.53 +// classes (f.e. nsMIMEInfo and nsProtocolInfo), but for now we reuse this class 1.54 +// for both and distinguish between the two kinds of handlers via the aClass 1.55 +// argument to this method, which can be either eMIMEInfo or eProtocolInfo. 1.56 +nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aType, HandlerClass aClass) : 1.57 + mSchemeOrType(aType), 1.58 + mClass(aClass), 1.59 + mPreferredAction(nsIMIMEInfo::saveToDisk), 1.60 + mAlwaysAskBeforeHandling(true) 1.61 +{ 1.62 +} 1.63 + 1.64 +nsMIMEInfoBase::~nsMIMEInfoBase() 1.65 +{ 1.66 +} 1.67 + 1.68 +NS_IMETHODIMP 1.69 +nsMIMEInfoBase::GetFileExtensions(nsIUTF8StringEnumerator** aResult) 1.70 +{ 1.71 + return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this); 1.72 +} 1.73 + 1.74 +NS_IMETHODIMP 1.75 +nsMIMEInfoBase::ExtensionExists(const nsACString& aExtension, bool *_retval) 1.76 +{ 1.77 + NS_ASSERTION(!aExtension.IsEmpty(), "no extension"); 1.78 + bool found = false; 1.79 + uint32_t extCount = mExtensions.Length(); 1.80 + if (extCount < 1) return NS_OK; 1.81 + 1.82 + for (uint8_t i=0; i < extCount; i++) { 1.83 + const nsCString& ext = mExtensions[i]; 1.84 + if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) { 1.85 + found = true; 1.86 + break; 1.87 + } 1.88 + } 1.89 + 1.90 + *_retval = found; 1.91 + return NS_OK; 1.92 +} 1.93 + 1.94 +NS_IMETHODIMP 1.95 +nsMIMEInfoBase::GetPrimaryExtension(nsACString& _retval) 1.96 +{ 1.97 + if (!mExtensions.Length()) 1.98 + return NS_ERROR_NOT_INITIALIZED; 1.99 + 1.100 + _retval = mExtensions[0]; 1.101 + return NS_OK; 1.102 +} 1.103 + 1.104 +NS_IMETHODIMP 1.105 +nsMIMEInfoBase::SetPrimaryExtension(const nsACString& aExtension) 1.106 +{ 1.107 + NS_ASSERTION(!aExtension.IsEmpty(), "no extension"); 1.108 + uint32_t extCount = mExtensions.Length(); 1.109 + uint8_t i; 1.110 + bool found = false; 1.111 + for (i=0; i < extCount; i++) { 1.112 + const nsCString& ext = mExtensions[i]; 1.113 + if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) { 1.114 + found = true; 1.115 + break; 1.116 + } 1.117 + } 1.118 + if (found) { 1.119 + mExtensions.RemoveElementAt(i); 1.120 + } 1.121 + 1.122 + mExtensions.InsertElementAt(0, aExtension); 1.123 + 1.124 + return NS_OK; 1.125 +} 1.126 + 1.127 +NS_IMETHODIMP 1.128 +nsMIMEInfoBase::AppendExtension(const nsACString& aExtension) 1.129 +{ 1.130 + mExtensions.AppendElement(aExtension); 1.131 + return NS_OK; 1.132 +} 1.133 + 1.134 +NS_IMETHODIMP 1.135 +nsMIMEInfoBase::GetType(nsACString& aType) 1.136 +{ 1.137 + if (mSchemeOrType.IsEmpty()) 1.138 + return NS_ERROR_NOT_INITIALIZED; 1.139 + 1.140 + aType = mSchemeOrType; 1.141 + return NS_OK; 1.142 +} 1.143 + 1.144 +NS_IMETHODIMP 1.145 +nsMIMEInfoBase::GetMIMEType(nsACString& aMIMEType) 1.146 +{ 1.147 + if (mSchemeOrType.IsEmpty()) 1.148 + return NS_ERROR_NOT_INITIALIZED; 1.149 + 1.150 + aMIMEType = mSchemeOrType; 1.151 + return NS_OK; 1.152 +} 1.153 + 1.154 +NS_IMETHODIMP 1.155 +nsMIMEInfoBase::GetDescription(nsAString& aDescription) 1.156 +{ 1.157 + aDescription = mDescription; 1.158 + return NS_OK; 1.159 +} 1.160 + 1.161 +NS_IMETHODIMP 1.162 +nsMIMEInfoBase::SetDescription(const nsAString& aDescription) 1.163 +{ 1.164 + mDescription = aDescription; 1.165 + return NS_OK; 1.166 +} 1.167 + 1.168 +NS_IMETHODIMP 1.169 +nsMIMEInfoBase::Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval) 1.170 +{ 1.171 + if (!aMIMEInfo) return NS_ERROR_NULL_POINTER; 1.172 + 1.173 + nsAutoCString type; 1.174 + nsresult rv = aMIMEInfo->GetMIMEType(type); 1.175 + if (NS_FAILED(rv)) return rv; 1.176 + 1.177 + *_retval = mSchemeOrType.Equals(type); 1.178 + 1.179 + return NS_OK; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +nsMIMEInfoBase::SetFileExtensions(const nsACString& aExtensions) 1.184 +{ 1.185 + mExtensions.Clear(); 1.186 + nsCString extList( aExtensions ); 1.187 + 1.188 + int32_t breakLocation = -1; 1.189 + while ( (breakLocation= extList.FindChar(',') )!= -1) 1.190 + { 1.191 + mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation)); 1.192 + extList.Cut(0, breakLocation+1 ); 1.193 + } 1.194 + if ( !extList.IsEmpty() ) 1.195 + mExtensions.AppendElement( extList ); 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +NS_IMETHODIMP 1.200 +nsMIMEInfoBase::GetDefaultDescription(nsAString& aDefaultDescription) 1.201 +{ 1.202 + aDefaultDescription = mDefaultAppDescription; 1.203 + return NS_OK; 1.204 +} 1.205 + 1.206 +NS_IMETHODIMP 1.207 +nsMIMEInfoBase::GetPreferredApplicationHandler(nsIHandlerApp ** aPreferredAppHandler) 1.208 +{ 1.209 + *aPreferredAppHandler = mPreferredApplication; 1.210 + NS_IF_ADDREF(*aPreferredAppHandler); 1.211 + return NS_OK; 1.212 +} 1.213 + 1.214 +NS_IMETHODIMP 1.215 +nsMIMEInfoBase::SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler) 1.216 +{ 1.217 + mPreferredApplication = aPreferredAppHandler; 1.218 + return NS_OK; 1.219 +} 1.220 + 1.221 +NS_IMETHODIMP 1.222 +nsMIMEInfoBase::GetPossibleApplicationHandlers(nsIMutableArray ** aPossibleAppHandlers) 1.223 +{ 1.224 + if (!mPossibleApplications) 1.225 + mPossibleApplications = do_CreateInstance(NS_ARRAY_CONTRACTID); 1.226 + 1.227 + if (!mPossibleApplications) 1.228 + return NS_ERROR_OUT_OF_MEMORY; 1.229 + 1.230 + *aPossibleAppHandlers = mPossibleApplications; 1.231 + NS_IF_ADDREF(*aPossibleAppHandlers); 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +NS_IMETHODIMP 1.236 +nsMIMEInfoBase::GetPreferredAction(nsHandlerInfoAction * aPreferredAction) 1.237 +{ 1.238 + *aPreferredAction = mPreferredAction; 1.239 + return NS_OK; 1.240 +} 1.241 + 1.242 +NS_IMETHODIMP 1.243 +nsMIMEInfoBase::SetPreferredAction(nsHandlerInfoAction aPreferredAction) 1.244 +{ 1.245 + mPreferredAction = aPreferredAction; 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +NS_IMETHODIMP 1.250 +nsMIMEInfoBase::GetAlwaysAskBeforeHandling(bool * aAlwaysAsk) 1.251 +{ 1.252 + *aAlwaysAsk = mAlwaysAskBeforeHandling; 1.253 + 1.254 + return NS_OK; 1.255 +} 1.256 + 1.257 +NS_IMETHODIMP 1.258 +nsMIMEInfoBase::SetAlwaysAskBeforeHandling(bool aAlwaysAsk) 1.259 +{ 1.260 + mAlwaysAskBeforeHandling = aAlwaysAsk; 1.261 + return NS_OK; 1.262 +} 1.263 + 1.264 +/* static */ 1.265 +nsresult 1.266 +nsMIMEInfoBase::GetLocalFileFromURI(nsIURI *aURI, nsIFile **aFile) 1.267 +{ 1.268 + nsresult rv; 1.269 + 1.270 + nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(aURI, &rv); 1.271 + if (NS_FAILED(rv)) { 1.272 + return rv; 1.273 + } 1.274 + 1.275 + nsCOMPtr<nsIFile> file; 1.276 + rv = fileUrl->GetFile(getter_AddRefs(file)); 1.277 + if (NS_FAILED(rv)) { 1.278 + return rv; 1.279 + } 1.280 + 1.281 + file.forget(aFile); 1.282 + return NS_OK; 1.283 +} 1.284 + 1.285 +NS_IMETHODIMP 1.286 +nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile) 1.287 +{ 1.288 + nsresult rv; 1.289 + 1.290 + // it doesn't make any sense to call this on protocol handlers 1.291 + NS_ASSERTION(mClass == eMIMEInfo, 1.292 + "nsMIMEInfoBase should have mClass == eMIMEInfo"); 1.293 + 1.294 + if (mPreferredAction == useSystemDefault) { 1.295 + return LaunchDefaultWithFile(aFile); 1.296 + } 1.297 + 1.298 + if (mPreferredAction == useHelperApp) { 1.299 + if (!mPreferredApplication) 1.300 + return NS_ERROR_FILE_NOT_FOUND; 1.301 + 1.302 + // at the moment, we only know how to hand files off to local handlers 1.303 + nsCOMPtr<nsILocalHandlerApp> localHandler = 1.304 + do_QueryInterface(mPreferredApplication, &rv); 1.305 + NS_ENSURE_SUCCESS(rv, rv); 1.306 + 1.307 + nsCOMPtr<nsIFile> executable; 1.308 + rv = localHandler->GetExecutable(getter_AddRefs(executable)); 1.309 + NS_ENSURE_SUCCESS(rv, rv); 1.310 + 1.311 + nsAutoCString path; 1.312 + aFile->GetNativePath(path); 1.313 + return LaunchWithIProcess(executable, path); 1.314 + } 1.315 + 1.316 + return NS_ERROR_INVALID_ARG; 1.317 +} 1.318 + 1.319 +NS_IMETHODIMP 1.320 +nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI, 1.321 + nsIInterfaceRequestor* aWindowContext) 1.322 +{ 1.323 + // for now, this is only being called with protocol handlers; that 1.324 + // will change once we get to more general registerContentHandler 1.325 + // support 1.326 + NS_ASSERTION(mClass == eProtocolInfo, 1.327 + "nsMIMEInfoBase should be a protocol handler"); 1.328 + 1.329 + if (mPreferredAction == useSystemDefault) { 1.330 + return LoadUriInternal(aURI); 1.331 + } 1.332 + 1.333 + if (mPreferredAction == useHelperApp) { 1.334 + if (!mPreferredApplication) 1.335 + return NS_ERROR_FILE_NOT_FOUND; 1.336 + 1.337 + return mPreferredApplication->LaunchWithURI(aURI, aWindowContext); 1.338 + } 1.339 + 1.340 + return NS_ERROR_INVALID_ARG; 1.341 +} 1.342 + 1.343 +void 1.344 +nsMIMEInfoBase::CopyBasicDataTo(nsMIMEInfoBase* aOther) 1.345 +{ 1.346 + aOther->mSchemeOrType = mSchemeOrType; 1.347 + aOther->mDefaultAppDescription = mDefaultAppDescription; 1.348 + aOther->mExtensions = mExtensions; 1.349 +} 1.350 + 1.351 +/* static */ 1.352 +already_AddRefed<nsIProcess> 1.353 +nsMIMEInfoBase::InitProcess(nsIFile* aApp, nsresult* aResult) 1.354 +{ 1.355 + NS_ASSERTION(aApp, "Unexpected null pointer, fix caller"); 1.356 + 1.357 + nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID, 1.358 + aResult); 1.359 + if (NS_FAILED(*aResult)) 1.360 + return nullptr; 1.361 + 1.362 + *aResult = process->Init(aApp); 1.363 + if (NS_FAILED(*aResult)) 1.364 + return nullptr; 1.365 + 1.366 + return process.forget(); 1.367 +} 1.368 + 1.369 +/* static */ 1.370 +nsresult 1.371 +nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsCString& aArg) 1.372 +{ 1.373 + nsresult rv; 1.374 + nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv); 1.375 + if (NS_FAILED(rv)) 1.376 + return rv; 1.377 + 1.378 + const char *string = aArg.get(); 1.379 + 1.380 + return process->Run(false, &string, 1); 1.381 +} 1.382 + 1.383 +/* static */ 1.384 +nsresult 1.385 +nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsString& aArg) 1.386 +{ 1.387 + nsresult rv; 1.388 + nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv); 1.389 + if (NS_FAILED(rv)) 1.390 + return rv; 1.391 + 1.392 + const char16_t *string = aArg.get(); 1.393 + 1.394 + return process->Runw(false, &string, 1); 1.395 +} 1.396 + 1.397 +// nsMIMEInfoImpl implementation 1.398 +NS_IMETHODIMP 1.399 +nsMIMEInfoImpl::GetDefaultDescription(nsAString& aDefaultDescription) 1.400 +{ 1.401 + if (mDefaultAppDescription.IsEmpty() && mDefaultApplication) { 1.402 + // Don't want to cache this, just in case someone resets the app 1.403 + // without changing the description.... 1.404 + mDefaultApplication->GetLeafName(aDefaultDescription); 1.405 + } else { 1.406 + aDefaultDescription = mDefaultAppDescription; 1.407 + } 1.408 + 1.409 + return NS_OK; 1.410 +} 1.411 + 1.412 +NS_IMETHODIMP 1.413 +nsMIMEInfoImpl::GetHasDefaultHandler(bool * _retval) 1.414 +{ 1.415 + *_retval = !mDefaultAppDescription.IsEmpty(); 1.416 + if (mDefaultApplication) { 1.417 + bool exists; 1.418 + *_retval = NS_SUCCEEDED(mDefaultApplication->Exists(&exists)) && exists; 1.419 + } 1.420 + return NS_OK; 1.421 +} 1.422 + 1.423 +nsresult 1.424 +nsMIMEInfoImpl::LaunchDefaultWithFile(nsIFile* aFile) 1.425 +{ 1.426 + if (!mDefaultApplication) 1.427 + return NS_ERROR_FILE_NOT_FOUND; 1.428 + 1.429 + nsAutoCString nativePath; 1.430 + aFile->GetNativePath(nativePath); 1.431 + 1.432 + return LaunchWithIProcess(mDefaultApplication, nativePath); 1.433 +} 1.434 + 1.435 +NS_IMETHODIMP 1.436 +nsMIMEInfoBase::GetPossibleLocalHandlers(nsIArray **_retval) 1.437 +{ 1.438 + return NS_ERROR_NOT_IMPLEMENTED; 1.439 +}