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