|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 |
|
8 A directory viewer object. Parses "application/http-index-format" |
|
9 per Lou Montulli's original spec: |
|
10 |
|
11 http://www.mozilla.org/projects/netlib/dirindexformat.html |
|
12 |
|
13 One added change is for a description entry, for when the |
|
14 target does not match the filename |
|
15 |
|
16 */ |
|
17 |
|
18 #include "nsDirectoryViewer.h" |
|
19 #include "nsIDirIndex.h" |
|
20 #include "nsIDocShell.h" |
|
21 #include "jsapi.h" |
|
22 #include "nsCOMPtr.h" |
|
23 #include "nsCRT.h" |
|
24 #include "nsEnumeratorUtils.h" |
|
25 #include "nsEscape.h" |
|
26 #include "nsIRDFService.h" |
|
27 #include "nsRDFCID.h" |
|
28 #include "rdf.h" |
|
29 #include "nsIScriptContext.h" |
|
30 #include "nsIScriptGlobalObject.h" |
|
31 #include "nsIServiceManager.h" |
|
32 #include "nsISupportsArray.h" |
|
33 #include "nsIXPConnect.h" |
|
34 #include "nsEnumeratorUtils.h" |
|
35 #include "nsString.h" |
|
36 #include "nsXPIDLString.h" |
|
37 #include "nsReadableUtils.h" |
|
38 #include "nsITextToSubURI.h" |
|
39 #include "nsIInterfaceRequestor.h" |
|
40 #include "nsIInterfaceRequestorUtils.h" |
|
41 #include "nsIFTPChannel.h" |
|
42 #include "nsIWindowWatcher.h" |
|
43 #include "nsIPrompt.h" |
|
44 #include "nsIAuthPrompt.h" |
|
45 #include "nsIProgressEventSink.h" |
|
46 #include "nsIDOMWindow.h" |
|
47 #include "nsIDOMWindowCollection.h" |
|
48 #include "nsIDOMElement.h" |
|
49 #include "nsIStreamConverterService.h" |
|
50 #include "nsICategoryManager.h" |
|
51 #include "nsXPCOMCID.h" |
|
52 #include "nsIDocument.h" |
|
53 #include "mozilla/Preferences.h" |
|
54 #include "nsCxPusher.h" |
|
55 |
|
56 using namespace mozilla; |
|
57 |
|
58 static const int FORMAT_XUL = 3; |
|
59 |
|
60 //---------------------------------------------------------------------- |
|
61 // |
|
62 // Common CIDs |
|
63 // |
|
64 |
|
65 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); |
|
66 |
|
67 // Various protocols we have to special case |
|
68 static const char kFTPProtocol[] = "ftp://"; |
|
69 |
|
70 //---------------------------------------------------------------------- |
|
71 // |
|
72 // nsHTTPIndex |
|
73 // |
|
74 |
|
75 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTTPIndex) |
|
76 NS_INTERFACE_MAP_ENTRY(nsIHTTPIndex) |
|
77 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) |
|
78 NS_INTERFACE_MAP_ENTRY(nsIStreamListener) |
|
79 NS_INTERFACE_MAP_ENTRY(nsIDirIndexListener) |
|
80 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) |
|
81 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
|
82 NS_INTERFACE_MAP_ENTRY(nsIFTPEventSink) |
|
83 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTTPIndex) |
|
84 NS_INTERFACE_MAP_END |
|
85 |
|
86 NS_IMPL_CYCLE_COLLECTION(nsHTTPIndex, mInner) |
|
87 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTTPIndex) |
|
88 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTTPIndex) |
|
89 |
|
90 NS_IMETHODIMP |
|
91 nsHTTPIndex::GetInterface(const nsIID &anIID, void **aResult ) |
|
92 { |
|
93 if (anIID.Equals(NS_GET_IID(nsIFTPEventSink))) { |
|
94 // If we don't have a container to store the logged data |
|
95 // then don't report ourselves back to the caller |
|
96 |
|
97 if (!mRequestor) |
|
98 return NS_ERROR_NO_INTERFACE; |
|
99 *aResult = static_cast<nsIFTPEventSink*>(this); |
|
100 NS_ADDREF(this); |
|
101 return NS_OK; |
|
102 } |
|
103 |
|
104 if (anIID.Equals(NS_GET_IID(nsIPrompt))) { |
|
105 |
|
106 if (!mRequestor) |
|
107 return NS_ERROR_NO_INTERFACE; |
|
108 |
|
109 nsCOMPtr<nsIDOMWindow> aDOMWindow = do_GetInterface(mRequestor); |
|
110 if (!aDOMWindow) |
|
111 return NS_ERROR_NO_INTERFACE; |
|
112 |
|
113 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); |
|
114 |
|
115 return wwatch->GetNewPrompter(aDOMWindow, (nsIPrompt**)aResult); |
|
116 } |
|
117 |
|
118 if (anIID.Equals(NS_GET_IID(nsIAuthPrompt))) { |
|
119 |
|
120 if (!mRequestor) |
|
121 return NS_ERROR_NO_INTERFACE; |
|
122 |
|
123 nsCOMPtr<nsIDOMWindow> aDOMWindow = do_GetInterface(mRequestor); |
|
124 if (!aDOMWindow) |
|
125 return NS_ERROR_NO_INTERFACE; |
|
126 |
|
127 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); |
|
128 |
|
129 return wwatch->GetNewAuthPrompter(aDOMWindow, (nsIAuthPrompt**)aResult); |
|
130 } |
|
131 |
|
132 if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) { |
|
133 |
|
134 if (!mRequestor) |
|
135 return NS_ERROR_NO_INTERFACE; |
|
136 |
|
137 nsCOMPtr<nsIProgressEventSink> sink = do_GetInterface(mRequestor); |
|
138 if (!sink) |
|
139 return NS_ERROR_NO_INTERFACE; |
|
140 |
|
141 *aResult = sink; |
|
142 NS_ADDREF((nsISupports*)*aResult); |
|
143 return NS_OK; |
|
144 } |
|
145 |
|
146 return NS_ERROR_NO_INTERFACE; |
|
147 } |
|
148 |
|
149 NS_IMETHODIMP |
|
150 nsHTTPIndex::OnFTPControlLog(bool server, const char *msg) |
|
151 { |
|
152 NS_ENSURE_TRUE(mRequestor, NS_OK); |
|
153 |
|
154 nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_GetInterface(mRequestor)); |
|
155 NS_ENSURE_TRUE(scriptGlobal, NS_OK); |
|
156 |
|
157 nsIScriptContext *context = scriptGlobal->GetContext(); |
|
158 NS_ENSURE_TRUE(context, NS_OK); |
|
159 |
|
160 AutoPushJSContext cx(context->GetNativeContext()); |
|
161 NS_ENSURE_TRUE(cx, NS_OK); |
|
162 |
|
163 JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx)); |
|
164 NS_ENSURE_TRUE(global, NS_OK); |
|
165 |
|
166 nsString unicodeMsg; |
|
167 unicodeMsg.AssignWithConversion(msg); |
|
168 JSString* jsMsgStr = JS_NewUCStringCopyZ(cx, unicodeMsg.get()); |
|
169 NS_ENSURE_TRUE(jsMsgStr, NS_ERROR_OUT_OF_MEMORY); |
|
170 |
|
171 JS::AutoValueArray<2> params(cx); |
|
172 params[0].setBoolean(server); |
|
173 params[1].setString(jsMsgStr); |
|
174 |
|
175 JS::Rooted<JS::Value> val(cx); |
|
176 JS_CallFunctionName(cx, |
|
177 global, |
|
178 "OnFTPControlLog", |
|
179 params, |
|
180 &val); |
|
181 return NS_OK; |
|
182 } |
|
183 |
|
184 NS_IMETHODIMP |
|
185 nsHTTPIndex::SetEncoding(const char *encoding) |
|
186 { |
|
187 mEncoding = encoding; |
|
188 return(NS_OK); |
|
189 } |
|
190 |
|
191 NS_IMETHODIMP |
|
192 nsHTTPIndex::GetEncoding(char **encoding) |
|
193 { |
|
194 NS_PRECONDITION(encoding, "null ptr"); |
|
195 if (! encoding) |
|
196 return(NS_ERROR_NULL_POINTER); |
|
197 |
|
198 *encoding = ToNewCString(mEncoding); |
|
199 if (!*encoding) |
|
200 return(NS_ERROR_OUT_OF_MEMORY); |
|
201 |
|
202 return(NS_OK); |
|
203 } |
|
204 |
|
205 NS_IMETHODIMP |
|
206 nsHTTPIndex::OnStartRequest(nsIRequest *request, nsISupports* aContext) |
|
207 { |
|
208 nsresult rv; |
|
209 |
|
210 mParser = do_CreateInstance(NS_DIRINDEXPARSER_CONTRACTID, &rv); |
|
211 if (NS_FAILED(rv)) return rv; |
|
212 |
|
213 rv = mParser->SetEncoding(mEncoding.get()); |
|
214 if (NS_FAILED(rv)) return rv; |
|
215 |
|
216 rv = mParser->SetListener(this); |
|
217 if (NS_FAILED(rv)) return rv; |
|
218 |
|
219 rv = mParser->OnStartRequest(request,aContext); |
|
220 if (NS_FAILED(rv)) return rv; |
|
221 |
|
222 // This should only run once... |
|
223 // Unless we don't have a container to start with |
|
224 // (ie called from bookmarks as an rdf datasource) |
|
225 if (mBindToGlobalObject && mRequestor) { |
|
226 mBindToGlobalObject = false; |
|
227 |
|
228 // Now get the content viewer container's script object. |
|
229 nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_GetInterface(mRequestor)); |
|
230 NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_FAILURE); |
|
231 |
|
232 nsIScriptContext *context = scriptGlobal->GetContext(); |
|
233 NS_ENSURE_TRUE(context, NS_ERROR_FAILURE); |
|
234 |
|
235 AutoPushJSContext cx(context->GetNativeContext()); |
|
236 JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx)); |
|
237 |
|
238 // Using XPConnect, wrap the HTTP index object... |
|
239 static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID); |
|
240 nsCOMPtr<nsIXPConnect> xpc(do_GetService(kXPConnectCID, &rv)); |
|
241 if (NS_FAILED(rv)) return rv; |
|
242 |
|
243 nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper; |
|
244 rv = xpc->WrapNative(cx, |
|
245 global, |
|
246 static_cast<nsIHTTPIndex*>(this), |
|
247 NS_GET_IID(nsIHTTPIndex), |
|
248 getter_AddRefs(wrapper)); |
|
249 |
|
250 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index"); |
|
251 if (NS_FAILED(rv)) return rv; |
|
252 |
|
253 JS::Rooted<JSObject*> jsobj(cx, wrapper->GetJSObject()); |
|
254 NS_ASSERTION(jsobj, |
|
255 "unable to get jsobj from xpconnect wrapper"); |
|
256 if (!jsobj) return NS_ERROR_UNEXPECTED; |
|
257 |
|
258 JS::Rooted<JS::Value> jslistener(cx, OBJECT_TO_JSVAL(jsobj)); |
|
259 |
|
260 // ...and stuff it into the global context |
|
261 bool ok = JS_SetProperty(cx, global, "HTTPIndex", jslistener); |
|
262 NS_ASSERTION(ok, "unable to set Listener property"); |
|
263 if (!ok) |
|
264 return NS_ERROR_FAILURE; |
|
265 } |
|
266 |
|
267 if (!aContext) { |
|
268 nsCOMPtr<nsIChannel> channel(do_QueryInterface(request)); |
|
269 NS_ASSERTION(channel, "request should be a channel"); |
|
270 |
|
271 // lets hijack the notifications: |
|
272 channel->SetNotificationCallbacks(this); |
|
273 |
|
274 // now create the top most resource |
|
275 nsCOMPtr<nsIURI> uri; |
|
276 channel->GetURI(getter_AddRefs(uri)); |
|
277 |
|
278 nsAutoCString entryuriC; |
|
279 uri->GetSpec(entryuriC); |
|
280 |
|
281 nsCOMPtr<nsIRDFResource> entry; |
|
282 rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry)); |
|
283 |
|
284 NS_ConvertUTF8toUTF16 uriUnicode(entryuriC); |
|
285 |
|
286 nsCOMPtr<nsIRDFLiteral> URLVal; |
|
287 rv = mDirRDF->GetLiteral(uriUnicode.get(), getter_AddRefs(URLVal)); |
|
288 |
|
289 Assert(entry, kNC_URL, URLVal, true); |
|
290 mDirectory = do_QueryInterface(entry); |
|
291 } |
|
292 else |
|
293 { |
|
294 // Get the directory from the context |
|
295 mDirectory = do_QueryInterface(aContext); |
|
296 } |
|
297 |
|
298 if (!mDirectory) { |
|
299 request->Cancel(NS_BINDING_ABORTED); |
|
300 return NS_BINDING_ABORTED; |
|
301 } |
|
302 |
|
303 // Mark the directory as "loading" |
|
304 rv = Assert(mDirectory, kNC_Loading, |
|
305 kTrueLiteral, true); |
|
306 if (NS_FAILED(rv)) return rv; |
|
307 |
|
308 return NS_OK; |
|
309 } |
|
310 |
|
311 |
|
312 NS_IMETHODIMP |
|
313 nsHTTPIndex::OnStopRequest(nsIRequest *request, |
|
314 nsISupports* aContext, |
|
315 nsresult aStatus) |
|
316 { |
|
317 // If mDirectory isn't set, then we should just bail. Either an |
|
318 // error occurred and OnStartRequest() never got called, or |
|
319 // something exploded in OnStartRequest(). |
|
320 if (! mDirectory) |
|
321 return NS_BINDING_ABORTED; |
|
322 |
|
323 mParser->OnStopRequest(request,aContext,aStatus); |
|
324 |
|
325 nsresult rv; |
|
326 |
|
327 nsXPIDLCString commentStr; |
|
328 mParser->GetComment(getter_Copies(commentStr)); |
|
329 |
|
330 nsCOMPtr<nsIRDFLiteral> comment; |
|
331 rv = mDirRDF->GetLiteral(NS_ConvertASCIItoUTF16(commentStr).get(), getter_AddRefs(comment)); |
|
332 if (NS_FAILED(rv)) return rv; |
|
333 |
|
334 rv = Assert(mDirectory, kNC_Comment, comment, true); |
|
335 if (NS_FAILED(rv)) return rv; |
|
336 |
|
337 // hack: Remove the 'loading' annotation (ignore errors) |
|
338 AddElement(mDirectory, kNC_Loading, kTrueLiteral); |
|
339 |
|
340 return NS_OK; |
|
341 } |
|
342 |
|
343 |
|
344 NS_IMETHODIMP |
|
345 nsHTTPIndex::OnDataAvailable(nsIRequest *request, |
|
346 nsISupports* aContext, |
|
347 nsIInputStream* aStream, |
|
348 uint64_t aSourceOffset, |
|
349 uint32_t aCount) |
|
350 { |
|
351 // If mDirectory isn't set, then we should just bail. Either an |
|
352 // error occurred and OnStartRequest() never got called, or |
|
353 // something exploded in OnStartRequest(). |
|
354 if (! mDirectory) |
|
355 return NS_BINDING_ABORTED; |
|
356 |
|
357 return mParser->OnDataAvailable(request, mDirectory, aStream, aSourceOffset, aCount); |
|
358 } |
|
359 |
|
360 |
|
361 nsresult |
|
362 nsHTTPIndex::OnIndexAvailable(nsIRequest* aRequest, nsISupports *aContext, |
|
363 nsIDirIndex* aIndex) |
|
364 { |
|
365 nsCOMPtr<nsIRDFResource> parentRes = do_QueryInterface(aContext); |
|
366 if (!parentRes) { |
|
367 NS_ERROR("Could not obtain parent resource"); |
|
368 return(NS_ERROR_UNEXPECTED); |
|
369 } |
|
370 |
|
371 const char* baseStr; |
|
372 parentRes->GetValueConst(&baseStr); |
|
373 if (! baseStr) { |
|
374 NS_ERROR("Could not reconstruct base uri"); |
|
375 return NS_ERROR_UNEXPECTED; |
|
376 } |
|
377 |
|
378 // we found the filename; construct a resource for its entry |
|
379 nsAutoCString entryuriC(baseStr); |
|
380 |
|
381 nsXPIDLCString filename; |
|
382 nsresult rv = aIndex->GetLocation(getter_Copies(filename)); |
|
383 if (NS_FAILED(rv)) return rv; |
|
384 entryuriC.Append(filename); |
|
385 |
|
386 // if its a directory, make sure it ends with a trailing slash. |
|
387 uint32_t type; |
|
388 rv = aIndex->GetType(&type); |
|
389 if (NS_FAILED(rv)) |
|
390 return rv; |
|
391 |
|
392 bool isDirType = (type == nsIDirIndex::TYPE_DIRECTORY); |
|
393 if (isDirType && entryuriC.Last() != '/') { |
|
394 entryuriC.Append('/'); |
|
395 } |
|
396 |
|
397 nsCOMPtr<nsIRDFResource> entry; |
|
398 rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry)); |
|
399 |
|
400 // At this point, we'll (hopefully) have found the filename and |
|
401 // constructed a resource for it, stored in entry. So now take a |
|
402 // second pass through the values and add as statements to the RDF |
|
403 // datasource. |
|
404 |
|
405 if (entry && NS_SUCCEEDED(rv)) { |
|
406 nsCOMPtr<nsIRDFLiteral> lit; |
|
407 nsString str; |
|
408 |
|
409 str.AssignWithConversion(entryuriC.get()); |
|
410 |
|
411 rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit)); |
|
412 |
|
413 if (NS_SUCCEEDED(rv)) { |
|
414 rv = Assert(entry, kNC_URL, lit, true); |
|
415 if (NS_FAILED(rv)) return rv; |
|
416 |
|
417 nsXPIDLString xpstr; |
|
418 |
|
419 // description |
|
420 rv = aIndex->GetDescription(getter_Copies(xpstr)); |
|
421 if (NS_FAILED(rv)) return rv; |
|
422 if (xpstr.Last() == '/') |
|
423 xpstr.Truncate(xpstr.Length() - 1); |
|
424 |
|
425 rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit)); |
|
426 if (NS_FAILED(rv)) return rv; |
|
427 rv = Assert(entry, kNC_Description, lit, true); |
|
428 if (NS_FAILED(rv)) return rv; |
|
429 |
|
430 // contentlength |
|
431 int64_t size; |
|
432 rv = aIndex->GetSize(&size); |
|
433 if (NS_FAILED(rv)) return rv; |
|
434 int64_t minus1 = UINT64_MAX; |
|
435 if (size != minus1) { |
|
436 int32_t intSize = int32_t(size); |
|
437 // XXX RDF should support 64 bit integers (bug 240160) |
|
438 nsCOMPtr<nsIRDFInt> val; |
|
439 rv = mDirRDF->GetIntLiteral(intSize, getter_AddRefs(val)); |
|
440 if (NS_FAILED(rv)) return rv; |
|
441 rv = Assert(entry, kNC_ContentLength, val, true); |
|
442 if (NS_FAILED(rv)) return rv; |
|
443 } |
|
444 |
|
445 // lastmodified |
|
446 PRTime tm; |
|
447 rv = aIndex->GetLastModified(&tm); |
|
448 if (NS_FAILED(rv)) return rv; |
|
449 if (tm != -1) { |
|
450 nsCOMPtr<nsIRDFDate> val; |
|
451 rv = mDirRDF->GetDateLiteral(tm, getter_AddRefs(val)); |
|
452 if (NS_FAILED(rv)) return rv; |
|
453 rv = Assert(entry, kNC_LastModified, val, true); |
|
454 } |
|
455 |
|
456 // filetype |
|
457 uint32_t type; |
|
458 rv = aIndex->GetType(&type); |
|
459 switch (type) { |
|
460 case nsIDirIndex::TYPE_UNKNOWN: |
|
461 rv = mDirRDF->GetLiteral(MOZ_UTF16("UNKNOWN"), getter_AddRefs(lit)); |
|
462 break; |
|
463 case nsIDirIndex::TYPE_DIRECTORY: |
|
464 rv = mDirRDF->GetLiteral(MOZ_UTF16("DIRECTORY"), getter_AddRefs(lit)); |
|
465 break; |
|
466 case nsIDirIndex::TYPE_FILE: |
|
467 rv = mDirRDF->GetLiteral(MOZ_UTF16("FILE"), getter_AddRefs(lit)); |
|
468 break; |
|
469 case nsIDirIndex::TYPE_SYMLINK: |
|
470 rv = mDirRDF->GetLiteral(MOZ_UTF16("SYMLINK"), getter_AddRefs(lit)); |
|
471 break; |
|
472 } |
|
473 |
|
474 if (NS_FAILED(rv)) return rv; |
|
475 rv = Assert(entry, kNC_FileType, lit, true); |
|
476 if (NS_FAILED(rv)) return rv; |
|
477 } |
|
478 |
|
479 // Since the definition of a directory depends on the protocol, we would have |
|
480 // to do string comparisons all the time. |
|
481 // But we're told if we're a container right here - so save that fact |
|
482 if (isDirType) |
|
483 Assert(entry, kNC_IsContainer, kTrueLiteral, true); |
|
484 else |
|
485 Assert(entry, kNC_IsContainer, kFalseLiteral, true); |
|
486 |
|
487 // instead of |
|
488 // rv = Assert(parentRes, kNC_Child, entry, true); |
|
489 // if (NS_FAILED(rv)) return rv; |
|
490 // defer insertion onto a timer so that the UI isn't starved |
|
491 AddElement(parentRes, kNC_Child, entry); |
|
492 } |
|
493 |
|
494 return rv; |
|
495 } |
|
496 |
|
497 nsresult |
|
498 nsHTTPIndex::OnInformationAvailable(nsIRequest *aRequest, |
|
499 nsISupports *aCtxt, |
|
500 const nsAString& aInfo) { |
|
501 return NS_ERROR_NOT_IMPLEMENTED; |
|
502 } |
|
503 |
|
504 //---------------------------------------------------------------------- |
|
505 // |
|
506 // nsHTTPIndex implementation |
|
507 // |
|
508 |
|
509 nsHTTPIndex::nsHTTPIndex() |
|
510 : mBindToGlobalObject(true), |
|
511 mRequestor(nullptr) |
|
512 { |
|
513 } |
|
514 |
|
515 |
|
516 nsHTTPIndex::nsHTTPIndex(nsIInterfaceRequestor* aRequestor) |
|
517 : mBindToGlobalObject(true), |
|
518 mRequestor(aRequestor) |
|
519 { |
|
520 } |
|
521 |
|
522 |
|
523 nsHTTPIndex::~nsHTTPIndex() |
|
524 { |
|
525 // note: these are NOT statics due to the native of nsHTTPIndex |
|
526 // where it may or may not be treated as a singleton |
|
527 |
|
528 if (mTimer) |
|
529 { |
|
530 // be sure to cancel the timer, as it holds a |
|
531 // weak reference back to nsHTTPIndex |
|
532 mTimer->Cancel(); |
|
533 mTimer = nullptr; |
|
534 } |
|
535 |
|
536 mConnectionList = nullptr; |
|
537 mNodeList = nullptr; |
|
538 |
|
539 if (mDirRDF) |
|
540 { |
|
541 // UnregisterDataSource() may fail; just ignore errors |
|
542 mDirRDF->UnregisterDataSource(this); |
|
543 } |
|
544 } |
|
545 |
|
546 |
|
547 |
|
548 nsresult |
|
549 nsHTTPIndex::CommonInit() |
|
550 { |
|
551 nsresult rv = NS_OK; |
|
552 |
|
553 // set initial/default encoding to ISO-8859-1 (not UTF-8) |
|
554 mEncoding = "ISO-8859-1"; |
|
555 |
|
556 mDirRDF = do_GetService(kRDFServiceCID, &rv); |
|
557 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service"); |
|
558 if (NS_FAILED(rv)) { |
|
559 return(rv); |
|
560 } |
|
561 |
|
562 mInner = do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource", &rv); |
|
563 |
|
564 if (NS_FAILED(rv)) |
|
565 return rv; |
|
566 |
|
567 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), |
|
568 getter_AddRefs(kNC_Child)); |
|
569 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"), |
|
570 getter_AddRefs(kNC_Loading)); |
|
571 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Comment"), |
|
572 getter_AddRefs(kNC_Comment)); |
|
573 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"), |
|
574 getter_AddRefs(kNC_URL)); |
|
575 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"), |
|
576 getter_AddRefs(kNC_Description)); |
|
577 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"), |
|
578 getter_AddRefs(kNC_ContentLength)); |
|
579 mDirRDF->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"), |
|
580 getter_AddRefs(kNC_LastModified)); |
|
581 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Type"), |
|
582 getter_AddRefs(kNC_ContentType)); |
|
583 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "File-Type"), |
|
584 getter_AddRefs(kNC_FileType)); |
|
585 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsContainer"), |
|
586 getter_AddRefs(kNC_IsContainer)); |
|
587 |
|
588 rv = mDirRDF->GetLiteral(MOZ_UTF16("true"), getter_AddRefs(kTrueLiteral)); |
|
589 if (NS_FAILED(rv)) return(rv); |
|
590 rv = mDirRDF->GetLiteral(MOZ_UTF16("false"), getter_AddRefs(kFalseLiteral)); |
|
591 if (NS_FAILED(rv)) return(rv); |
|
592 |
|
593 rv = NS_NewISupportsArray(getter_AddRefs(mConnectionList)); |
|
594 if (NS_FAILED(rv)) return(rv); |
|
595 |
|
596 // note: don't register DS here |
|
597 return rv; |
|
598 } |
|
599 |
|
600 |
|
601 nsresult |
|
602 nsHTTPIndex::Init() |
|
603 { |
|
604 nsresult rv; |
|
605 |
|
606 // set initial/default encoding to ISO-8859-1 (not UTF-8) |
|
607 mEncoding = "ISO-8859-1"; |
|
608 |
|
609 rv = CommonInit(); |
|
610 if (NS_FAILED(rv)) return(rv); |
|
611 |
|
612 // (do this last) register this as a named data source with the RDF service |
|
613 rv = mDirRDF->RegisterDataSource(this, false); |
|
614 if (NS_FAILED(rv)) return(rv); |
|
615 |
|
616 return(NS_OK); |
|
617 } |
|
618 |
|
619 |
|
620 |
|
621 nsresult |
|
622 nsHTTPIndex::Init(nsIURI* aBaseURL) |
|
623 { |
|
624 NS_PRECONDITION(aBaseURL != nullptr, "null ptr"); |
|
625 if (! aBaseURL) |
|
626 return NS_ERROR_NULL_POINTER; |
|
627 |
|
628 nsresult rv; |
|
629 |
|
630 rv = CommonInit(); |
|
631 if (NS_FAILED(rv)) return(rv); |
|
632 |
|
633 // note: don't register DS here (singleton case) |
|
634 |
|
635 rv = aBaseURL->GetSpec(mBaseURL); |
|
636 if (NS_FAILED(rv)) return rv; |
|
637 |
|
638 // Mark the base url as a container |
|
639 nsCOMPtr<nsIRDFResource> baseRes; |
|
640 mDirRDF->GetResource(mBaseURL, getter_AddRefs(baseRes)); |
|
641 Assert(baseRes, kNC_IsContainer, kTrueLiteral, true); |
|
642 |
|
643 return NS_OK; |
|
644 } |
|
645 |
|
646 |
|
647 |
|
648 nsresult |
|
649 nsHTTPIndex::Create(nsIURI* aBaseURL, nsIInterfaceRequestor* aRequestor, |
|
650 nsIHTTPIndex** aResult) |
|
651 { |
|
652 *aResult = nullptr; |
|
653 |
|
654 nsHTTPIndex* result = new nsHTTPIndex(aRequestor); |
|
655 if (! result) |
|
656 return NS_ERROR_OUT_OF_MEMORY; |
|
657 |
|
658 nsresult rv = result->Init(aBaseURL); |
|
659 if (NS_SUCCEEDED(rv)) |
|
660 { |
|
661 NS_ADDREF(result); |
|
662 *aResult = result; |
|
663 } |
|
664 else |
|
665 { |
|
666 delete result; |
|
667 } |
|
668 return rv; |
|
669 } |
|
670 |
|
671 NS_IMETHODIMP |
|
672 nsHTTPIndex::GetBaseURL(char** _result) |
|
673 { |
|
674 *_result = ToNewCString(mBaseURL); |
|
675 if (! *_result) |
|
676 return NS_ERROR_OUT_OF_MEMORY; |
|
677 |
|
678 return NS_OK; |
|
679 } |
|
680 |
|
681 NS_IMETHODIMP |
|
682 nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result) |
|
683 { |
|
684 NS_ADDREF(*_result = this); |
|
685 return NS_OK; |
|
686 } |
|
687 |
|
688 // This function finds the destination when following a given nsIRDFResource |
|
689 // If the resource has a URL attribute, we use that. If not, just use |
|
690 // the uri. |
|
691 // |
|
692 // Do NOT try to get the destination of a uri in any other way |
|
693 void nsHTTPIndex::GetDestination(nsIRDFResource* r, nsXPIDLCString& dest) { |
|
694 // First try the URL attribute |
|
695 nsCOMPtr<nsIRDFNode> node; |
|
696 |
|
697 GetTarget(r, kNC_URL, true, getter_AddRefs(node)); |
|
698 nsCOMPtr<nsIRDFLiteral> url; |
|
699 |
|
700 if (node) |
|
701 url = do_QueryInterface(node); |
|
702 |
|
703 if (!url) { |
|
704 const char* temp; |
|
705 r->GetValueConst(&temp); |
|
706 dest.Adopt(temp ? strdup(temp) : 0); |
|
707 } else { |
|
708 const char16_t* uri; |
|
709 url->GetValueConst(&uri); |
|
710 dest.Adopt(ToNewUTF8String(nsDependentString(uri))); |
|
711 } |
|
712 } |
|
713 |
|
714 // rjc: isWellknownContainerURI() decides whether a URI is a container for which, |
|
715 // when asked (say, by the template builder), we'll make a network connection |
|
716 // to get its contents. For the moment, all we speak is ftp:// URLs, even though |
|
717 // a) we can get "http-index" mimetypes for really anything |
|
718 // b) we could easily handle file:// URLs here |
|
719 // Q: Why don't we? |
|
720 // A: The file system datasource ("rdf:file"); at some point, the two |
|
721 // should be perhaps united. Until then, we can't aggregate both |
|
722 // "rdf:file" and "http-index" (such as with bookmarks) because we'd |
|
723 // get double the # of answers we really want... also, "rdf:file" is |
|
724 // less expensive in terms of both memory usage as well as speed |
|
725 |
|
726 |
|
727 |
|
728 // We use an rdf attribute to mark if this is a container or not. |
|
729 // Note that we still have to do string comparisons as a fallback |
|
730 // because stuff like the personal toolbar and bookmarks check whether |
|
731 // a URL is a container, and we have no attribute in that case. |
|
732 bool |
|
733 nsHTTPIndex::isWellknownContainerURI(nsIRDFResource *r) |
|
734 { |
|
735 nsCOMPtr<nsIRDFNode> node; |
|
736 GetTarget(r, kNC_IsContainer, true, getter_AddRefs(node)); |
|
737 if (node) { |
|
738 bool isContainerFlag; |
|
739 if (NS_SUCCEEDED(node->EqualsNode(kTrueLiteral, &isContainerFlag))) |
|
740 return isContainerFlag; |
|
741 } |
|
742 |
|
743 nsXPIDLCString uri; |
|
744 GetDestination(r, uri); |
|
745 return uri.get() && !strncmp(uri, kFTPProtocol, sizeof(kFTPProtocol) - 1) && |
|
746 (uri.Last() == '/'); |
|
747 } |
|
748 |
|
749 |
|
750 NS_IMETHODIMP |
|
751 nsHTTPIndex::GetURI(char * *uri) |
|
752 { |
|
753 NS_PRECONDITION(uri != nullptr, "null ptr"); |
|
754 if (! uri) |
|
755 return(NS_ERROR_NULL_POINTER); |
|
756 |
|
757 if ((*uri = strdup("rdf:httpindex")) == nullptr) |
|
758 return(NS_ERROR_OUT_OF_MEMORY); |
|
759 |
|
760 return(NS_OK); |
|
761 } |
|
762 |
|
763 |
|
764 |
|
765 NS_IMETHODIMP |
|
766 nsHTTPIndex::GetSource(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue, |
|
767 nsIRDFResource **_retval) |
|
768 { |
|
769 nsresult rv = NS_ERROR_UNEXPECTED; |
|
770 |
|
771 *_retval = nullptr; |
|
772 |
|
773 if (mInner) |
|
774 { |
|
775 rv = mInner->GetSource(aProperty, aTarget, aTruthValue, _retval); |
|
776 } |
|
777 return(rv); |
|
778 } |
|
779 |
|
780 NS_IMETHODIMP |
|
781 nsHTTPIndex::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue, |
|
782 nsISimpleEnumerator **_retval) |
|
783 { |
|
784 nsresult rv = NS_ERROR_UNEXPECTED; |
|
785 |
|
786 if (mInner) |
|
787 { |
|
788 rv = mInner->GetSources(aProperty, aTarget, aTruthValue, _retval); |
|
789 } |
|
790 else |
|
791 { |
|
792 rv = NS_NewEmptyEnumerator(_retval); |
|
793 } |
|
794 return(rv); |
|
795 } |
|
796 |
|
797 NS_IMETHODIMP |
|
798 nsHTTPIndex::GetTarget(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue, |
|
799 nsIRDFNode **_retval) |
|
800 { |
|
801 nsresult rv = NS_ERROR_UNEXPECTED; |
|
802 |
|
803 *_retval = nullptr; |
|
804 |
|
805 if ((aTruthValue) && (aProperty == kNC_Child) && isWellknownContainerURI(aSource)) |
|
806 { |
|
807 // fake out the generic builder (i.e. return anything in this case) |
|
808 // so that search containers never appear to be empty |
|
809 NS_IF_ADDREF(aSource); |
|
810 *_retval = aSource; |
|
811 return(NS_OK); |
|
812 } |
|
813 |
|
814 if (mInner) |
|
815 { |
|
816 rv = mInner->GetTarget(aSource, aProperty, aTruthValue, _retval); |
|
817 } |
|
818 return(rv); |
|
819 } |
|
820 |
|
821 NS_IMETHODIMP |
|
822 nsHTTPIndex::GetTargets(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue, |
|
823 nsISimpleEnumerator **_retval) |
|
824 { |
|
825 nsresult rv = NS_ERROR_UNEXPECTED; |
|
826 |
|
827 if (mInner) |
|
828 { |
|
829 rv = mInner->GetTargets(aSource, aProperty, aTruthValue, _retval); |
|
830 } |
|
831 else |
|
832 { |
|
833 rv = NS_NewEmptyEnumerator(_retval); |
|
834 } |
|
835 |
|
836 if ((aProperty == kNC_Child) && isWellknownContainerURI(aSource)) |
|
837 { |
|
838 bool doNetworkRequest = true; |
|
839 if (NS_SUCCEEDED(rv) && (_retval)) |
|
840 { |
|
841 // check and see if we already have data for the search in question; |
|
842 // if we do, don't bother doing the search again |
|
843 bool hasResults; |
|
844 if (NS_SUCCEEDED((*_retval)->HasMoreElements(&hasResults)) && |
|
845 hasResults) |
|
846 doNetworkRequest = false; |
|
847 } |
|
848 |
|
849 // Note: if we need to do a network request, do it out-of-band |
|
850 // (because the XUL template builder isn't re-entrant) |
|
851 // by using a global connection list and an immediately-firing timer |
|
852 if (doNetworkRequest && mConnectionList) |
|
853 { |
|
854 int32_t connectionIndex = mConnectionList->IndexOf(aSource); |
|
855 if (connectionIndex < 0) |
|
856 { |
|
857 // add aSource into list of connections to make |
|
858 mConnectionList->AppendElement(aSource); |
|
859 |
|
860 // if we don't have a timer about to fire, create one |
|
861 // which should fire as soon as possible (out-of-band) |
|
862 if (!mTimer) |
|
863 { |
|
864 mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); |
|
865 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer"); |
|
866 if (NS_SUCCEEDED(rv)) |
|
867 { |
|
868 mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1, |
|
869 nsITimer::TYPE_ONE_SHOT); |
|
870 // Note: don't addref "this" as we'll cancel the |
|
871 // timer in the httpIndex destructor |
|
872 } |
|
873 } |
|
874 } |
|
875 } |
|
876 } |
|
877 |
|
878 return(rv); |
|
879 } |
|
880 |
|
881 |
|
882 nsresult |
|
883 nsHTTPIndex::AddElement(nsIRDFResource *parent, nsIRDFResource *prop, nsIRDFNode *child) |
|
884 { |
|
885 nsresult rv; |
|
886 |
|
887 if (!mNodeList) |
|
888 { |
|
889 rv = NS_NewISupportsArray(getter_AddRefs(mNodeList)); |
|
890 if (NS_FAILED(rv)) return(rv); |
|
891 } |
|
892 |
|
893 // order required: parent, prop, then child |
|
894 mNodeList->AppendElement(parent); |
|
895 mNodeList->AppendElement(prop); |
|
896 mNodeList->AppendElement(child); |
|
897 |
|
898 if (!mTimer) |
|
899 { |
|
900 mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); |
|
901 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer"); |
|
902 if (NS_FAILED(rv)) return(rv); |
|
903 |
|
904 mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1, |
|
905 nsITimer::TYPE_ONE_SHOT); |
|
906 // Note: don't addref "this" as we'll cancel the |
|
907 // timer in the httpIndex destructor |
|
908 } |
|
909 |
|
910 return(NS_OK); |
|
911 } |
|
912 |
|
913 void |
|
914 nsHTTPIndex::FireTimer(nsITimer* aTimer, void* aClosure) |
|
915 { |
|
916 nsHTTPIndex *httpIndex = static_cast<nsHTTPIndex *>(aClosure); |
|
917 if (!httpIndex) return; |
|
918 |
|
919 // don't return out of this loop as mTimer may need to be cancelled afterwards |
|
920 uint32_t numItems = 0; |
|
921 if (httpIndex->mConnectionList) |
|
922 { |
|
923 httpIndex->mConnectionList->Count(&numItems); |
|
924 if (numItems > 0) |
|
925 { |
|
926 nsCOMPtr<nsISupports> isupports; |
|
927 httpIndex->mConnectionList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); |
|
928 httpIndex->mConnectionList->RemoveElementAt((uint32_t)0); |
|
929 |
|
930 nsCOMPtr<nsIRDFResource> aSource; |
|
931 if (isupports) aSource = do_QueryInterface(isupports); |
|
932 |
|
933 nsXPIDLCString uri; |
|
934 if (aSource) { |
|
935 httpIndex->GetDestination(aSource, uri); |
|
936 } |
|
937 |
|
938 if (!uri) { |
|
939 NS_ERROR("Could not reconstruct uri"); |
|
940 return; |
|
941 } |
|
942 |
|
943 nsresult rv = NS_OK; |
|
944 nsCOMPtr<nsIURI> url; |
|
945 |
|
946 rv = NS_NewURI(getter_AddRefs(url), uri.get()); |
|
947 nsCOMPtr<nsIChannel> channel; |
|
948 if (NS_SUCCEEDED(rv) && (url)) { |
|
949 rv = NS_NewChannel(getter_AddRefs(channel), url, nullptr, nullptr); |
|
950 } |
|
951 if (NS_SUCCEEDED(rv) && (channel)) { |
|
952 channel->SetNotificationCallbacks(httpIndex); |
|
953 rv = channel->AsyncOpen(httpIndex, aSource); |
|
954 } |
|
955 } |
|
956 } |
|
957 if (httpIndex->mNodeList) |
|
958 { |
|
959 httpIndex->mNodeList->Count(&numItems); |
|
960 if (numItems > 0) |
|
961 { |
|
962 // account for order required: src, prop, then target |
|
963 numItems /=3; |
|
964 if (numItems > 10) numItems = 10; |
|
965 |
|
966 int32_t loop; |
|
967 for (loop=0; loop<(int32_t)numItems; loop++) |
|
968 { |
|
969 nsCOMPtr<nsISupports> isupports; |
|
970 httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); |
|
971 httpIndex->mNodeList->RemoveElementAt((uint32_t)0); |
|
972 nsCOMPtr<nsIRDFResource> src; |
|
973 if (isupports) src = do_QueryInterface(isupports); |
|
974 httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); |
|
975 httpIndex->mNodeList->RemoveElementAt((uint32_t)0); |
|
976 nsCOMPtr<nsIRDFResource> prop; |
|
977 if (isupports) prop = do_QueryInterface(isupports); |
|
978 |
|
979 httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); |
|
980 httpIndex->mNodeList->RemoveElementAt((uint32_t)0); |
|
981 nsCOMPtr<nsIRDFNode> target; |
|
982 if (isupports) target = do_QueryInterface(isupports); |
|
983 |
|
984 if (src && prop && target) |
|
985 { |
|
986 if (prop.get() == httpIndex->kNC_Loading) |
|
987 { |
|
988 httpIndex->Unassert(src, prop, target); |
|
989 } |
|
990 else |
|
991 { |
|
992 httpIndex->Assert(src, prop, target, true); |
|
993 } |
|
994 } |
|
995 } |
|
996 } |
|
997 } |
|
998 |
|
999 bool refireTimer = false; |
|
1000 // check both lists to see if the timer needs to continue firing |
|
1001 if (httpIndex->mConnectionList) |
|
1002 { |
|
1003 httpIndex->mConnectionList->Count(&numItems); |
|
1004 if (numItems > 0) |
|
1005 { |
|
1006 refireTimer = true; |
|
1007 } |
|
1008 else |
|
1009 { |
|
1010 httpIndex->mConnectionList->Clear(); |
|
1011 } |
|
1012 } |
|
1013 if (httpIndex->mNodeList) |
|
1014 { |
|
1015 httpIndex->mNodeList->Count(&numItems); |
|
1016 if (numItems > 0) |
|
1017 { |
|
1018 refireTimer = true; |
|
1019 } |
|
1020 else |
|
1021 { |
|
1022 httpIndex->mNodeList->Clear(); |
|
1023 } |
|
1024 } |
|
1025 |
|
1026 // be sure to cancel the timer, as it holds a |
|
1027 // weak reference back to nsHTTPIndex |
|
1028 httpIndex->mTimer->Cancel(); |
|
1029 httpIndex->mTimer = nullptr; |
|
1030 |
|
1031 // after firing off any/all of the connections be sure |
|
1032 // to cancel the timer if we don't need to refire it |
|
1033 if (refireTimer) |
|
1034 { |
|
1035 httpIndex->mTimer = do_CreateInstance("@mozilla.org/timer;1"); |
|
1036 if (httpIndex->mTimer) |
|
1037 { |
|
1038 httpIndex->mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, aClosure, 10, |
|
1039 nsITimer::TYPE_ONE_SHOT); |
|
1040 // Note: don't addref "this" as we'll cancel the |
|
1041 // timer in the httpIndex destructor |
|
1042 } |
|
1043 } |
|
1044 } |
|
1045 |
|
1046 NS_IMETHODIMP |
|
1047 nsHTTPIndex::Assert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget, |
|
1048 bool aTruthValue) |
|
1049 { |
|
1050 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1051 if (mInner) |
|
1052 { |
|
1053 rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue); |
|
1054 } |
|
1055 return(rv); |
|
1056 } |
|
1057 |
|
1058 NS_IMETHODIMP |
|
1059 nsHTTPIndex::Unassert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget) |
|
1060 { |
|
1061 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1062 if (mInner) |
|
1063 { |
|
1064 rv = mInner->Unassert(aSource, aProperty, aTarget); |
|
1065 } |
|
1066 return(rv); |
|
1067 } |
|
1068 |
|
1069 NS_IMETHODIMP |
|
1070 nsHTTPIndex::Change(nsIRDFResource *aSource, nsIRDFResource *aProperty, |
|
1071 nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget) |
|
1072 { |
|
1073 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1074 if (mInner) |
|
1075 { |
|
1076 rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); |
|
1077 } |
|
1078 return(rv); |
|
1079 } |
|
1080 |
|
1081 NS_IMETHODIMP |
|
1082 nsHTTPIndex::Move(nsIRDFResource *aOldSource, nsIRDFResource *aNewSource, |
|
1083 nsIRDFResource *aProperty, nsIRDFNode *aTarget) |
|
1084 { |
|
1085 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1086 if (mInner) |
|
1087 { |
|
1088 rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget); |
|
1089 } |
|
1090 return(rv); |
|
1091 } |
|
1092 |
|
1093 NS_IMETHODIMP |
|
1094 nsHTTPIndex::HasAssertion(nsIRDFResource *aSource, nsIRDFResource *aProperty, |
|
1095 nsIRDFNode *aTarget, bool aTruthValue, bool *_retval) |
|
1096 { |
|
1097 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1098 if (mInner) |
|
1099 { |
|
1100 rv = mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, _retval); |
|
1101 } |
|
1102 return(rv); |
|
1103 } |
|
1104 |
|
1105 NS_IMETHODIMP |
|
1106 nsHTTPIndex::AddObserver(nsIRDFObserver *aObserver) |
|
1107 { |
|
1108 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1109 if (mInner) |
|
1110 { |
|
1111 rv = mInner->AddObserver(aObserver); |
|
1112 } |
|
1113 return(rv); |
|
1114 } |
|
1115 |
|
1116 NS_IMETHODIMP |
|
1117 nsHTTPIndex::RemoveObserver(nsIRDFObserver *aObserver) |
|
1118 { |
|
1119 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1120 if (mInner) |
|
1121 { |
|
1122 rv = mInner->RemoveObserver(aObserver); |
|
1123 } |
|
1124 return(rv); |
|
1125 } |
|
1126 |
|
1127 NS_IMETHODIMP |
|
1128 nsHTTPIndex::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) |
|
1129 { |
|
1130 if (!mInner) { |
|
1131 *result = false; |
|
1132 return NS_OK; |
|
1133 } |
|
1134 return mInner->HasArcIn(aNode, aArc, result); |
|
1135 } |
|
1136 |
|
1137 NS_IMETHODIMP |
|
1138 nsHTTPIndex::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) |
|
1139 { |
|
1140 if (aArc == kNC_Child && isWellknownContainerURI(aSource)) { |
|
1141 *result = true; |
|
1142 return NS_OK; |
|
1143 } |
|
1144 |
|
1145 if (mInner) { |
|
1146 return mInner->HasArcOut(aSource, aArc, result); |
|
1147 } |
|
1148 |
|
1149 *result = false; |
|
1150 return NS_OK; |
|
1151 } |
|
1152 |
|
1153 NS_IMETHODIMP |
|
1154 nsHTTPIndex::ArcLabelsIn(nsIRDFNode *aNode, nsISimpleEnumerator **_retval) |
|
1155 { |
|
1156 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1157 if (mInner) |
|
1158 { |
|
1159 rv = mInner->ArcLabelsIn(aNode, _retval); |
|
1160 } |
|
1161 return(rv); |
|
1162 } |
|
1163 |
|
1164 NS_IMETHODIMP |
|
1165 nsHTTPIndex::ArcLabelsOut(nsIRDFResource *aSource, nsISimpleEnumerator **_retval) |
|
1166 { |
|
1167 *_retval = nullptr; |
|
1168 |
|
1169 nsCOMPtr<nsISimpleEnumerator> child, anonArcs; |
|
1170 if (isWellknownContainerURI(aSource)) |
|
1171 { |
|
1172 NS_NewSingletonEnumerator(getter_AddRefs(child), kNC_Child); |
|
1173 } |
|
1174 |
|
1175 if (mInner) |
|
1176 { |
|
1177 mInner->ArcLabelsOut(aSource, getter_AddRefs(anonArcs)); |
|
1178 } |
|
1179 |
|
1180 return NS_NewUnionEnumerator(_retval, child, anonArcs); |
|
1181 } |
|
1182 |
|
1183 NS_IMETHODIMP |
|
1184 nsHTTPIndex::GetAllResources(nsISimpleEnumerator **_retval) |
|
1185 { |
|
1186 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1187 if (mInner) |
|
1188 { |
|
1189 rv = mInner->GetAllResources(_retval); |
|
1190 } |
|
1191 return(rv); |
|
1192 } |
|
1193 |
|
1194 NS_IMETHODIMP |
|
1195 nsHTTPIndex::IsCommandEnabled(nsISupportsArray *aSources, nsIRDFResource *aCommand, |
|
1196 nsISupportsArray *aArguments, bool *_retval) |
|
1197 { |
|
1198 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1199 if (mInner) |
|
1200 { |
|
1201 rv = mInner->IsCommandEnabled(aSources, aCommand, aArguments, _retval); |
|
1202 } |
|
1203 return(rv); |
|
1204 } |
|
1205 |
|
1206 NS_IMETHODIMP |
|
1207 nsHTTPIndex::DoCommand(nsISupportsArray *aSources, nsIRDFResource *aCommand, |
|
1208 nsISupportsArray *aArguments) |
|
1209 { |
|
1210 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1211 if (mInner) |
|
1212 { |
|
1213 rv = mInner->DoCommand(aSources, aCommand, aArguments); |
|
1214 } |
|
1215 return(rv); |
|
1216 } |
|
1217 |
|
1218 NS_IMETHODIMP |
|
1219 nsHTTPIndex::BeginUpdateBatch() |
|
1220 { |
|
1221 return mInner->BeginUpdateBatch(); |
|
1222 } |
|
1223 |
|
1224 NS_IMETHODIMP |
|
1225 nsHTTPIndex::EndUpdateBatch() |
|
1226 { |
|
1227 return mInner->EndUpdateBatch(); |
|
1228 } |
|
1229 |
|
1230 NS_IMETHODIMP |
|
1231 nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval) |
|
1232 { |
|
1233 nsresult rv = NS_ERROR_UNEXPECTED; |
|
1234 if (mInner) |
|
1235 { |
|
1236 rv = mInner->GetAllCmds(aSource, _retval); |
|
1237 } |
|
1238 return(rv); |
|
1239 } |
|
1240 |
|
1241 |
|
1242 //---------------------------------------------------------------------- |
|
1243 // |
|
1244 // nsDirectoryViewerFactory |
|
1245 // |
|
1246 nsDirectoryViewerFactory::nsDirectoryViewerFactory() |
|
1247 { |
|
1248 } |
|
1249 |
|
1250 |
|
1251 |
|
1252 nsDirectoryViewerFactory::~nsDirectoryViewerFactory() |
|
1253 { |
|
1254 } |
|
1255 |
|
1256 |
|
1257 NS_IMPL_ISUPPORTS(nsDirectoryViewerFactory, nsIDocumentLoaderFactory) |
|
1258 |
|
1259 |
|
1260 |
|
1261 NS_IMETHODIMP |
|
1262 nsDirectoryViewerFactory::CreateInstance(const char *aCommand, |
|
1263 nsIChannel* aChannel, |
|
1264 nsILoadGroup* aLoadGroup, |
|
1265 const char* aContentType, |
|
1266 nsIDocShell* aContainer, |
|
1267 nsISupports* aExtraInfo, |
|
1268 nsIStreamListener** aDocListenerResult, |
|
1269 nsIContentViewer** aDocViewerResult) |
|
1270 { |
|
1271 nsresult rv; |
|
1272 |
|
1273 bool viewSource = (PL_strstr(aContentType,"view-source") != 0); |
|
1274 |
|
1275 if (!viewSource && |
|
1276 Preferences::GetInt("network.dir.format", FORMAT_XUL) == FORMAT_XUL) { |
|
1277 // ... and setup the original channel's content type |
|
1278 (void)aChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml")); |
|
1279 |
|
1280 // This is where we shunt the HTTP/Index stream into our datasource, |
|
1281 // and open the directory viewer XUL file as the content stream to |
|
1282 // load in its place. |
|
1283 |
|
1284 // Create a dummy loader that will load a stub XUL document. |
|
1285 nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); |
|
1286 if (NS_FAILED(rv)) |
|
1287 return rv; |
|
1288 nsXPIDLCString contractID; |
|
1289 rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "application/vnd.mozilla.xul+xml", |
|
1290 getter_Copies(contractID)); |
|
1291 if (NS_FAILED(rv)) |
|
1292 return rv; |
|
1293 |
|
1294 nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv)); |
|
1295 if (NS_FAILED(rv)) return rv; |
|
1296 |
|
1297 nsCOMPtr<nsIURI> uri; |
|
1298 rv = NS_NewURI(getter_AddRefs(uri), "chrome://communicator/content/directory/directory.xul"); |
|
1299 if (NS_FAILED(rv)) return rv; |
|
1300 |
|
1301 nsCOMPtr<nsIChannel> channel; |
|
1302 rv = NS_NewChannel(getter_AddRefs(channel), uri, nullptr, aLoadGroup); |
|
1303 if (NS_FAILED(rv)) return rv; |
|
1304 |
|
1305 nsCOMPtr<nsIStreamListener> listener; |
|
1306 rv = factory->CreateInstance(aCommand, channel, aLoadGroup, "application/vnd.mozilla.xul+xml", |
|
1307 aContainer, aExtraInfo, getter_AddRefs(listener), |
|
1308 aDocViewerResult); |
|
1309 if (NS_FAILED(rv)) return rv; |
|
1310 |
|
1311 rv = channel->AsyncOpen(listener, nullptr); |
|
1312 if (NS_FAILED(rv)) return rv; |
|
1313 |
|
1314 // Create an HTTPIndex object so that we can stuff it into the script context |
|
1315 nsCOMPtr<nsIURI> baseuri; |
|
1316 rv = aChannel->GetURI(getter_AddRefs(baseuri)); |
|
1317 if (NS_FAILED(rv)) return rv; |
|
1318 |
|
1319 nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aContainer,&rv); |
|
1320 if (NS_FAILED(rv)) return rv; |
|
1321 |
|
1322 nsCOMPtr<nsIHTTPIndex> httpindex; |
|
1323 rv = nsHTTPIndex::Create(baseuri, requestor, getter_AddRefs(httpindex)); |
|
1324 if (NS_FAILED(rv)) return rv; |
|
1325 |
|
1326 // Now shanghai the stream into our http-index parsing datasource |
|
1327 // wrapper beastie. |
|
1328 listener = do_QueryInterface(httpindex,&rv); |
|
1329 *aDocListenerResult = listener.get(); |
|
1330 NS_ADDREF(*aDocListenerResult); |
|
1331 |
|
1332 return NS_OK; |
|
1333 } |
|
1334 |
|
1335 // setup the original channel's content type |
|
1336 (void)aChannel->SetContentType(NS_LITERAL_CSTRING("text/html")); |
|
1337 |
|
1338 // Otherwise, lets use the html listing |
|
1339 nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); |
|
1340 if (NS_FAILED(rv)) |
|
1341 return rv; |
|
1342 nsXPIDLCString contractID; |
|
1343 rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html", |
|
1344 getter_Copies(contractID)); |
|
1345 if (NS_FAILED(rv)) |
|
1346 return rv; |
|
1347 |
|
1348 nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv)); |
|
1349 if (NS_FAILED(rv)) return rv; |
|
1350 |
|
1351 nsCOMPtr<nsIStreamListener> listener; |
|
1352 |
|
1353 if (viewSource) { |
|
1354 rv = factory->CreateInstance("view-source", aChannel, aLoadGroup, "text/html; x-view-type=view-source", |
|
1355 aContainer, aExtraInfo, getter_AddRefs(listener), |
|
1356 aDocViewerResult); |
|
1357 } else { |
|
1358 rv = factory->CreateInstance("view", aChannel, aLoadGroup, "text/html", |
|
1359 aContainer, aExtraInfo, getter_AddRefs(listener), |
|
1360 aDocViewerResult); |
|
1361 } |
|
1362 |
|
1363 if (NS_FAILED(rv)) return rv; |
|
1364 |
|
1365 nsCOMPtr<nsIStreamConverterService> scs = do_GetService("@mozilla.org/streamConverters;1", &rv); |
|
1366 if (NS_FAILED(rv)) return rv; |
|
1367 |
|
1368 rv = scs->AsyncConvertData("application/http-index-format", |
|
1369 "text/html", |
|
1370 listener, |
|
1371 nullptr, |
|
1372 aDocListenerResult); |
|
1373 |
|
1374 if (NS_FAILED(rv)) return rv; |
|
1375 |
|
1376 return NS_OK; |
|
1377 } |
|
1378 |
|
1379 |
|
1380 |
|
1381 NS_IMETHODIMP |
|
1382 nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer, |
|
1383 nsIDocument* aDocument, |
|
1384 const char *aCommand, |
|
1385 nsIContentViewer** aDocViewerResult) |
|
1386 { |
|
1387 NS_NOTYETIMPLEMENTED("didn't expect to get here"); |
|
1388 return NS_ERROR_NOT_IMPLEMENTED; |
|
1389 } |
|
1390 |
|
1391 NS_IMETHODIMP |
|
1392 nsDirectoryViewerFactory::CreateBlankDocument(nsILoadGroup *aLoadGroup, |
|
1393 nsIPrincipal *aPrincipal, |
|
1394 nsIDocument **_retval) { |
|
1395 |
|
1396 NS_NOTYETIMPLEMENTED("didn't expect to get here"); |
|
1397 return NS_ERROR_NOT_IMPLEMENTED; |
|
1398 } |