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