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