Wed, 31 Dec 2014 07:53:36 +0100
Correct small whitespace inconsistency, lost while renaming variables.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMIMEInfoImpl.h"
8 #include "nsXPIDLString.h"
9 #include "nsReadableUtils.h"
10 #include "nsStringEnumerator.h"
11 #include "nsIFile.h"
12 #include "nsIFileURL.h"
13 #include "nsEscape.h"
14 #include "nsNetUtil.h"
15 #include "nsIURILoader.h"
16 #include "nsCURILoader.h"
18 // nsISupports methods
19 NS_IMPL_ADDREF(nsMIMEInfoBase)
20 NS_IMPL_RELEASE(nsMIMEInfoBase)
22 NS_INTERFACE_MAP_BEGIN(nsMIMEInfoBase)
23 NS_INTERFACE_MAP_ENTRY(nsIHandlerInfo)
24 // This is only an nsIMIMEInfo if it's a MIME handler.
25 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMIMEInfo, mClass == eMIMEInfo)
26 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHandlerInfo)
27 NS_INTERFACE_MAP_END_THREADSAFE
29 // nsMIMEInfoImpl methods
31 // Constructors for a MIME handler.
32 nsMIMEInfoBase::nsMIMEInfoBase(const char *aMIMEType) :
33 mSchemeOrType(aMIMEType),
34 mClass(eMIMEInfo),
35 mPreferredAction(nsIMIMEInfo::saveToDisk),
36 mAlwaysAskBeforeHandling(true)
37 {
38 }
40 nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aMIMEType) :
41 mSchemeOrType(aMIMEType),
42 mClass(eMIMEInfo),
43 mPreferredAction(nsIMIMEInfo::saveToDisk),
44 mAlwaysAskBeforeHandling(true)
45 {
46 }
48 // Constructor for a handler that lets the caller specify whether this is a
49 // MIME handler or a protocol handler. In the long run, these will be distinct
50 // classes (f.e. nsMIMEInfo and nsProtocolInfo), but for now we reuse this class
51 // for both and distinguish between the two kinds of handlers via the aClass
52 // argument to this method, which can be either eMIMEInfo or eProtocolInfo.
53 nsMIMEInfoBase::nsMIMEInfoBase(const nsACString& aType, HandlerClass aClass) :
54 mSchemeOrType(aType),
55 mClass(aClass),
56 mPreferredAction(nsIMIMEInfo::saveToDisk),
57 mAlwaysAskBeforeHandling(true)
58 {
59 }
61 nsMIMEInfoBase::~nsMIMEInfoBase()
62 {
63 }
65 NS_IMETHODIMP
66 nsMIMEInfoBase::GetFileExtensions(nsIUTF8StringEnumerator** aResult)
67 {
68 return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this);
69 }
71 NS_IMETHODIMP
72 nsMIMEInfoBase::ExtensionExists(const nsACString& aExtension, bool *_retval)
73 {
74 NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
75 bool found = false;
76 uint32_t extCount = mExtensions.Length();
77 if (extCount < 1) return NS_OK;
79 for (uint8_t i=0; i < extCount; i++) {
80 const nsCString& ext = mExtensions[i];
81 if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
82 found = true;
83 break;
84 }
85 }
87 *_retval = found;
88 return NS_OK;
89 }
91 NS_IMETHODIMP
92 nsMIMEInfoBase::GetPrimaryExtension(nsACString& _retval)
93 {
94 if (!mExtensions.Length())
95 return NS_ERROR_NOT_INITIALIZED;
97 _retval = mExtensions[0];
98 return NS_OK;
99 }
101 NS_IMETHODIMP
102 nsMIMEInfoBase::SetPrimaryExtension(const nsACString& aExtension)
103 {
104 NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
105 uint32_t extCount = mExtensions.Length();
106 uint8_t i;
107 bool found = false;
108 for (i=0; i < extCount; i++) {
109 const nsCString& ext = mExtensions[i];
110 if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
111 found = true;
112 break;
113 }
114 }
115 if (found) {
116 mExtensions.RemoveElementAt(i);
117 }
119 mExtensions.InsertElementAt(0, aExtension);
121 return NS_OK;
122 }
124 NS_IMETHODIMP
125 nsMIMEInfoBase::AppendExtension(const nsACString& aExtension)
126 {
127 mExtensions.AppendElement(aExtension);
128 return NS_OK;
129 }
131 NS_IMETHODIMP
132 nsMIMEInfoBase::GetType(nsACString& aType)
133 {
134 if (mSchemeOrType.IsEmpty())
135 return NS_ERROR_NOT_INITIALIZED;
137 aType = mSchemeOrType;
138 return NS_OK;
139 }
141 NS_IMETHODIMP
142 nsMIMEInfoBase::GetMIMEType(nsACString& aMIMEType)
143 {
144 if (mSchemeOrType.IsEmpty())
145 return NS_ERROR_NOT_INITIALIZED;
147 aMIMEType = mSchemeOrType;
148 return NS_OK;
149 }
151 NS_IMETHODIMP
152 nsMIMEInfoBase::GetDescription(nsAString& aDescription)
153 {
154 aDescription = mDescription;
155 return NS_OK;
156 }
158 NS_IMETHODIMP
159 nsMIMEInfoBase::SetDescription(const nsAString& aDescription)
160 {
161 mDescription = aDescription;
162 return NS_OK;
163 }
165 NS_IMETHODIMP
166 nsMIMEInfoBase::Equals(nsIMIMEInfo *aMIMEInfo, bool *_retval)
167 {
168 if (!aMIMEInfo) return NS_ERROR_NULL_POINTER;
170 nsAutoCString type;
171 nsresult rv = aMIMEInfo->GetMIMEType(type);
172 if (NS_FAILED(rv)) return rv;
174 *_retval = mSchemeOrType.Equals(type);
176 return NS_OK;
177 }
179 NS_IMETHODIMP
180 nsMIMEInfoBase::SetFileExtensions(const nsACString& aExtensions)
181 {
182 mExtensions.Clear();
183 nsCString extList( aExtensions );
185 int32_t breakLocation = -1;
186 while ( (breakLocation= extList.FindChar(',') )!= -1)
187 {
188 mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation));
189 extList.Cut(0, breakLocation+1 );
190 }
191 if ( !extList.IsEmpty() )
192 mExtensions.AppendElement( extList );
193 return NS_OK;
194 }
196 NS_IMETHODIMP
197 nsMIMEInfoBase::GetDefaultDescription(nsAString& aDefaultDescription)
198 {
199 aDefaultDescription = mDefaultAppDescription;
200 return NS_OK;
201 }
203 NS_IMETHODIMP
204 nsMIMEInfoBase::GetPreferredApplicationHandler(nsIHandlerApp ** aPreferredAppHandler)
205 {
206 *aPreferredAppHandler = mPreferredApplication;
207 NS_IF_ADDREF(*aPreferredAppHandler);
208 return NS_OK;
209 }
211 NS_IMETHODIMP
212 nsMIMEInfoBase::SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler)
213 {
214 mPreferredApplication = aPreferredAppHandler;
215 return NS_OK;
216 }
218 NS_IMETHODIMP
219 nsMIMEInfoBase::GetPossibleApplicationHandlers(nsIMutableArray ** aPossibleAppHandlers)
220 {
221 if (!mPossibleApplications)
222 mPossibleApplications = do_CreateInstance(NS_ARRAY_CONTRACTID);
224 if (!mPossibleApplications)
225 return NS_ERROR_OUT_OF_MEMORY;
227 *aPossibleAppHandlers = mPossibleApplications;
228 NS_IF_ADDREF(*aPossibleAppHandlers);
229 return NS_OK;
230 }
232 NS_IMETHODIMP
233 nsMIMEInfoBase::GetPreferredAction(nsHandlerInfoAction * aPreferredAction)
234 {
235 *aPreferredAction = mPreferredAction;
236 return NS_OK;
237 }
239 NS_IMETHODIMP
240 nsMIMEInfoBase::SetPreferredAction(nsHandlerInfoAction aPreferredAction)
241 {
242 mPreferredAction = aPreferredAction;
243 return NS_OK;
244 }
246 NS_IMETHODIMP
247 nsMIMEInfoBase::GetAlwaysAskBeforeHandling(bool * aAlwaysAsk)
248 {
249 *aAlwaysAsk = mAlwaysAskBeforeHandling;
251 return NS_OK;
252 }
254 NS_IMETHODIMP
255 nsMIMEInfoBase::SetAlwaysAskBeforeHandling(bool aAlwaysAsk)
256 {
257 mAlwaysAskBeforeHandling = aAlwaysAsk;
258 return NS_OK;
259 }
261 /* static */
262 nsresult
263 nsMIMEInfoBase::GetLocalFileFromURI(nsIURI *aURI, nsIFile **aFile)
264 {
265 nsresult rv;
267 nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(aURI, &rv);
268 if (NS_FAILED(rv)) {
269 return rv;
270 }
272 nsCOMPtr<nsIFile> file;
273 rv = fileUrl->GetFile(getter_AddRefs(file));
274 if (NS_FAILED(rv)) {
275 return rv;
276 }
278 file.forget(aFile);
279 return NS_OK;
280 }
282 NS_IMETHODIMP
283 nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile)
284 {
285 nsresult rv;
287 // it doesn't make any sense to call this on protocol handlers
288 NS_ASSERTION(mClass == eMIMEInfo,
289 "nsMIMEInfoBase should have mClass == eMIMEInfo");
291 if (mPreferredAction == useSystemDefault) {
292 return LaunchDefaultWithFile(aFile);
293 }
295 if (mPreferredAction == useHelperApp) {
296 if (!mPreferredApplication)
297 return NS_ERROR_FILE_NOT_FOUND;
299 // at the moment, we only know how to hand files off to local handlers
300 nsCOMPtr<nsILocalHandlerApp> localHandler =
301 do_QueryInterface(mPreferredApplication, &rv);
302 NS_ENSURE_SUCCESS(rv, rv);
304 nsCOMPtr<nsIFile> executable;
305 rv = localHandler->GetExecutable(getter_AddRefs(executable));
306 NS_ENSURE_SUCCESS(rv, rv);
308 nsAutoCString path;
309 aFile->GetNativePath(path);
310 return LaunchWithIProcess(executable, path);
311 }
313 return NS_ERROR_INVALID_ARG;
314 }
316 NS_IMETHODIMP
317 nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI,
318 nsIInterfaceRequestor* aWindowContext)
319 {
320 // for now, this is only being called with protocol handlers; that
321 // will change once we get to more general registerContentHandler
322 // support
323 NS_ASSERTION(mClass == eProtocolInfo,
324 "nsMIMEInfoBase should be a protocol handler");
326 if (mPreferredAction == useSystemDefault) {
327 return LoadUriInternal(aURI);
328 }
330 if (mPreferredAction == useHelperApp) {
331 if (!mPreferredApplication)
332 return NS_ERROR_FILE_NOT_FOUND;
334 return mPreferredApplication->LaunchWithURI(aURI, aWindowContext);
335 }
337 return NS_ERROR_INVALID_ARG;
338 }
340 void
341 nsMIMEInfoBase::CopyBasicDataTo(nsMIMEInfoBase* aOther)
342 {
343 aOther->mSchemeOrType = mSchemeOrType;
344 aOther->mDefaultAppDescription = mDefaultAppDescription;
345 aOther->mExtensions = mExtensions;
346 }
348 /* static */
349 already_AddRefed<nsIProcess>
350 nsMIMEInfoBase::InitProcess(nsIFile* aApp, nsresult* aResult)
351 {
352 NS_ASSERTION(aApp, "Unexpected null pointer, fix caller");
354 nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID,
355 aResult);
356 if (NS_FAILED(*aResult))
357 return nullptr;
359 *aResult = process->Init(aApp);
360 if (NS_FAILED(*aResult))
361 return nullptr;
363 return process.forget();
364 }
366 /* static */
367 nsresult
368 nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsCString& aArg)
369 {
370 nsresult rv;
371 nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv);
372 if (NS_FAILED(rv))
373 return rv;
375 const char *string = aArg.get();
377 return process->Run(false, &string, 1);
378 }
380 /* static */
381 nsresult
382 nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsString& aArg)
383 {
384 nsresult rv;
385 nsCOMPtr<nsIProcess> process = InitProcess(aApp, &rv);
386 if (NS_FAILED(rv))
387 return rv;
389 const char16_t *string = aArg.get();
391 return process->Runw(false, &string, 1);
392 }
394 // nsMIMEInfoImpl implementation
395 NS_IMETHODIMP
396 nsMIMEInfoImpl::GetDefaultDescription(nsAString& aDefaultDescription)
397 {
398 if (mDefaultAppDescription.IsEmpty() && mDefaultApplication) {
399 // Don't want to cache this, just in case someone resets the app
400 // without changing the description....
401 mDefaultApplication->GetLeafName(aDefaultDescription);
402 } else {
403 aDefaultDescription = mDefaultAppDescription;
404 }
406 return NS_OK;
407 }
409 NS_IMETHODIMP
410 nsMIMEInfoImpl::GetHasDefaultHandler(bool * _retval)
411 {
412 *_retval = !mDefaultAppDescription.IsEmpty();
413 if (mDefaultApplication) {
414 bool exists;
415 *_retval = NS_SUCCEEDED(mDefaultApplication->Exists(&exists)) && exists;
416 }
417 return NS_OK;
418 }
420 nsresult
421 nsMIMEInfoImpl::LaunchDefaultWithFile(nsIFile* aFile)
422 {
423 if (!mDefaultApplication)
424 return NS_ERROR_FILE_NOT_FOUND;
426 nsAutoCString nativePath;
427 aFile->GetNativePath(nativePath);
429 return LaunchWithIProcess(mDefaultApplication, nativePath);
430 }
432 NS_IMETHODIMP
433 nsMIMEInfoBase::GetPossibleLocalHandlers(nsIArray **_retval)
434 {
435 return NS_ERROR_NOT_IMPLEMENTED;
436 }