xpfe/components/directory/nsDirectoryViewer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial