Back to index

lightning-sunbird  0.9+nobinonly
nsInternetSearchService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Robert John Churchill      <rjc@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040   Implementation for an internet search RDF data store.
00041  */
00042 
00043 #include "nsInternetSearchService.h"
00044 #include "nsLocalSearchService.h"
00045 
00046 #include "nscore.h"
00047 #include "nsIEnumerator.h"
00048 #include "nsIRDFObserver.h"
00049 #include "nsIRDFContainer.h"
00050 #include "nsIRDFContainerUtils.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsVoidArray.h"  // XXX introduces dependency on raptorbase
00053 #include "nsXPIDLString.h"
00054 #include "nsRDFCID.h"
00055 #include "plhash.h"
00056 #include "plstr.h"
00057 #include "prmem.h"
00058 #include "prprf.h"
00059 #include "prio.h"
00060 #include "prlog.h"
00061 #include "rdf.h"
00062 #include "nsIDirectoryService.h"
00063 #include "nsDirectoryServiceDefs.h"
00064 #include "nsAppDirectoryServiceDefs.h"
00065 #include "nsCOMArray.h"
00066 #include "nsCRT.h"
00067 #include "nsEnumeratorUtils.h"
00068 #include "nsIRDFRemoteDataSource.h"
00069 #include "nsICharsetConverterManager.h"
00070 #include "nsICharsetAlias.h"
00071 #include "nsITextToSubURI.h"
00072 #include "nsEscape.h"
00073 #include "nsNetUtil.h"
00074 #include "nsIChannel.h"
00075 #include "nsIFileChannel.h"
00076 #include "nsIHttpChannel.h"
00077 #include "nsIUploadChannel.h"
00078 #include "nsIInputStream.h"
00079 #ifndef MOZ_PLACES
00080 #include "nsIBookmarksService.h"
00081 #endif
00082 #include "nsIStringBundle.h"
00083 #include "nsIObserverService.h"
00084 #include "nsIURL.h"
00085 #include "nsILocalFile.h"
00086 #include "nsUnicharUtils.h"
00087 #include "nsReadableUtils.h"
00088 #include "nsIPrefLocalizedString.h"
00089 #include "nsIGenericFactory.h"
00090 
00091 #ifdef XP_WIN
00092 #include "windef.h"
00093 #include "winbase.h"
00094 #endif
00095 
00096 #ifdef DEBUG
00097 // #define    DEBUG_SEARCH_OUTPUT  1
00098 // #define    DEBUG_SEARCH_UPDATES 1
00099 #endif
00100 
00101 #define MAX_SEARCH_RESULTS_ALLOWED  100
00102 
00103 #define POSTHEADER_PREFIX "Content-type: application/x-www-form-urlencoded\r\nContent-Length: "
00104 #define POSTHEADER_SUFFIX "\r\n\r\n"
00105 #define SEARCH_PROPERTIES "chrome://communicator/locale/search/search-panel.properties"
00106 #ifdef MOZ_XUL_APP
00107 #define SEARCHCONFIG_PROPERTIES "chrome://branding/content/searchconfig.properties"
00108 #define INTL_PROPERTIES "chrome://global/locale/intl.properties"
00109 #else
00110 #define SEARCHCONFIG_PROPERTIES "chrome://navigator/content/searchconfig.properties"
00111 #define INTL_PROPERTIES "chrome://navigator/locale/navigator.properties"
00112 #endif
00113 
00114 static NS_DEFINE_CID(kRDFServiceCID,               NS_RDFSERVICE_CID);
00115 static NS_DEFINE_CID(kRDFContainerCID,             NS_RDFCONTAINER_CID);
00116 static NS_DEFINE_CID(kRDFContainerUtilsCID,        NS_RDFCONTAINERUTILS_CID);
00117 static NS_DEFINE_CID(kRDFInMemoryDataSourceCID,    NS_RDFINMEMORYDATASOURCE_CID);
00118 static NS_DEFINE_CID(kRDFXMLDataSourceCID,         NS_RDFXMLDATASOURCE_CID);
00119 static NS_DEFINE_CID(kTextToSubURICID,             NS_TEXTTOSUBURI_CID);
00120 static NS_DEFINE_CID(kPrefCID,                     NS_PREF_CID);
00121 
00122 static const char kURINC_SearchEngineRoot[]                   = "NC:SearchEngineRoot";
00123 static const char kURINC_SearchResultsSitesRoot[]             = "NC:SearchResultsSitesRoot";
00124 static const char kURINC_LastSearchRoot[]                     = "NC:LastSearchRoot";
00125 static const char kURINC_SearchCategoryRoot[]                 = "NC:SearchCategoryRoot";
00126 static const char kURINC_SearchCategoryPrefix[]               = "NC:SearchCategory?category=";
00127 static const char kURINC_SearchCategoryEnginePrefix[]         = "NC:SearchCategory?engine=";
00128 static const char kURINC_SearchCategoryEngineBasenamePrefix[] = "NC:SearchCategory?engine=urn:search:engine:";
00129  
00130 static const char kURINC_FilterSearchURLsRoot[]       = "NC:FilterSearchURLsRoot";
00131 static const char kURINC_FilterSearchSitesRoot[]      = "NC:FilterSearchSitesRoot";
00132 static const char kSearchCommand[]                    = "http://home.netscape.com/NC-rdf#command?";
00133 
00134 int    PR_CALLBACK searchModePrefCallback(const char *pref, void *aClosure);
00135 
00136 // helper routine because we need to rewrite this to use string
00137 // iterators.. this replaces the old nsString::Find
00138 
00139 static PRInt32 nsString_Find(const nsAString& aPattern,
00140                              const nsAString& aSource,
00141                              PRBool aIgnoreCase = PR_FALSE,
00142                              PRInt32 aOffset = 0, PRInt32 aCount = -1)
00143 {
00144     nsAString::const_iterator start, end;
00145     aSource.BeginReading(start);
00146     aSource.EndReading(end);
00147 
00148     // now adjust for the parameters
00149     start.advance(aOffset);
00150     if (aCount>0) {
00151        end = start;         // note that start may have been advanced!
00152        end.advance(aCount);
00153     }
00154     PRBool found;
00155     if (aIgnoreCase)
00156        found = FindInReadable(aPattern, start, end,
00157                             nsCaseInsensitiveStringComparator());
00158     else
00159        found = FindInReadable(aPattern, start, end);
00160 
00161     if (!found)
00162        return kNotFound;
00163 
00164     nsAString::const_iterator originalStart;
00165     aSource.BeginReading(originalStart);
00166     return Distance(originalStart, start);
00167 }
00168 
00169 class  InternetSearchContext : public nsIInternetSearchContext
00170 {
00171 public:
00172                      InternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine,
00173                             nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint);
00174        virtual              ~InternetSearchContext(void);
00175        NS_METHOD     Init();
00176 
00177        NS_DECL_ISUPPORTS
00178        NS_DECL_NSIINTERNETSEARCHCONTEXT
00179 
00180 private:
00181        PRUint32                    mContextType;
00182        nsCOMPtr<nsIRDFResource>    mParent;
00183        nsCOMPtr<nsIRDFResource>    mEngine;
00184        nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
00185        nsString                    mBuffer;
00186        nsString                    mHint;
00187 };
00188 
00189 
00190 
00191 InternetSearchContext::~InternetSearchContext(void)
00192 {
00193 }
00194 
00195 
00196 
00197 InternetSearchContext::InternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine,
00198                             nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint)
00199        : mContextType(contextType), mParent(aParent), mEngine(aEngine), mUnicodeDecoder(aUnicodeDecoder), mHint(hint)
00200 {
00201 }
00202 
00203 
00204 
00205 NS_IMETHODIMP
00206 InternetSearchContext::Init()
00207 {
00208        return(NS_OK);
00209 }
00210 
00211 
00212 
00213 NS_IMETHODIMP
00214 InternetSearchContext::GetContextType(PRUint32 *aContextType)
00215 {
00216        *aContextType = mContextType;
00217        return(NS_OK);
00218 }
00219 
00220 
00221 
00222 NS_IMETHODIMP
00223 InternetSearchContext::GetUnicodeDecoder(nsIUnicodeDecoder **decoder)
00224 {
00225        *decoder = mUnicodeDecoder;
00226        NS_IF_ADDREF(*decoder);
00227        return(NS_OK);
00228 }
00229 
00230 
00231 
00232 NS_IMETHODIMP
00233 InternetSearchContext::GetEngine(nsIRDFResource **node)
00234 {
00235        *node = mEngine;
00236        NS_IF_ADDREF(*node);
00237        return(NS_OK);
00238 }
00239 
00240 
00241 
00242 NS_IMETHODIMP
00243 InternetSearchContext::GetHintConst(const PRUnichar **hint)
00244 {
00245        *hint = mHint.get();
00246        return(NS_OK);
00247 }
00248 
00249 
00250 
00251 NS_IMETHODIMP
00252 InternetSearchContext::GetParent(nsIRDFResource **node)
00253 {
00254        *node = mParent;
00255        NS_IF_ADDREF(*node);
00256        return(NS_OK);
00257 }
00258 
00259 
00260 
00261 NS_IMETHODIMP
00262 InternetSearchContext::AppendBytes(const char *buffer, PRInt32 numBytes)
00263 {
00264        mBuffer.AppendWithConversion(buffer, numBytes);
00265        return(NS_OK);
00266 }
00267 
00268 
00269 
00270 NS_IMETHODIMP
00271 InternetSearchContext::AppendUnicodeBytes(const PRUnichar *buffer, PRInt32 numUniBytes)
00272 {
00273        mBuffer.Append(buffer, numUniBytes);
00274        return(NS_OK);
00275 }
00276 
00277 
00278 
00279 NS_IMETHODIMP
00280 InternetSearchContext::GetBufferConst(const PRUnichar **buffer)
00281 {
00282        *buffer = mBuffer.get();
00283        return(NS_OK);
00284 }
00285 
00286 
00287 
00288 NS_IMETHODIMP
00289 InternetSearchContext::GetBufferLength(PRInt32 *bufferLen)
00290 {
00291        *bufferLen = mBuffer.Length();
00292        return(NS_OK);
00293 }
00294 
00295 
00296 
00297 NS_IMETHODIMP
00298 InternetSearchContext::Truncate()
00299 {
00300        mBuffer.Truncate();
00301        return(NS_OK);
00302 }
00303 
00304 
00305 
00306 NS_IMPL_THREADSAFE_ISUPPORTS1(InternetSearchContext, nsIInternetSearchContext)
00307 
00308 
00309 
00310 nsresult
00311 NS_NewInternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine,
00312                          nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint, nsIInternetSearchContext **aResult)
00313 {
00314         InternetSearchContext *result =
00315                new InternetSearchContext(contextType, aParent, aEngine, aUnicodeDecoder, hint);
00316 
00317         if (! result)
00318                return NS_ERROR_OUT_OF_MEMORY;
00319 
00320         nsresult rv = result->Init();
00321         if (NS_FAILED(rv)) {
00322                delete result;
00323                return rv;
00324         }
00325 
00326         NS_ADDREF(result);
00327         *aResult = result;
00328         return NS_OK;
00329 }
00330 
00331 
00332 
00333 
00334 
00335 static const char           kEngineProtocol[] = "engine://";
00336 static const char           kSearchProtocol[] = "internetsearch:";
00337 
00338 #ifdef DEBUG_SEARCH_UPDATES
00339 #define       SEARCH_UPDATE_TIMEOUT       10000         // fire every 10 seconds
00340 #else
00341 #define       SEARCH_UPDATE_TIMEOUT       60000         // fire every 60 seconds
00342 #endif
00343 
00344 
00345 int PR_CALLBACK
00346 searchModePrefCallback(const char *pref, void *aClosure)
00347 {
00348        InternetSearchDataSource *searchDS = NS_STATIC_CAST(InternetSearchDataSource *, aClosure);
00349        if (!searchDS)       return(NS_OK);
00350 
00351        if (searchDS->prefs)
00352        {
00353               searchDS->prefs->GetIntPref(pref, &searchDS->gBrowserSearchMode);
00354 #ifdef DEBUG
00355               printf("searchModePrefCallback: '%s' = %d\n", pref, searchDS->gBrowserSearchMode);
00356 #endif
00357               searchDS->Assert(searchDS->kNC_LastSearchRoot, searchDS->kNC_LastSearchMode, searchDS->kTrueLiteral, PR_TRUE);
00358        }
00359        return(NS_OK);
00360 }
00361 
00362 static nsIRDFService        *gRDFService = nsnull;
00363 static nsIRDFContainerUtils *gRDFC = nsnull;
00364 PRInt32                            InternetSearchDataSource::gRefCnt = 0;
00365 PRInt32                            InternetSearchDataSource::gBrowserSearchMode = 0;
00366 nsIRDFDataSource            *InternetSearchDataSource::mInner = nsnull;
00367 nsCOMPtr<nsISupportsArray>  InternetSearchDataSource::mUpdateArray;
00368 nsCOMPtr<nsIRDFDataSource>  InternetSearchDataSource::mLocalstore;
00369 nsCOMPtr<nsIRDFDataSource>  InternetSearchDataSource::categoryDataSource;
00370 PRBool                      InternetSearchDataSource::gEngineListBuilt = PR_FALSE;
00371 #ifdef MOZ_PHOENIX
00372 PRBool        InternetSearchDataSource::gReorderedEngineList = PR_FALSE;
00373 #endif
00374 nsCOMPtr<nsILoadGroup>             InternetSearchDataSource::mBackgroundLoadGroup;
00375 nsCOMPtr<nsILoadGroup>             InternetSearchDataSource::mLoadGroup;
00376 nsCOMPtr<nsIPref>           InternetSearchDataSource::prefs;
00377 
00378 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchResult;
00379 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchEngineRoot;
00380 nsIRDFResource                     *InternetSearchDataSource::kNC_LastSearchRoot;
00381 nsIRDFResource                     *InternetSearchDataSource::kNC_LastSearchMode;
00382 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCategoryRoot;
00383 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchResultsSitesRoot;
00384 nsIRDFResource                     *InternetSearchDataSource::kNC_FilterSearchURLsRoot;
00385 nsIRDFResource                     *InternetSearchDataSource::kNC_FilterSearchSitesRoot;
00386 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchType;
00387 nsIRDFResource                     *InternetSearchDataSource::kNC_Ref;
00388 nsIRDFResource                     *InternetSearchDataSource::kNC_Child;
00389 nsIRDFResource                     *InternetSearchDataSource::kNC_Title;
00390 nsIRDFResource                     *InternetSearchDataSource::kNC_Data;
00391 nsIRDFResource                     *InternetSearchDataSource::kNC_Name;
00392 nsIRDFResource                     *InternetSearchDataSource::kNC_Description;
00393 nsIRDFResource                     *InternetSearchDataSource::kNC_Version;
00394 nsIRDFResource                     *InternetSearchDataSource::kNC_actionButton;
00395 nsIRDFResource                     *InternetSearchDataSource::kNC_actionBar;
00396 nsIRDFResource                     *InternetSearchDataSource::kNC_searchForm;
00397 nsIRDFResource                     *InternetSearchDataSource::kNC_LastText;
00398 nsIRDFResource                     *InternetSearchDataSource::kNC_URL;
00399 nsIRDFResource                     *InternetSearchDataSource::kRDF_InstanceOf;
00400 nsIRDFResource                     *InternetSearchDataSource::kRDF_type;
00401 nsIRDFResource                     *InternetSearchDataSource::kNC_loading;
00402 nsIRDFResource                     *InternetSearchDataSource::kNC_HTML;
00403 nsIRDFResource                     *InternetSearchDataSource::kNC_Icon;
00404 nsIRDFResource                     *InternetSearchDataSource::kNC_StatusIcon;
00405 nsIRDFResource                     *InternetSearchDataSource::kNC_Banner;
00406 nsIRDFResource                     *InternetSearchDataSource::kNC_Site;
00407 nsIRDFResource                     *InternetSearchDataSource::kNC_Relevance;
00408 nsIRDFResource                     *InternetSearchDataSource::kNC_RelevanceSort;
00409 nsIRDFResource                     *InternetSearchDataSource::kNC_Date;
00410 nsIRDFResource                     *InternetSearchDataSource::kNC_PageRank;
00411 nsIRDFResource                     *InternetSearchDataSource::kNC_Engine;
00412 nsIRDFResource                     *InternetSearchDataSource::kNC_Price;
00413 nsIRDFResource                     *InternetSearchDataSource::kNC_PriceSort;
00414 nsIRDFResource                     *InternetSearchDataSource::kNC_Availability;
00415 nsIRDFResource                     *InternetSearchDataSource::kNC_BookmarkSeparator;
00416 nsIRDFResource                     *InternetSearchDataSource::kNC_Update;
00417 nsIRDFResource                     *InternetSearchDataSource::kNC_UpdateIcon;
00418 nsIRDFResource                     *InternetSearchDataSource::kNC_UpdateCheckDays;
00419 nsIRDFResource                     *InternetSearchDataSource::kWEB_LastPingDate;
00420 nsIRDFResource                     *InternetSearchDataSource::kWEB_LastPingModDate;
00421 nsIRDFResource                     *InternetSearchDataSource::kWEB_LastPingContentLen;
00422 
00423 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCommand_AddToBookmarks;
00424 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCommand_AddQueryToBookmarks;
00425 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCommand_FilterResult;
00426 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCommand_FilterSite;
00427 nsIRDFResource                     *InternetSearchDataSource::kNC_SearchCommand_ClearFilters;
00428 
00429 nsIRDFLiteral               *InternetSearchDataSource::kTrueLiteral;
00430 InternetSearchDataSource::InternetSearchDataSource(void)
00431 {
00432        if (gRefCnt++ == 0)
00433        {
00434               nsresult rv = CallGetService(kRDFServiceCID, &gRDFService);
00435               NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
00436 
00437               rv = CallGetService(kRDFContainerUtilsCID, &gRDFC);
00438               NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF container utils");
00439 
00440               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchEngineRoot),
00441                              &kNC_SearchEngineRoot);
00442               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_LastSearchRoot),
00443                              &kNC_LastSearchRoot);
00444               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchResultsSitesRoot),
00445                              &kNC_SearchResultsSitesRoot);
00446               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_FilterSearchURLsRoot),
00447                              &kNC_FilterSearchURLsRoot);
00448               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_FilterSearchSitesRoot),
00449                              &kNC_FilterSearchSitesRoot);
00450               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchCategoryRoot),
00451                              &kNC_SearchCategoryRoot);
00452               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "SearchMode"),
00453                              &kNC_LastSearchMode);
00454 
00455               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "searchtype"),
00456                              &kNC_SearchType);
00457               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "SearchResult"),
00458                              &kNC_SearchResult);
00459               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "ref"),
00460                              &kNC_Ref);
00461               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
00462                              &kNC_Child);
00463               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "title"),
00464                              &kNC_Title);
00465               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "data"),
00466                              &kNC_Data);
00467               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
00468                              &kNC_Name);
00469               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Description"),
00470                              &kNC_Description);
00471               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Version"),
00472                              &kNC_Version);
00473               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "actionButton"),
00474                              &kNC_actionButton);
00475               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "actionBar"),
00476                              &kNC_actionBar);
00477               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "searchForm"),
00478                              &kNC_searchForm);
00479               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "LastText"),
00480                              &kNC_LastText);
00481               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"),
00482                              &kNC_URL);
00483               gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
00484                              &kRDF_InstanceOf);
00485               gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
00486                              &kRDF_type);
00487               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"),
00488                              &kNC_loading);
00489               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "HTML"),
00490                              &kNC_HTML);
00491               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Icon"),
00492                              &kNC_Icon);
00493               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "StatusIcon"),
00494                              &kNC_StatusIcon);
00495               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Banner"),
00496                              &kNC_Banner);
00497               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Site"),
00498                              &kNC_Site);
00499               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Relevance"),
00500                              &kNC_Relevance);
00501               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Relevance?sort=true"),
00502                              &kNC_RelevanceSort);
00503               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Date"),
00504                              &kNC_Date);
00505               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "PageRank"),
00506                              &kNC_PageRank);
00507               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Engine"),
00508                              &kNC_Engine);
00509               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Price"),
00510                              &kNC_Price);
00511               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Price?sort=true"),
00512                              &kNC_PriceSort);
00513               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Availability"),
00514                              &kNC_Availability);
00515               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
00516                              &kNC_BookmarkSeparator);
00517               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Update"),
00518                              &kNC_Update);
00519               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "UpdateIcon"),
00520                              &kNC_UpdateIcon);
00521               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "UpdateCheckDays"),
00522                              &kNC_UpdateCheckDays);
00523               gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingDate"),
00524                              &kWEB_LastPingDate);
00525               gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingModDate"),
00526                              &kWEB_LastPingModDate);
00527               gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingContentLen"),
00528                              &kWEB_LastPingContentLen);
00529 
00530               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=addtobookmarks"),
00531                              &kNC_SearchCommand_AddToBookmarks);
00532               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=addquerytobookmarks"),
00533                              &kNC_SearchCommand_AddQueryToBookmarks);
00534               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=filterresult"),
00535                              &kNC_SearchCommand_FilterResult);
00536               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=filtersite"),
00537                              &kNC_SearchCommand_FilterSite);
00538               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=clearfilters"),
00539                              &kNC_SearchCommand_ClearFilters);
00540 
00541               gRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), &kTrueLiteral);
00542 
00543               prefs = do_GetService(kPrefCID);
00544               if (prefs)
00545               {
00546                      prefs->RegisterCallback("browser.search.mode", searchModePrefCallback, this);
00547                      prefs->GetIntPref("browser.search.mode", &gBrowserSearchMode);
00548               }
00549        }
00550 }
00551 
00552 
00553 
00554 InternetSearchDataSource::~InternetSearchDataSource (void)
00555 {
00556        if (--gRefCnt == 0)
00557        {
00558               NS_IF_RELEASE(kNC_SearchResult);
00559               NS_IF_RELEASE(kNC_SearchEngineRoot);
00560               NS_IF_RELEASE(kNC_LastSearchRoot);
00561               NS_IF_RELEASE(kNC_LastSearchMode);
00562               NS_IF_RELEASE(kNC_SearchCategoryRoot);
00563               NS_IF_RELEASE(kNC_SearchResultsSitesRoot);
00564               NS_IF_RELEASE(kNC_FilterSearchURLsRoot);
00565               NS_IF_RELEASE(kNC_FilterSearchSitesRoot);
00566               NS_IF_RELEASE(kNC_SearchType);
00567               NS_IF_RELEASE(kNC_Ref);
00568               NS_IF_RELEASE(kNC_Child);
00569               NS_IF_RELEASE(kNC_Title);
00570               NS_IF_RELEASE(kNC_Data);
00571               NS_IF_RELEASE(kNC_Name);
00572               NS_IF_RELEASE(kNC_Description);
00573               NS_IF_RELEASE(kNC_Version);
00574               NS_IF_RELEASE(kNC_actionButton);
00575               NS_IF_RELEASE(kNC_actionBar);
00576               NS_IF_RELEASE(kNC_searchForm);
00577               NS_IF_RELEASE(kNC_LastText);
00578               NS_IF_RELEASE(kNC_URL);
00579               NS_IF_RELEASE(kRDF_InstanceOf);
00580               NS_IF_RELEASE(kRDF_type);
00581               NS_IF_RELEASE(kNC_loading);
00582               NS_IF_RELEASE(kNC_HTML);
00583               NS_IF_RELEASE(kNC_Icon);
00584               NS_IF_RELEASE(kNC_StatusIcon);
00585               NS_IF_RELEASE(kNC_Banner);
00586               NS_IF_RELEASE(kNC_Site);
00587               NS_IF_RELEASE(kNC_Relevance);
00588               NS_IF_RELEASE(kNC_RelevanceSort);
00589               NS_IF_RELEASE(kNC_Date);
00590               NS_IF_RELEASE(kNC_PageRank);
00591               NS_IF_RELEASE(kNC_Engine);
00592               NS_IF_RELEASE(kNC_Price);
00593               NS_IF_RELEASE(kNC_PriceSort);
00594               NS_IF_RELEASE(kNC_Availability);
00595               NS_IF_RELEASE(kNC_BookmarkSeparator);
00596               NS_IF_RELEASE(kNC_Update);
00597               NS_IF_RELEASE(kNC_UpdateIcon);
00598               NS_IF_RELEASE(kNC_UpdateCheckDays);
00599               NS_IF_RELEASE(kWEB_LastPingDate);
00600               NS_IF_RELEASE(kWEB_LastPingModDate);
00601               NS_IF_RELEASE(kWEB_LastPingContentLen);
00602 
00603               NS_IF_RELEASE(kNC_SearchCommand_AddToBookmarks);
00604               NS_IF_RELEASE(kNC_SearchCommand_AddQueryToBookmarks);
00605               NS_IF_RELEASE(kNC_SearchCommand_FilterResult);
00606               NS_IF_RELEASE(kNC_SearchCommand_FilterSite);
00607               NS_IF_RELEASE(kNC_SearchCommand_ClearFilters);
00608 
00609               NS_IF_RELEASE(kTrueLiteral);
00610 
00611               NS_IF_RELEASE(mInner);
00612 
00613               mUpdateArray = nsnull;
00614               mLocalstore = nsnull;
00615               mBackgroundLoadGroup = nsnull;
00616               mLoadGroup = nsnull;
00617               categoryDataSource = nsnull;              
00618 
00619               if (mTimer)
00620               {
00621                      // be sure to cancel the timer, as it holds a
00622                      // weak reference back to InternetSearchDataSource
00623                      mTimer->Cancel();
00624                      mTimer = nsnull;
00625               }
00626 
00627               if (prefs)
00628               {
00629                      prefs->UnregisterCallback("browser.search.mode", searchModePrefCallback, this);
00630                      prefs = nsnull;
00631               }
00632 
00633     NS_IF_RELEASE(gRDFC);
00634 
00635               if (gRDFService)
00636               {
00637                      gRDFService->UnregisterDataSource(this);
00638       NS_RELEASE(gRDFService);
00639               }
00640        }
00641 }
00642 
00643 
00644 
00645 nsresult
00646 InternetSearchDataSource::GetSearchEngineToPing(nsIRDFResource **theEngine, nsCString &updateURL)
00647 {
00648        nsresult      rv = NS_OK;
00649 
00650        *theEngine = nsnull;
00651        updateURL.Truncate();
00652 
00653        if (!mUpdateArray)   return(NS_OK);
00654 
00655        PRUint32      numEngines = 0;
00656        if (NS_FAILED(rv = mUpdateArray->Count(&numEngines)))   return(rv);
00657        if (numEngines < 1)  return(NS_OK);
00658 
00659        nsCOMPtr<nsIRDFResource> aRes (do_QueryElementAt(mUpdateArray, 0));
00660 
00661        // note: important to remove element from array
00662        mUpdateArray->RemoveElementAt(0);
00663 
00664        if (aRes)
00665        {
00666               if (isSearchCategoryEngineURI(aRes))
00667               {
00668                      nsCOMPtr<nsIRDFResource>    trueEngine;
00669                      rv = resolveSearchCategoryEngineURI(aRes, getter_AddRefs(trueEngine));
00670                      if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
00671                      if (!trueEngine)     return(NS_RDF_NO_VALUE);
00672 
00673                      aRes = trueEngine;
00674               }
00675 
00676               if (!aRes)    return(NS_OK);
00677 
00678               *theEngine = aRes.get();
00679               NS_ADDREF(*theEngine);
00680 
00681               // get update URL
00682               nsCOMPtr<nsIRDFNode> aNode;
00683               if (NS_SUCCEEDED(rv = mInner->GetTarget(aRes, kNC_Update, PR_TRUE, getter_AddRefs(aNode)))
00684                             && (rv != NS_RDF_NO_VALUE))
00685               {
00686                      nsCOMPtr<nsIRDFLiteral>     aLiteral (do_QueryInterface(aNode));
00687                      if (aLiteral)
00688                      {
00689                             const PRUnichar      *updateUni = nsnull;
00690                             aLiteral->GetValueConst(&updateUni);
00691                             if (updateUni)
00692                             {
00693                                    updateURL.AssignWithConversion(updateUni);
00694                             }
00695                      }
00696               }
00697        }
00698        return(rv);
00699 }
00700 
00701 
00702 
00703 void
00704 InternetSearchDataSource::FireTimer(nsITimer* aTimer, void* aClosure)
00705 {
00706        InternetSearchDataSource *search = NS_STATIC_CAST(InternetSearchDataSource *, aClosure);
00707        if (!search)  return;
00708 
00709   if (!search->busySchedule)
00710        {
00711               nsresult                    rv;
00712               nsCOMPtr<nsIRDFResource>    searchURI;
00713               nsCAutoString               updateURL;
00714               if (NS_FAILED(rv = search->GetSearchEngineToPing(getter_AddRefs(searchURI), updateURL)))
00715                      return;
00716               if (!searchURI)                    return;
00717               if (updateURL.IsEmpty())    return;
00718 
00719               search->busyResource = searchURI;
00720 
00721               nsCOMPtr<nsIInternetSearchContext> engineContext;
00722               if (NS_FAILED(rv = NS_NewInternetSearchContext(nsIInternetSearchContext::ENGINE_UPDATE_HEAD_CONTEXT,
00723                      nsnull, searchURI, nsnull, nsnull, getter_AddRefs(engineContext))))
00724                      return;
00725               if (!engineContext)  return;
00726 
00727               nsCOMPtr<nsIURI>     uri;
00728               if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(uri), updateURL.get())))  return;
00729 
00730               nsCOMPtr<nsIChannel> channel;
00731               if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull)))     return;
00732 
00733               channel->SetLoadFlags(nsIRequest::VALIDATE_ALWAYS);
00734 
00735               nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface(channel));
00736               if (!httpChannel)    return;
00737 
00738               // rjc says: just check "HEAD" info for whether a search file has changed
00739         httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD"));
00740               if (NS_SUCCEEDED(rv = channel->AsyncOpen(search, engineContext)))
00741               {
00742                      search->busySchedule = PR_TRUE;
00743 
00744 #ifdef DEBUG_SEARCH_UPDATES
00745                      printf("    InternetSearchDataSource::FireTimer - Pinging '%s'\n", (char *)updateURL.get());
00746 #endif
00747               }
00748        }
00749 #ifdef DEBUG_SEARCH_UPDATES
00750 else
00751        {
00752        printf("    InternetSearchDataSource::FireTimer - busy pinging.\n");
00753        }
00754 #endif
00755 }
00756 
00757 
00758 
00759 PRBool
00760 InternetSearchDataSource::isEngineURI(nsIRDFResource *r)
00761 {
00762        PRBool        isEngineURIFlag = PR_FALSE;
00763        const char    *uri = nsnull;
00764        
00765        r->GetValueConst(&uri);
00766        if ((uri) && (!strncmp(uri, kEngineProtocol, sizeof(kEngineProtocol) - 1)))
00767        {
00768               isEngineURIFlag = PR_TRUE;
00769        }
00770        return(isEngineURIFlag);
00771 }
00772 
00773 
00774 
00775 PRBool
00776 InternetSearchDataSource::isSearchURI(nsIRDFResource *r)
00777 {
00778        PRBool        isSearchURIFlag = PR_FALSE;
00779        const char    *uri = nsnull;
00780        
00781        r->GetValueConst(&uri);
00782        if ((uri) && (!strncmp(uri, kSearchProtocol, sizeof(kSearchProtocol) - 1)))
00783        {
00784               isSearchURIFlag = PR_TRUE;
00785        }
00786        return(isSearchURIFlag);
00787 }
00788 
00789 
00790 
00791 PRBool
00792 InternetSearchDataSource::isSearchCategoryURI(nsIRDFResource *r)
00793 {
00794        PRBool        isSearchCategoryURIFlag = PR_FALSE;
00795        const char    *uri = nsnull;
00796        
00797        r->GetValueConst(&uri);
00798        if ((uri) && (!strncmp(uri, kURINC_SearchCategoryPrefix, sizeof(kURINC_SearchCategoryPrefix) - 1)))
00799        {
00800               isSearchCategoryURIFlag = PR_TRUE;
00801        }
00802        return(isSearchCategoryURIFlag);
00803 }
00804 
00805 
00806 
00807 PRBool
00808 InternetSearchDataSource::isSearchCategoryEngineURI(nsIRDFResource *r)
00809 {
00810        PRBool        isSearchCategoryEngineURIFlag = PR_FALSE;
00811        const char    *uri = nsnull;
00812        
00813        r->GetValueConst(&uri);
00814        if ((uri) && (!strncmp(uri, kURINC_SearchCategoryEnginePrefix, sizeof(kURINC_SearchCategoryEnginePrefix) - 1)))
00815        {
00816               isSearchCategoryEngineURIFlag = PR_TRUE;
00817        }
00818        return(isSearchCategoryEngineURIFlag);
00819 }
00820 
00821 
00822 
00823 PRBool
00824 InternetSearchDataSource::isSearchCategoryEngineBasenameURI(nsIRDFNode *r)
00825 {
00826        PRBool        isSearchCategoryEngineBasenameURIFlag = PR_FALSE;
00827 
00828        nsCOMPtr<nsIRDFResource> aRes (do_QueryInterface(r));
00829        if (aRes)
00830        {
00831               const char    *uri = nsnull;
00832               aRes->GetValueConst(&uri);
00833               if ((uri) && (!nsCRT::strncmp(uri, kURINC_SearchCategoryEngineBasenamePrefix,
00834                      (int)sizeof(kURINC_SearchCategoryEngineBasenamePrefix) - 1)))
00835               {
00836                      isSearchCategoryEngineBasenameURIFlag = PR_TRUE;
00837               }
00838        }
00839        else
00840        {
00841               nsCOMPtr<nsIRDFLiteral>     aLit (do_QueryInterface(r));
00842               if (aLit)
00843               {
00844                      const  PRUnichar     *uriUni = nsnull;
00845                      aLit->GetValueConst(&uriUni);
00846                      if ((uriUni) && (!nsCRT::strncmp(uriUni,
00847                                                   NS_ConvertASCIItoUCS2(kURINC_SearchCategoryEngineBasenamePrefix).get(),
00848                             (int)sizeof(kURINC_SearchCategoryEngineBasenamePrefix) - 1)))
00849                      {
00850                             isSearchCategoryEngineBasenameURIFlag = PR_TRUE;
00851                      }
00852               }
00853        }
00854        return(isSearchCategoryEngineBasenameURIFlag);
00855 }
00856 
00857 
00858 
00859 PRBool
00860 InternetSearchDataSource::isSearchCommand(nsIRDFResource *r)
00861 {
00862        PRBool        isSearchCommandFlag = PR_FALSE;
00863        const char    *uri = nsnull;
00864        
00865        if (NS_SUCCEEDED(r->GetValueConst( &uri )) && (uri))
00866        {
00867               if (!strncmp(uri, kSearchCommand, sizeof(kSearchCommand) - 1))
00868               {
00869                      isSearchCommandFlag = PR_TRUE;
00870               }
00871        }
00872        return(isSearchCommandFlag);
00873 }
00874 
00875 
00876 
00877 nsresult
00878 InternetSearchDataSource::resolveSearchCategoryEngineURI(nsIRDFResource *engine, nsIRDFResource **trueEngine)
00879 {
00880        *trueEngine = nsnull;
00881 
00882        if ((!categoryDataSource) || (!mInner))   return(NS_ERROR_UNEXPECTED);
00883 
00884        nsresult      rv;
00885        const char    *uriUni = nsnull;
00886        if (NS_FAILED(rv = engine->GetValueConst(&uriUni)))     return(rv);
00887        if (!uriUni)  return(NS_ERROR_NULL_POINTER);
00888 
00889        nsAutoString         uri;
00890        uri.AssignWithConversion(uriUni);
00891        if (uri.Find(kURINC_SearchCategoryEngineBasenamePrefix) !=0)   return(NS_ERROR_UNEXPECTED);
00892 
00893        nsCOMPtr<nsIRDFLiteral>     basenameLiteral;
00894        if (NS_FAILED(rv = gRDFService->GetLiteral(uri.get(),
00895                      getter_AddRefs(basenameLiteral)))) return(rv);
00896 
00897        nsCOMPtr<nsIRDFResource>    catSrc;
00898        rv = mInner->GetSource(kNC_URL, basenameLiteral, PR_TRUE, getter_AddRefs(catSrc));
00899        if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
00900        if (!catSrc)         return(NS_ERROR_UNEXPECTED);
00901 
00902        *trueEngine = catSrc;
00903        NS_IF_ADDREF(*trueEngine);
00904        return(NS_OK);
00905 }
00906 
00907 
00908 
00910 
00911 NS_IMPL_ADDREF(InternetSearchDataSource)
00912 NS_IMPL_RELEASE(InternetSearchDataSource)
00913 
00914 NS_INTERFACE_MAP_BEGIN(InternetSearchDataSource)
00915    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInternetSearchService)
00916    NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
00917    NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
00918    NS_INTERFACE_MAP_ENTRY(nsIInternetSearchService)
00919    NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
00920    NS_INTERFACE_MAP_ENTRY(nsIObserver)
00921    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00922 NS_INTERFACE_MAP_END
00923 
00924 
00925 NS_METHOD
00926 InternetSearchDataSource::Init()
00927 {
00928        nsresult      rv = NS_ERROR_OUT_OF_MEMORY;
00929 
00930        if (NS_FAILED(rv = CallCreateInstance(kRDFInMemoryDataSourceCID, &mInner)))
00931               return(rv);
00932 
00933        // get localstore, as we'll be using it
00934        if (NS_FAILED(rv = gRDFService->GetDataSource("rdf:local-store", getter_AddRefs(mLocalstore))))
00935               return(rv);
00936 
00937        if (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(mUpdateArray))))
00938               return(rv);
00939 
00940        // register this as a named data source with the service manager
00941        if (NS_FAILED(rv = gRDFService->RegisterDataSource(this, PR_FALSE)))
00942               return(rv);
00943 
00944        rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull);
00945        NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create load group");
00946 
00947        if (!mTimer)
00948        {
00949               busySchedule = PR_FALSE;
00950               mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
00951               if (mTimer)
00952               {
00953                      mTimer->InitWithFuncCallback(InternetSearchDataSource::FireTimer, this,
00954                                                      SEARCH_UPDATE_TIMEOUT, nsITimer::TYPE_REPEATING_SLACK);
00955                      // Note: don't addref "this" as we'll cancel the timer in the
00956                      //       InternetSearchDataSource destructor
00957               }
00958        }
00959 
00960        gEngineListBuilt = PR_FALSE;
00961 
00962        // Register as a profile change obsevrer
00963   nsCOMPtr<nsIObserverService> observerService = 
00964            do_GetService("@mozilla.org/observer-service;1", &rv);
00965   if (observerService) {
00966     observerService->AddObserver(this, "profile-before-change", PR_TRUE);
00967     observerService->AddObserver(this, "profile-do-change", PR_TRUE);
00968   }
00969 
00970        return(rv);
00971 }
00972 
00973 void
00974 InternetSearchDataSource::DeferredInit()
00975 {
00976   if (gEngineListBuilt)
00977     return;
00978 
00979   nsresult rv;
00980 
00981   nsCOMPtr<nsIProperties> dirSvc
00982     (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
00983   if (!dirSvc)
00984     return;
00985 
00986   gEngineListBuilt = PR_TRUE;
00987 
00988   // get available search engines
00989   nsCOMPtr<nsISimpleEnumerator> dirlist;
00990   rv = dirSvc->Get(NS_APP_SEARCH_DIR_LIST,
00991                    NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirlist));
00992   if (NS_SUCCEEDED(rv))
00993   {
00994     PRBool more;
00995     while (NS_SUCCEEDED(dirlist->HasMoreElements(&more)) && more) {
00996       nsCOMPtr<nsISupports> suppfile;
00997       nsCOMPtr<nsIFile> dir;
00998       dirlist->GetNext(getter_AddRefs(suppfile));
00999       dir = do_QueryInterface(suppfile);
01000       if (dir)
01001       {
01002         GetSearchEngineList(dir, PR_FALSE);
01003       }
01004     }
01005   }
01006 
01007   // read in category list
01008   GetCategoryList();
01009 }
01010 
01011 NS_IMETHODIMP
01012 InternetSearchDataSource::GetURI(char **uri)
01013 {
01014        NS_PRECONDITION(uri != nsnull, "null ptr");
01015        if (! uri)
01016               return NS_ERROR_NULL_POINTER;
01017 
01018        if ((*uri = nsCRT::strdup("rdf:internetsearch")) == nsnull)
01019               return NS_ERROR_OUT_OF_MEMORY;
01020 
01021        return NS_OK;
01022 }
01023 
01024 
01025 
01026 NS_IMETHODIMP
01027 InternetSearchDataSource::GetSource(nsIRDFResource* property,
01028                                 nsIRDFNode* target,
01029                                 PRBool tv,
01030                                 nsIRDFResource** source /* out */)
01031 {
01032        NS_PRECONDITION(property != nsnull, "null ptr");
01033        if (! property)
01034               return NS_ERROR_NULL_POINTER;
01035 
01036        NS_PRECONDITION(target != nsnull, "null ptr");
01037        if (! target)
01038               return NS_ERROR_NULL_POINTER;
01039 
01040        NS_PRECONDITION(source != nsnull, "null ptr");
01041        if (! source)
01042               return NS_ERROR_NULL_POINTER;
01043 
01044        *source = nsnull;
01045        return NS_RDF_NO_VALUE;
01046 }
01047 
01048 
01049 
01050 NS_IMETHODIMP
01051 InternetSearchDataSource::GetSources(nsIRDFResource *property,
01052                                  nsIRDFNode *target,
01053                                  PRBool tv,
01054                                  nsISimpleEnumerator **sources /* out */)
01055 {
01056        nsresult      rv = NS_RDF_NO_VALUE;
01057 
01058        if (mInner)
01059        {
01060               rv = mInner->GetSources(property, target, tv, sources);
01061        }
01062        else
01063        {
01064               rv = NS_NewEmptyEnumerator(sources);
01065        }
01066        return(rv);
01067 }
01068 
01069 
01070 
01071 NS_IMETHODIMP
01072 InternetSearchDataSource::GetTarget(nsIRDFResource *source,
01073                                 nsIRDFResource *property,
01074                                 PRBool tv,
01075                                 nsIRDFNode **target /* out */)
01076 {
01077        NS_PRECONDITION(source != nsnull, "null ptr");
01078        if (! source)
01079               return NS_ERROR_NULL_POINTER;
01080 
01081        NS_PRECONDITION(property != nsnull, "null ptr");
01082        if (! property)
01083               return NS_ERROR_NULL_POINTER;
01084 
01085        NS_PRECONDITION(target != nsnull, "null ptr");
01086        if (! target)
01087               return NS_ERROR_NULL_POINTER;
01088 
01089        *target = nsnull;
01090 
01091        nsresult             rv = NS_RDF_NO_VALUE;
01092 
01093        // we only have positive assertions in the internet search data source.
01094        if (! tv)
01095               return(rv);
01096 
01097        if ((isSearchCategoryURI(source)) && (categoryDataSource))
01098        {
01099               const char    *uri = nsnull;
01100               source->GetValueConst(&uri);
01101               if (!uri)     return(NS_ERROR_UNEXPECTED);
01102               nsAutoString  catURI;
01103               catURI.AssignWithConversion(uri);
01104 
01105               nsCOMPtr<nsIRDFResource>    category;
01106               nsCAutoString               caturiC;
01107               caturiC.AssignWithConversion(catURI);
01108               if (NS_FAILED(rv = gRDFService->GetResource(caturiC,
01109                      getter_AddRefs(category))))
01110                      return(rv);
01111 
01112               rv = categoryDataSource->GetTarget(category, property, tv, target);
01113               return(rv);
01114        }
01115 
01116        if (isSearchCategoryEngineURI(source))
01117        {
01118               nsCOMPtr<nsIRDFResource>    trueEngine;
01119               rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine));
01120               if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
01121               if (!trueEngine)     return(NS_RDF_NO_VALUE);
01122 
01123               source = trueEngine;
01124        }
01125 
01126        if (isSearchURI(source) && (property == kNC_Child))
01127        {
01128               // fake out the generic builder (i.e. return anything in this case)
01129               // so that search containers never appear to be empty
01130               *target = source;
01131               NS_ADDREF(source);
01132               return(NS_OK);
01133        }
01134 
01135        if (isSearchCommand(source) && (property == kNC_Name))
01136        {
01137     nsresult rv;
01138     nsCOMPtr<nsIStringBundleService>
01139     stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
01140 
01141     if (NS_SUCCEEDED(rv) && stringService) {
01142 
01143       nsCOMPtr<nsIStringBundle> bundle;
01144       rv = stringService->CreateBundle(SEARCH_PROPERTIES, getter_AddRefs(bundle));
01145       if (NS_SUCCEEDED(rv) && bundle) {
01146 
01147         nsXPIDLString valUni;
01148         nsAutoString name;
01149 
01150         if (source == kNC_SearchCommand_AddToBookmarks)
01151           name.AssignLiteral("addtobookmarks");
01152         else if (source == kNC_SearchCommand_AddQueryToBookmarks)
01153           name.AssignLiteral("addquerytobookmarks");
01154         else if (source == kNC_SearchCommand_FilterResult)
01155           name.AssignLiteral("excludeurl");
01156         else if (source == kNC_SearchCommand_FilterSite)
01157           name.AssignLiteral("excludedomain");
01158         else if (source == kNC_SearchCommand_ClearFilters)
01159           name.AssignLiteral("clearfilters");
01160 
01161         rv = bundle->GetStringFromName(name.get(), getter_Copies(valUni));
01162         if (NS_SUCCEEDED(rv) && valUni && *valUni) {
01163           *target = nsnull;
01164           nsCOMPtr<nsIRDFLiteral> literal;
01165           if (NS_FAILED(rv = gRDFService->GetLiteral(valUni, getter_AddRefs(literal))))
01166             return rv;
01167           *target = literal;
01168           NS_IF_ADDREF(*target);
01169           return rv;
01170         }
01171       }
01172     }
01173   }
01174 
01175        if (isEngineURI(source))
01176        {
01177               // if we're asking for info on a search engine, (deferred) load it if needed
01178               nsCOMPtr<nsIRDFLiteral>     dataLit;
01179               FindData(source, getter_AddRefs(dataLit));
01180        }
01181 
01182        if (mInner)
01183        {
01184               rv = mInner->GetTarget(source, property, tv, target);
01185        }
01186 
01187        return(rv);
01188 }
01189 
01190 #ifdef MOZ_PHOENIX
01191 void
01192 InternetSearchDataSource::ReorderEngineList()
01193 {
01194   // XXXben - a temporary, inelegant solution to search list ordering until 
01195   //          after 1.0 when we replace all of this with something better 
01196   //          suited to our needs. 
01197   nsresult rv;
01198   nsCOMArray<nsIRDFResource> engineList;
01199 
01200   // Load all data for sherlock files...
01201   nsCOMPtr<nsISimpleEnumerator> engines;
01202   rv = GetTargets(kNC_SearchEngineRoot, kNC_Child, PR_TRUE, getter_AddRefs(engines));
01203   if (NS_FAILED(rv)) return; // Not Fatal. 
01204 
01205   do {
01206     PRBool hasMore;
01207     engines->HasMoreElements(&hasMore);
01208     if (!hasMore)
01209       break;
01210 
01211     nsCOMPtr<nsISupports> supp;
01212     engines->GetNext(getter_AddRefs(supp));
01213     nsCOMPtr<nsIRDFResource> engineResource(do_QueryInterface(supp));
01214 
01215     nsCOMPtr<nsIRDFLiteral> data;
01216     FindData(engineResource, getter_AddRefs(data));
01217   }
01218   while (PR_TRUE);
01219 
01220   // Build the ordered items first...
01221   nsCOMPtr<nsIPrefBranch> pserv(do_QueryInterface(prefs));
01222   char prefNameBuf[1096];
01223   PRInt32 i = 0; 
01224   do {
01225     ++i;
01226     sprintf(prefNameBuf, "browser.search.order.%d", i);
01227 
01228     nsCOMPtr<nsIPrefLocalizedString> engineName;
01229     rv = pserv->GetComplexValue(prefNameBuf, 
01230                                 NS_GET_IID(nsIPrefLocalizedString),
01231                                 getter_AddRefs(engineName));
01232     if (NS_FAILED(rv)) break;
01233 
01234     nsXPIDLString data;
01235     engineName->GetData(getter_Copies(data));
01236 
01237     nsCOMPtr<nsIRDFLiteral> engineNameLiteral;
01238     gRDFService->GetLiteral(data, getter_AddRefs(engineNameLiteral));
01239 
01240     nsCOMPtr<nsIRDFResource> engineResource;
01241     rv = mInner->GetSource(kNC_Name, engineNameLiteral, PR_TRUE, getter_AddRefs(engineResource));
01242     if (NS_FAILED(rv)) continue;
01243 
01244     engineList.AppendObject(engineResource);
01245   }
01246   while (PR_TRUE);
01247 
01248   // Now add the rest...
01249   rv = GetTargets(kNC_SearchEngineRoot, kNC_Child, PR_TRUE, getter_AddRefs(engines));
01250   if (NS_FAILED(rv)) return; // Not Fatal. 
01251 
01252   do {
01253     PRBool hasMore;
01254     engines->HasMoreElements(&hasMore);
01255     if (!hasMore)
01256       break;
01257 
01258     nsCOMPtr<nsISupports> supp;
01259     engines->GetNext(getter_AddRefs(supp));
01260     nsCOMPtr<nsIRDFResource> engineResource(do_QueryInterface(supp));
01261 
01262     if (engineList.IndexOfObject(engineResource) == -1) 
01263       engineList.AppendObject(engineResource);
01264 
01265     // Unhook the item from the list, so we can rebuild it in the right
01266     // order. Failures are benign.
01267     Unassert(kNC_SearchEngineRoot, kNC_Child, engineResource);
01268   }
01269   while (PR_TRUE);
01270 
01271   PRInt32 engineCount = engineList.Count();
01272   for (i = 0; i < engineCount; ++i)
01273     Assert(kNC_SearchEngineRoot, kNC_Child, engineList[i], PR_TRUE);
01274 
01275   gReorderedEngineList = PR_TRUE;
01276 }
01277 #endif
01278 
01279 NS_IMETHODIMP
01280 InternetSearchDataSource::GetTargets(nsIRDFResource *source,
01281                            nsIRDFResource *property,
01282                            PRBool tv,
01283                            nsISimpleEnumerator **targets /* out */)
01284 {
01285        NS_PRECONDITION(source != nsnull, "null ptr");
01286        if (! source)
01287               return NS_ERROR_NULL_POINTER;
01288 
01289        NS_PRECONDITION(property != nsnull, "null ptr");
01290        if (! property)
01291               return NS_ERROR_NULL_POINTER;
01292 
01293        NS_PRECONDITION(targets != nsnull, "null ptr");
01294        if (! targets)
01295               return NS_ERROR_NULL_POINTER;
01296 
01297        nsresult rv = NS_RDF_NO_VALUE;
01298 
01299        // we only have positive assertions in the internet search data source.
01300        if (! tv)
01301               return(rv);
01302 
01303        if ((isSearchCategoryURI(source)) && (categoryDataSource))
01304        {
01305               const char    *uri = nsnull;
01306               source->GetValueConst(&uri);
01307               if (!uri)     return(NS_ERROR_UNEXPECTED);
01308               nsAutoString  catURI;
01309               catURI.AssignWithConversion(uri);
01310 
01311               nsCOMPtr<nsIRDFResource>    category;
01312               nsCAutoString               caturiC;
01313               caturiC.AssignWithConversion(catURI);
01314               if (NS_FAILED(rv = gRDFService->GetResource(caturiC,
01315                      getter_AddRefs(category))))
01316                      return(rv);
01317 
01318               rv = categoryDataSource->GetTargets(category, property, tv, targets);
01319               return(rv);
01320        }
01321 
01322        if (isSearchCategoryEngineURI(source))
01323        {
01324               nsCOMPtr<nsIRDFResource>    trueEngine;
01325               rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine));
01326               if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
01327               if (!trueEngine)     return(NS_RDF_NO_VALUE);
01328 
01329               source = trueEngine;
01330        }
01331 
01332        if (mInner)
01333        {      
01334               // defer search engine discovery until needed; small startup time improvement
01335     if ((source == kNC_SearchEngineRoot || isSearchURI(source)) &&
01336         property == kNC_Child && !gEngineListBuilt)
01337               {
01338                      DeferredInit();
01339               }
01340 
01341     rv = mInner->GetTargets(source, property, tv, targets);
01342        }
01343        if (isSearchURI(source))
01344        {
01345               if (property == kNC_Child)
01346               {
01347                      PRBool        doNetworkRequest = PR_TRUE;
01348                      if (NS_SUCCEEDED(rv) && (targets))
01349                      {
01350                             // check and see if we already have data for the search in question;
01351                             // if we do, BeginSearchRequest() won't bother doing the search again,
01352                             // otherwise it will kickstart it
01353                             PRBool        hasResults = PR_FALSE;
01354         if (NS_SUCCEEDED((*targets)->HasMoreElements(&hasResults)) &&
01355             hasResults)
01356                             {
01357                                    doNetworkRequest = PR_FALSE;
01358                             }
01359                      }
01360                      BeginSearchRequest(source, doNetworkRequest);
01361               }
01362        }
01363        return(rv);
01364 }
01365 
01366 
01367 
01368 nsresult
01369 InternetSearchDataSource::GetCategoryList()
01370 {
01371        nsIRDFDataSource     *ds;
01372        nsresult rv = CallCreateInstance(kRDFXMLDataSourceCID, &ds);
01373        if (NS_FAILED(rv))   return(rv);
01374        if (!ds)             return(NS_ERROR_UNEXPECTED);
01375 
01376        categoryDataSource = do_QueryInterface(ds);
01377        NS_RELEASE(ds);
01378        ds = nsnull;
01379        if (!categoryDataSource)    return(NS_ERROR_UNEXPECTED);
01380 
01381        nsCOMPtr<nsIRDFRemoteDataSource> remoteCategoryDataSource (do_QueryInterface(categoryDataSource));
01382        if (!remoteCategoryDataSource)     return(NS_ERROR_UNEXPECTED);
01383 
01384        // get search.rdf
01385               
01386   nsCOMPtr<nsIFile> searchFile;
01387   nsCAutoString searchFileURLSpec;
01388 
01389   rv = NS_GetSpecialDirectory(NS_APP_SEARCH_50_FILE, getter_AddRefs(searchFile));
01390   if (NS_FAILED(rv)) return rv;
01391   NS_GetURLSpecFromFile(searchFile, searchFileURLSpec);
01392   if (NS_FAILED(rv)) return rv;
01393        rv = remoteCategoryDataSource->Init(searchFileURLSpec.get());
01394   if (NS_FAILED(rv)) return rv;
01395     
01396        // synchronous read
01397        rv = remoteCategoryDataSource->Refresh(PR_TRUE);
01398        if (NS_FAILED(rv))   return(rv);
01399 
01400        // ensure that all search engine references actually exist; if not, forget about them
01401 
01402        PRBool                      isDirtyFlag = PR_FALSE;
01403        nsCOMPtr<nsIRDFContainer>   categoryRoot;
01404        rv = gRDFC->MakeSeq(categoryDataSource, kNC_SearchCategoryRoot, getter_AddRefs(categoryRoot));
01405        if (NS_FAILED(rv))   return(rv);
01406        if (!categoryRoot)   return(NS_ERROR_UNEXPECTED);
01407 
01408        rv = categoryRoot->Init(categoryDataSource, kNC_SearchCategoryRoot);
01409        if (NS_FAILED(rv))   return(rv);
01410 
01411        PRInt32              numCategories = 0;
01412        rv = categoryRoot->GetCount(&numCategories);
01413        if (NS_FAILED(rv))   return(rv);
01414 
01415        // Note: one-based
01416        for (PRInt32 catLoop=1; catLoop <= numCategories; catLoop++)
01417        {
01418               nsCOMPtr<nsIRDFResource>    aCategoryOrdinal;
01419               rv = gRDFC->IndexToOrdinalResource(catLoop,
01420                      getter_AddRefs(aCategoryOrdinal));
01421               if (NS_FAILED(rv))   break;
01422               if (!aCategoryOrdinal)      break;
01423 
01424               nsCOMPtr<nsIRDFNode>        aCategoryNode;
01425               rv = categoryDataSource->GetTarget(kNC_SearchCategoryRoot, aCategoryOrdinal,
01426                      PR_TRUE, getter_AddRefs(aCategoryNode));
01427               if (NS_FAILED(rv))   break;
01428               nsCOMPtr<nsIRDFResource> aCategoryRes (do_QueryInterface(aCategoryNode));
01429               if (!aCategoryRes)   break;
01430               const  char                 *catResURI = nsnull;
01431               aCategoryRes->GetValueConst(&catResURI);
01432               if (!catResURI)             break;
01433               nsAutoString         categoryStr;
01434               categoryStr.AssignWithConversion(kURINC_SearchCategoryPrefix);
01435               categoryStr.AppendWithConversion(catResURI);
01436 
01437               nsCOMPtr<nsIRDFResource>    searchCategoryRes;
01438               if (NS_FAILED(rv = gRDFService->GetUnicodeResource(categoryStr,
01439                      getter_AddRefs(searchCategoryRes))))      break;
01440 
01441               nsCOMPtr<nsIRDFContainer> categoryContainer;
01442               rv = gRDFC->MakeSeq(categoryDataSource, searchCategoryRes,
01443                      getter_AddRefs(categoryContainer));
01444               if (NS_FAILED(rv))   continue;
01445 
01446               rv = categoryContainer->Init(categoryDataSource, searchCategoryRes);
01447               if (NS_FAILED(rv))   return(rv);
01448 
01449               PRInt32              numEngines = 0;
01450               rv = categoryContainer->GetCount(&numEngines);
01451               if (NS_FAILED(rv))   break;
01452 
01453               // Note: one-based, and loop backwards as we might be removing entries
01454               for (PRInt32 engineLoop=numEngines; engineLoop >= 1; engineLoop--)
01455               {
01456                      nsCOMPtr<nsIRDFResource>    aEngineOrdinal;
01457                      rv = gRDFC->IndexToOrdinalResource(engineLoop,
01458                             getter_AddRefs(aEngineOrdinal));
01459                      if (NS_FAILED(rv))   break;
01460                      if (!aEngineOrdinal) break;
01461 
01462                      nsCOMPtr<nsIRDFNode>        aEngineNode;
01463                      rv = categoryDataSource->GetTarget(searchCategoryRes, aEngineOrdinal,
01464                             PR_TRUE, getter_AddRefs(aEngineNode));
01465                      if (NS_FAILED(rv))   break;
01466                      nsCOMPtr<nsIRDFResource> aEngineRes (do_QueryInterface(aEngineNode));
01467                      if (!aEngineRes)     break;
01468 
01469                      if (isSearchCategoryEngineURI(aEngineRes))
01470                      {
01471                             nsCOMPtr<nsIRDFResource>    trueEngine;
01472                             rv = resolveSearchCategoryEngineURI(aEngineRes,
01473                                    getter_AddRefs(trueEngine));
01474                             if (NS_FAILED(rv) || (!trueEngine))
01475                             {
01476                                    // unable to resolve, so forget about this engine reference
01477 #ifdef DEBUG
01478                                    const  char          *catEngineURI = nsnull;
01479                                    aEngineRes->GetValueConst(&catEngineURI);
01480                                    if (catEngineURI)
01481                                    {
01482                                           printf("**** Stale search engine reference to '%s'\n",
01483                                                  catEngineURI);
01484                                    }
01485 #endif
01486                                    nsCOMPtr<nsIRDFNode> staleCatEngine;
01487                                    rv = categoryContainer->RemoveElementAt(engineLoop, PR_TRUE,
01488                                           getter_AddRefs(staleCatEngine));
01489                                    isDirtyFlag = PR_TRUE;
01490                             }
01491                      }
01492               }
01493        }
01494 
01495   if (isDirtyFlag)
01496        {
01497               if (remoteCategoryDataSource)
01498               {
01499                      remoteCategoryDataSource->Flush();
01500               }
01501        }
01502 
01503        return(rv);
01504 }
01505 
01506 
01507 
01508 NS_IMETHODIMP
01509 InternetSearchDataSource::Assert(nsIRDFResource *source,
01510                        nsIRDFResource *property,
01511                        nsIRDFNode *target,
01512                        PRBool tv)
01513 {
01514        nsresult      rv = NS_RDF_ASSERTION_REJECTED;
01515 
01516        // we only have positive assertions in the internet search data source.
01517        if (! tv)
01518               return(rv);
01519 
01520        if (mInner)
01521        {
01522               rv = mInner->Assert(source, property, target, tv);
01523        }
01524        return(rv);
01525 }
01526 
01527 
01528 
01529 NS_IMETHODIMP
01530 InternetSearchDataSource::Unassert(nsIRDFResource *source,
01531                          nsIRDFResource *property,
01532                          nsIRDFNode *target)
01533 {
01534        nsresult      rv = NS_RDF_ASSERTION_REJECTED;
01535 
01536        if (mInner)
01537        {
01538               rv = mInner->Unassert(source, property, target);
01539        }
01540        return(rv);
01541 }
01542 
01543 
01544 
01545 NS_IMETHODIMP
01546 InternetSearchDataSource::Change(nsIRDFResource *source,
01547                      nsIRDFResource *property,
01548                      nsIRDFNode *oldTarget,
01549                      nsIRDFNode *newTarget)
01550 {
01551        nsresult      rv = NS_RDF_ASSERTION_REJECTED;
01552 
01553        if (mInner)
01554        {
01555               rv = mInner->Change(source, property, oldTarget, newTarget);
01556        }
01557        return(rv);
01558 }
01559 
01560 
01561 
01562 NS_IMETHODIMP
01563 InternetSearchDataSource::Move(nsIRDFResource *oldSource,
01564                                       nsIRDFResource *newSource,
01565                                       nsIRDFResource *property,
01566                                       nsIRDFNode *target)
01567 {
01568        nsresult      rv = NS_RDF_ASSERTION_REJECTED;
01569 
01570        if (mInner)
01571        {
01572               rv = mInner->Move(oldSource, newSource, property, target);
01573        }
01574        return(rv);
01575 }
01576 
01577 
01578 
01579 NS_IMETHODIMP
01580 InternetSearchDataSource::HasAssertion(nsIRDFResource *source,
01581                              nsIRDFResource *property,
01582                              nsIRDFNode *target,
01583                              PRBool tv,
01584                              PRBool *hasAssertion /* out */)
01585 {
01586        NS_PRECONDITION(source != nsnull, "null ptr");
01587        if (! source)
01588               return NS_ERROR_NULL_POINTER;
01589 
01590        NS_PRECONDITION(property != nsnull, "null ptr");
01591        if (! property)
01592               return NS_ERROR_NULL_POINTER;
01593 
01594        NS_PRECONDITION(target != nsnull, "null ptr");
01595        if (! target)
01596               return NS_ERROR_NULL_POINTER;
01597 
01598        NS_PRECONDITION(hasAssertion != nsnull, "null ptr");
01599        if (! hasAssertion)
01600               return NS_ERROR_NULL_POINTER;
01601 
01602        *hasAssertion = PR_FALSE;
01603 
01604        // we only have positive assertions in the internet search data source.
01605        if (! tv)
01606        {
01607               return NS_OK;
01608         }
01609         nsresult     rv = NS_RDF_NO_VALUE;
01610         
01611         if (mInner)
01612         {
01613               rv = mInner->HasAssertion(source, property, target, tv, hasAssertion);
01614        }
01615         return(rv);
01616 }
01617 
01618 NS_IMETHODIMP 
01619 InternetSearchDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
01620 {
01621     if (mInner) {
01622        return mInner->HasArcIn(aNode, aArc, result);
01623     }
01624     else {
01625        *result = PR_FALSE;
01626     }
01627     return NS_OK;
01628 }
01629 
01630 NS_IMETHODIMP 
01631 InternetSearchDataSource::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, PRBool *result)
01632 {
01633     NS_PRECONDITION(source != nsnull, "null ptr");
01634     if (! source)
01635        return NS_ERROR_NULL_POINTER;
01636 
01637     nsresult rv;
01638 
01639     if ((source == kNC_SearchEngineRoot) || (source == kNC_LastSearchRoot) || isSearchURI(source))
01640     {
01641        *result = (aArc == kNC_Child);
01642        return NS_OK;
01643     }
01644 
01645     if ((isSearchCategoryURI(source)) && (categoryDataSource))
01646     {
01647        const char    *uri = nsnull;
01648        source->GetValueConst(&uri);
01649        if (!uri)     return(NS_ERROR_UNEXPECTED);
01650 
01651        nsCOMPtr<nsIRDFResource>    category;
01652        if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(uri),
01653                                               getter_AddRefs(category))))
01654            return(rv);
01655 
01656        return categoryDataSource->HasArcOut(source, aArc, result);
01657     }
01658 
01659     if (isSearchCategoryEngineURI(source))
01660     {
01661        nsCOMPtr<nsIRDFResource>    trueEngine;
01662        rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine));
01663        if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
01664        if (!trueEngine) {
01665            *result = PR_FALSE;
01666            return NS_OK;
01667        }
01668        source = trueEngine;
01669     }
01670 
01671     if (isEngineURI(source))
01672     {
01673        // if we're asking for info on a search engine, (deferred) load it if needed
01674        nsCOMPtr<nsIRDFLiteral>     dataLit;
01675        FindData(source, getter_AddRefs(dataLit));
01676     }
01677 
01678     if (mInner)
01679     {
01680        return mInner->HasArcOut(source, aArc, result);
01681     }
01682 
01683     *result = PR_FALSE;
01684     return NS_OK;
01685 }
01686 
01687 NS_IMETHODIMP
01688 InternetSearchDataSource::ArcLabelsIn(nsIRDFNode *node,
01689                             nsISimpleEnumerator ** labels /* out */)
01690 {
01691        nsresult      rv;
01692 
01693        if (mInner)
01694        {
01695               rv = mInner->ArcLabelsIn(node, labels);
01696               return(rv);
01697        }
01698        else
01699        {
01700               rv = NS_NewEmptyEnumerator(labels);
01701        }
01702        return(rv);
01703 }
01704 
01705 
01706 
01707 NS_IMETHODIMP
01708 InternetSearchDataSource::ArcLabelsOut(nsIRDFResource *source,
01709                              nsISimpleEnumerator **labels /* out */)
01710 {
01711        NS_PRECONDITION(source != nsnull, "null ptr");
01712        if (! source)
01713               return NS_ERROR_NULL_POINTER;
01714 
01715        NS_PRECONDITION(labels != nsnull, "null ptr");
01716        if (! labels)
01717               return NS_ERROR_NULL_POINTER;
01718 
01719        nsresult rv;
01720 
01721        if ((source == kNC_SearchEngineRoot) || (source == kNC_LastSearchRoot) || isSearchURI(source))
01722        {
01723             nsCOMPtr<nsISupportsArray> array;
01724             rv = NS_NewISupportsArray(getter_AddRefs(array));
01725             if (NS_FAILED(rv)) return rv;
01726 
01727             array->AppendElement(kNC_Child);
01728 
01729             nsISimpleEnumerator* result = new nsArrayEnumerator(array);
01730             if (! result)
01731                 return NS_ERROR_OUT_OF_MEMORY;
01732 
01733             NS_ADDREF(result);
01734             *labels = result;
01735             return(NS_OK);
01736        }
01737 
01738        if ((isSearchCategoryURI(source)) && (categoryDataSource))
01739        {
01740               const char    *uri = nsnull;
01741               source->GetValueConst(&uri);
01742               if (!uri)     return(NS_ERROR_UNEXPECTED);
01743 
01744               nsCOMPtr<nsIRDFResource>    category;
01745               if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(uri),
01746                      getter_AddRefs(category))))
01747                      return(rv);
01748 
01749               rv = categoryDataSource->ArcLabelsOut(category, labels);
01750               return(rv);
01751        }
01752 
01753        if (isSearchCategoryEngineURI(source))
01754        {
01755               nsCOMPtr<nsIRDFResource>    trueEngine;
01756               rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine));
01757               if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
01758               if (!trueEngine)     return(NS_RDF_NO_VALUE);
01759 
01760               source = trueEngine;
01761        }
01762 
01763        if (isEngineURI(source))
01764        {
01765               // if we're asking for info on a search engine, (deferred) load it if needed
01766               nsCOMPtr<nsIRDFLiteral>     dataLit;
01767               FindData(source, getter_AddRefs(dataLit));
01768        }
01769 
01770        if (mInner)
01771        {
01772               rv = mInner->ArcLabelsOut(source, labels);
01773               return(rv);
01774        }
01775 
01776        return NS_NewEmptyEnumerator(labels);
01777 }
01778 
01779 
01780 
01781 NS_IMETHODIMP
01782 InternetSearchDataSource::GetAllResources(nsISimpleEnumerator** aCursor)
01783 {
01784        nsresult      rv = NS_RDF_NO_VALUE;
01785 
01786        if (mInner)
01787        {
01788               rv = mInner->GetAllResources(aCursor);
01789        }
01790        return(rv);
01791 }
01792 
01793 
01794 
01795 NS_IMETHODIMP
01796 InternetSearchDataSource::AddObserver(nsIRDFObserver *aObserver)
01797 {
01798        nsresult      rv = NS_OK;
01799 
01800        if (mInner)
01801        {
01802               rv = mInner->AddObserver(aObserver);
01803        }
01804        return(rv);
01805 }
01806 
01807 
01808 
01809 NS_IMETHODIMP
01810 InternetSearchDataSource::RemoveObserver(nsIRDFObserver *aObserver)
01811 {
01812        nsresult      rv = NS_OK;
01813 
01814        if (mInner)
01815        {
01816               rv = mInner->RemoveObserver(aObserver);
01817        }
01818        return(rv);
01819 }
01820 
01821 
01822 
01823 NS_IMETHODIMP
01824 InternetSearchDataSource::GetAllCmds(nsIRDFResource* source,
01825                                      nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
01826 {
01827        nsCOMPtr<nsISupportsArray>  cmdArray;
01828        nsresult                    rv;
01829        rv = NS_NewISupportsArray(getter_AddRefs(cmdArray));
01830        if (NS_FAILED(rv))   return(rv);
01831 
01832        // check if we have any filters, enable command to clear them
01833        PRBool                      haveFilters = PR_FALSE;
01834 
01835        if (mLocalstore)
01836        {
01837               nsCOMPtr<nsISimpleEnumerator>      cursor;
01838               PRBool                      hasMore = PR_FALSE;
01839 
01840               // check kNC_FilterSearchURLsRoot
01841               if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchURLsRoot, kNC_Child,
01842                      PR_TRUE, getter_AddRefs(cursor))))
01843               {
01844       if (NS_SUCCEEDED(cursor->HasMoreElements(&hasMore)) && hasMore)
01845                      {
01846                             haveFilters = PR_TRUE;
01847                      }
01848               }
01849     if (!haveFilters)
01850               {
01851                      // check kNC_FilterSearchSitesRoot
01852                      if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchSitesRoot, kNC_Child,
01853                             PR_TRUE, getter_AddRefs(cursor))))
01854                      {
01855         if (NS_SUCCEEDED(cursor->HasMoreElements(&hasMore)) && hasMore)
01856                             {
01857                                    haveFilters = PR_TRUE;
01858                             }
01859                      }
01860               }
01861        }
01862 
01863        PRBool                      isSearchResult = PR_FALSE;
01864   rv = mInner->HasAssertion(source, kRDF_type, kNC_SearchResult, PR_TRUE,
01865           &isSearchResult);
01866   if (NS_SUCCEEDED(rv) && isSearchResult)
01867        {
01868 #ifndef MOZ_PLACES
01869               nsCOMPtr<nsIRDFDataSource>  datasource;
01870               if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource))))
01871               {
01872                      nsCOMPtr<nsIBookmarksService> bookmarks (do_QueryInterface(datasource));
01873                      if (bookmarks)
01874                      {
01875                             char *uri = getSearchURI(source);
01876                             if (uri)
01877                             {
01878                                    PRBool isBookmarkedFlag = PR_FALSE;
01879           rv = bookmarks->IsBookmarked(uri, &isBookmarkedFlag);
01880           if (NS_SUCCEEDED(rv) && !isBookmarkedFlag)
01881                                    {
01882                                           cmdArray->AppendElement(kNC_SearchCommand_AddToBookmarks);
01883                                    }
01884                                    Recycle(uri);
01885                             }
01886                      }
01887               }
01888 #endif
01889               cmdArray->AppendElement(kNC_SearchCommand_AddQueryToBookmarks);
01890               cmdArray->AppendElement(kNC_BookmarkSeparator);
01891 
01892               // if this is a search result, and it isn't filtered, enable command to be able to filter it
01893               PRBool                      isURLFiltered = PR_FALSE;
01894     rv = mInner->HasAssertion(kNC_FilterSearchURLsRoot, kNC_Child, source,
01895                               PR_TRUE, &isURLFiltered);
01896     if (NS_SUCCEEDED(rv) && !isURLFiltered)
01897               {
01898                      cmdArray->AppendElement(kNC_SearchCommand_FilterResult);
01899               }
01900 
01901               // XXX (should check site) if this is a search result site, and the site isn't filtered,
01902               //     enable command to filter it
01903               cmdArray->AppendElement(kNC_SearchCommand_FilterSite);
01904 
01905     if (haveFilters)
01906               {
01907                      cmdArray->AppendElement(kNC_BookmarkSeparator);
01908                      cmdArray->AppendElement(kNC_SearchCommand_ClearFilters);
01909               }
01910        }
01911        else if (isSearchURI(source) || (source == kNC_LastSearchRoot))
01912        {
01913     if (haveFilters)
01914               {
01915                      cmdArray->AppendElement(kNC_SearchCommand_ClearFilters);
01916               }
01917        }
01918 
01919        // always append a separator last (due to aggregation of commands from multiple datasources)
01920        cmdArray->AppendElement(kNC_BookmarkSeparator);
01921 
01922        nsISimpleEnumerator         *result = new nsArrayEnumerator(cmdArray);
01923        if (!result)
01924               return(NS_ERROR_OUT_OF_MEMORY);
01925        NS_ADDREF(result);
01926        *commands = result;
01927        return(NS_OK);
01928 }
01929 
01930 
01931 
01932 NS_IMETHODIMP
01933 InternetSearchDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
01934                                        nsIRDFResource*   aCommand,
01935                                        nsISupportsArray/*<nsIRDFResource>*/* aArguments,
01936                                        PRBool* aResult)
01937 {
01938        return(NS_ERROR_NOT_IMPLEMENTED);
01939 }
01940 
01941 
01942 
01943 char *
01944 InternetSearchDataSource::getSearchURI(nsIRDFResource *src)
01945 {
01946        char   *uri = nsnull;
01947 
01948        if (src)
01949        {
01950               nsresult             rv;
01951               nsCOMPtr<nsIRDFNode> srcNode;
01952               if (NS_SUCCEEDED(rv = mInner->GetTarget(src, kNC_URL, PR_TRUE, getter_AddRefs(srcNode))))
01953               {
01954                      nsCOMPtr<nsIRDFLiteral>     urlLiteral (do_QueryInterface(srcNode));
01955                      if (urlLiteral)
01956                      {
01957                             const PRUnichar      *uriUni = nsnull;
01958                             urlLiteral->GetValueConst(&uriUni);
01959                             if (uriUni)
01960                             {
01961                                    nsAutoString  uriString(uriUni);
01962                                    uri = ToNewUTF8String(uriString);
01963                             }
01964                      }
01965               }
01966        }
01967        return(uri);
01968 }
01969 
01970 
01971 
01972 nsresult
01973 InternetSearchDataSource::addToBookmarks(nsIRDFResource *src)
01974 {
01975        if (!src)     return(NS_ERROR_UNEXPECTED);
01976        if (!mInner)  return(NS_ERROR_UNEXPECTED);
01977 
01978        nsresult             rv;
01979        nsCOMPtr<nsIRDFNode> nameNode;
01980        // Note: nameLiteral needs to stay in scope for the life of "name"
01981        nsCOMPtr<nsIRDFLiteral>     nameLiteral;
01982        const PRUnichar             *name = nsnull;
01983        if (NS_SUCCEEDED(rv = mInner->GetTarget(src, kNC_Name, PR_TRUE, getter_AddRefs(nameNode))))
01984        {
01985               nameLiteral = do_QueryInterface(nameNode);
01986               if (nameLiteral)
01987               {
01988                      nameLiteral->GetValueConst(&name);
01989               }
01990        }
01991 
01992 #ifndef MOZ_PLACES
01993        nsCOMPtr<nsIRDFDataSource>  datasource;
01994        if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource))))
01995        {
01996               nsCOMPtr<nsIBookmarksService> bookmarks (do_QueryInterface(datasource));
01997               if (bookmarks)
01998               {
01999                      char   *uri = getSearchURI(src);
02000                      if (uri)
02001                      {
02002                             rv = bookmarks->AddBookmarkImmediately(NS_ConvertUTF8toUTF16(uri).get(),
02003                                                name, nsIBookmarksService::BOOKMARK_SEARCH_TYPE, nsnull);
02004                             Recycle(uri);
02005                      }
02006               }
02007        }
02008 #endif
02009 
02010        return(NS_OK);
02011 }
02012 
02013 
02014 
02015 nsresult
02016 InternetSearchDataSource::addQueryToBookmarks(nsIRDFResource *src)
02017 {
02018        if (!src)     return(NS_ERROR_UNEXPECTED);
02019        if (!mInner)  return(NS_ERROR_UNEXPECTED);
02020 
02021        nsresult rv;
02022        nsCOMPtr<nsIRDFNode> refNode;
02023        if (NS_FAILED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref, PR_TRUE,
02024               getter_AddRefs(refNode))))
02025               return(rv);
02026        nsCOMPtr<nsIRDFLiteral>     urlLiteral (do_QueryInterface(refNode));
02027        if (!urlLiteral)
02028          return(NS_ERROR_UNEXPECTED);
02029        const PRUnichar      *uriUni = nsnull;
02030        urlLiteral->GetValueConst(&uriUni);
02031 
02032        nsCOMPtr<nsIRDFNode> textNode;
02033        if (NS_FAILED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_LastText, PR_TRUE,
02034               getter_AddRefs(textNode))))
02035               return(rv);
02036        nsCOMPtr<nsIRDFLiteral> textLiteral = do_QueryInterface(textNode);
02037        nsXPIDLString value;
02038        if (textLiteral)
02039        {
02040               const PRUnichar *textUni = nsnull;
02041               textLiteral->GetValueConst(&textUni);
02042        nsAutoString name;
02043               name.Assign(textUni);
02044               // replace pluses with spaces
02045               name.ReplaceChar(PRUnichar('+'), PRUnichar(' '));
02046 
02047        nsCOMPtr<nsIStringBundleService>
02048        stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
02049        if (NS_SUCCEEDED(rv) && stringService)
02050        {
02051               nsCOMPtr<nsIStringBundle> bundle;
02052               rv = stringService->CreateBundle(SEARCH_PROPERTIES, getter_AddRefs(bundle));
02053               if (bundle)
02054               {
02055                      const PRUnichar *strings[] = { name.get() };
02056                      rv = bundle->FormatStringFromName(NS_LITERAL_STRING("searchTitle").get(), strings, 1, 
02057                             getter_Copies(value));
02058                      }
02059               }
02060        }
02061 
02062 #ifndef MOZ_PLACES
02063        nsCOMPtr<nsIRDFDataSource>  datasource;
02064        if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource))))
02065        {
02066               nsCOMPtr<nsIBookmarksService> bookmarks (do_QueryInterface(datasource));
02067               if (bookmarks)
02068                      rv = bookmarks->AddBookmarkImmediately(uriUni, value.get(),
02069                                              nsIBookmarksService::BOOKMARK_SEARCH_TYPE, nsnull);
02070        }
02071 #endif
02072 
02073        return(NS_OK);
02074 }
02075 
02076 
02077 
02078 nsresult
02079 InternetSearchDataSource::filterResult(nsIRDFResource *aResource)
02080 {
02081        if (!aResource)      return(NS_ERROR_UNEXPECTED);
02082        if (!mInner)  return(NS_ERROR_UNEXPECTED);
02083 
02084        // remove all anonymous resources which have this as a #URL
02085        char   *uri = getSearchURI(aResource);
02086        if (!uri)     return(NS_ERROR_UNEXPECTED);
02087        nsAutoString  url;
02088        url.AssignWithConversion(uri);
02089        Recycle(uri);
02090 
02091        nsresult                    rv;
02092        nsCOMPtr<nsIRDFLiteral>     urlLiteral;
02093        if (NS_FAILED(rv = gRDFService->GetLiteral(url.get(), getter_AddRefs(urlLiteral)))
02094               || (urlLiteral == nsnull))  return(NS_ERROR_UNEXPECTED);
02095 
02096        // add aResource into a list of nodes to filter out
02097        PRBool alreadyFiltered = PR_FALSE;
02098   rv = mLocalstore->HasAssertion(kNC_FilterSearchURLsRoot, kNC_Child,
02099          urlLiteral, PR_TRUE, &alreadyFiltered);
02100   if (NS_SUCCEEDED(rv) && alreadyFiltered)
02101        {
02102               // already filtered, nothing to do
02103               return(rv);
02104        }
02105 
02106        // filter this URL out
02107        mLocalstore->Assert(kNC_FilterSearchURLsRoot, kNC_Child, urlLiteral, PR_TRUE);
02108 
02109        // flush localstore
02110        nsCOMPtr<nsIRDFRemoteDataSource> remoteLocalStore (do_QueryInterface(mLocalstore));
02111        if (remoteLocalStore)
02112        {
02113               remoteLocalStore->Flush();
02114        }
02115 
02116        nsCOMPtr<nsISimpleEnumerator>      anonArcs;
02117        if (NS_SUCCEEDED(rv = mInner->GetSources(kNC_URL, urlLiteral, PR_TRUE,
02118               getter_AddRefs(anonArcs))))
02119        {
02120               PRBool               hasMoreAnonArcs = PR_TRUE;
02121     while (hasMoreAnonArcs)
02122               {
02123       if (NS_FAILED(anonArcs->HasMoreElements(&hasMoreAnonArcs)) ||
02124           !hasMoreAnonArcs)
02125         break;
02126                      nsCOMPtr<nsISupports>       anonArc;
02127                      if (NS_FAILED(anonArcs->GetNext(getter_AddRefs(anonArc))))
02128                             break;
02129                      nsCOMPtr<nsIRDFResource> anonChild (do_QueryInterface(anonArc));
02130                      if (!anonChild)      continue;
02131 
02132                      PRBool isSearchResult = PR_FALSE;
02133       rv = mInner->HasAssertion(anonChild, kRDF_type, kNC_SearchResult,
02134                                 PR_TRUE, &isSearchResult);
02135       if (NS_FAILED(rv) || !isSearchResult)
02136                             continue;
02137 
02138                      nsCOMPtr<nsIRDFResource>    anonParent;
02139                      if (NS_FAILED(rv = mInner->GetSource(kNC_Child, anonChild, PR_TRUE,
02140                             getter_AddRefs(anonParent))))      continue;
02141                      if (!anonParent)     continue;
02142 
02143                      mInner->Unassert(anonParent, kNC_Child, anonChild);
02144               }
02145        }
02146 
02147        return(NS_OK);
02148 }
02149 
02150 
02151 
02152 nsresult
02153 InternetSearchDataSource::filterSite(nsIRDFResource *aResource)
02154 {
02155        if (!aResource)      return(NS_ERROR_UNEXPECTED);
02156        if (!mInner)  return(NS_ERROR_UNEXPECTED);
02157 
02158        char   *uri = getSearchURI(aResource);
02159        if (!uri)     return(NS_ERROR_UNEXPECTED);
02160        nsAutoString  host;
02161        host.AssignWithConversion(uri);
02162        Recycle(uri);
02163 
02164        // determine site (host name)
02165        PRInt32              slashOffset1 = host.Find("://");
02166        if (slashOffset1 < 1)                     return(NS_ERROR_UNEXPECTED);
02167        PRInt32       slashOffset2 = host.FindChar(PRUnichar('/'), slashOffset1 + 3);
02168        if (slashOffset2 <= slashOffset1)  return(NS_ERROR_UNEXPECTED);
02169        host.Truncate(slashOffset2 + 1);
02170 
02171        nsresult                    rv;
02172        nsCOMPtr<nsIRDFLiteral>     urlLiteral;
02173        if (NS_FAILED(rv = gRDFService->GetLiteral(host.get(), getter_AddRefs(urlLiteral)))
02174               || (urlLiteral == nsnull))  return(NS_ERROR_UNEXPECTED);
02175 
02176        // add aResource into a list of nodes to filter out
02177        PRBool alreadyFiltered = PR_FALSE;
02178   rv = mLocalstore->HasAssertion(kNC_FilterSearchSitesRoot, kNC_Child,
02179          urlLiteral, PR_TRUE, &alreadyFiltered);
02180   if (NS_SUCCEEDED(rv) && alreadyFiltered)
02181        {
02182               // already filtered, nothing to do
02183               return(rv);
02184        }
02185 
02186        // filter this site out
02187        mLocalstore->Assert(kNC_FilterSearchSitesRoot, kNC_Child, urlLiteral, PR_TRUE);
02188 
02189        // flush localstore
02190        nsCOMPtr<nsIRDFRemoteDataSource> remoteLocalStore (do_QueryInterface(mLocalstore));
02191        if (remoteLocalStore)
02192        {
02193               remoteLocalStore->Flush();
02194        }
02195 
02196        // remove all anonymous resources which have this as a site
02197 
02198        nsCOMPtr<nsISupportsArray>  array;
02199        nsCOMPtr<nsIRDFResource>    aRes;
02200        nsCOMPtr<nsISimpleEnumerator>      cursor;
02201        PRBool                      hasMore;
02202 
02203        rv = NS_NewISupportsArray(getter_AddRefs(array));
02204        if (NS_FAILED(rv)) return rv;
02205 
02206        if (NS_FAILED(rv = GetAllResources(getter_AddRefs(cursor))))   return(rv);
02207        if (!cursor)  return(NS_ERROR_UNEXPECTED);
02208 
02209        hasMore = PR_TRUE;
02210   while (hasMore)
02211        {
02212               if (NS_FAILED(rv = cursor->HasMoreElements(&hasMore)))  return(rv);
02213     if (!hasMore)
02214       break;
02215               
02216               nsCOMPtr<nsISupports>       isupports;
02217               if (NS_FAILED(rv = cursor->GetNext(getter_AddRefs(isupports))))
02218                             return(rv);
02219               if (!isupports)      return(NS_ERROR_UNEXPECTED);
02220               aRes = do_QueryInterface(isupports);
02221               if (!aRes)    return(NS_ERROR_UNEXPECTED);
02222 
02223               if ((aRes.get() == kNC_LastSearchRoot) || (isSearchURI(aRes)))
02224               {
02225                      array->AppendElement(aRes);
02226               }
02227        }
02228 
02229        PRUint32      count;
02230        if (NS_FAILED(rv = array->Count(&count))) return(rv);
02231        for (PRUint32 loop=0; loop<count; loop++)
02232        {
02233               nsCOMPtr<nsIRDFResource> aSearchRoot (do_QueryElementAt(array, loop));
02234               if (!aSearchRoot)    break;
02235 
02236               if (NS_SUCCEEDED(rv = mInner->GetTargets(aSearchRoot, kNC_Child,
02237                      PR_TRUE, getter_AddRefs(cursor))))
02238               {
02239                      hasMore = PR_TRUE;
02240       while (hasMore)
02241                      {
02242         if (NS_FAILED(cursor->HasMoreElements(&hasMore)) || !hasMore)
02243           break;
02244 
02245                             nsCOMPtr<nsISupports>              arc;
02246                             if (NS_FAILED(cursor->GetNext(getter_AddRefs(arc))))
02247                                    break;
02248                             aRes = do_QueryInterface(arc);
02249                             if (!aRes)    break;
02250 
02251                             uri = getSearchURI(aRes);
02252                             if (!uri)     return(NS_ERROR_UNEXPECTED);
02253                             nsAutoString  site;
02254                             site.AssignWithConversion(uri);
02255                             Recycle(uri);
02256 
02257                             // determine site (host name)
02258                             slashOffset1 = site.Find("://");
02259                             if (slashOffset1 < 1)                     return(NS_ERROR_UNEXPECTED);
02260                             slashOffset2 = site.FindChar(PRUnichar('/'), slashOffset1 + 3);
02261                             if (slashOffset2 <= slashOffset1)  return(NS_ERROR_UNEXPECTED);
02262                             site.Truncate(slashOffset2 + 1);
02263 
02264                             if (site.Equals(host, nsCaseInsensitiveStringComparator()))
02265                             {
02266                                    mInner->Unassert(aSearchRoot, kNC_Child, aRes);
02267                             }
02268                      }
02269               }
02270        }
02271 
02272        return(NS_OK);
02273 }
02274 
02275 
02276 
02277 nsresult
02278 InternetSearchDataSource::clearFilters(void)
02279 {
02280        if (!mInner)  return(NS_ERROR_UNEXPECTED);
02281 
02282        nsresult                    rv;
02283        nsCOMPtr<nsISimpleEnumerator>      arcs;
02284        PRBool                      hasMore = PR_TRUE;
02285        nsCOMPtr<nsISupports>              arc;
02286 
02287        // remove all filtered URLs
02288        if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchURLsRoot, kNC_Child,
02289               PR_TRUE, getter_AddRefs(arcs))))
02290        {
02291               hasMore = PR_TRUE;
02292     while (hasMore)
02293               {
02294       if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
02295                             break;
02296                      if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
02297                             break;
02298 
02299                      nsCOMPtr<nsIRDFLiteral>     filterURL (do_QueryInterface(arc));
02300                      if (!filterURL)      continue;
02301                      
02302                      mLocalstore->Unassert(kNC_FilterSearchURLsRoot, kNC_Child, filterURL);
02303               }
02304        }
02305 
02306        // remove all filtered sites
02307        if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchSitesRoot, kNC_Child,
02308               PR_TRUE, getter_AddRefs(arcs))))
02309        {
02310               hasMore = PR_TRUE;
02311     while (hasMore)
02312               {
02313       if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
02314                             break;
02315                      if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
02316                             break;
02317 
02318                      nsCOMPtr<nsIRDFLiteral>     filterSiteLiteral (do_QueryInterface(arc));
02319                      if (!filterSiteLiteral)     continue;
02320                      
02321                      mLocalstore->Unassert(kNC_FilterSearchSitesRoot, kNC_Child, filterSiteLiteral);
02322               }
02323        }
02324 
02325        // flush localstore
02326        nsCOMPtr<nsIRDFRemoteDataSource> remoteLocalStore (do_QueryInterface(mLocalstore));
02327        if (remoteLocalStore)
02328        {
02329               remoteLocalStore->Flush();
02330        }
02331 
02332        return(NS_OK);
02333 }
02334 
02335 
02336 
02337 PRBool
02338 InternetSearchDataSource::isSearchResultFiltered(const nsString &hrefStr)
02339 {
02340        PRBool        filterStatus = PR_FALSE;
02341        nsresult      rv;
02342 
02343        const PRUnichar      *hrefUni = hrefStr.get();
02344        if (!hrefUni) return(filterStatus);
02345 
02346        // check if this specific URL is to be filtered out
02347        nsCOMPtr<nsIRDFLiteral>     hrefLiteral;
02348        if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(hrefUni, getter_AddRefs(hrefLiteral))))
02349        {
02350               if (NS_SUCCEEDED(rv = mLocalstore->HasAssertion(kNC_FilterSearchURLsRoot,
02351                      kNC_Child, hrefLiteral, PR_TRUE, &filterStatus)))
02352               {
02353       if (filterStatus)
02354                      {
02355                             return(filterStatus);
02356                      }
02357               }
02358        }
02359 
02360        // check if this specific Site is to be filtered out
02361 
02362        // determine site (host name)
02363        nsAutoString  host(hrefStr);
02364        PRInt32              slashOffset1 = host.Find("://");
02365        if (slashOffset1 < 1)                     return(NS_ERROR_UNEXPECTED);
02366        PRInt32       slashOffset2 = host.FindChar(PRUnichar('/'), slashOffset1 + 3);
02367        if (slashOffset2 <= slashOffset1)  return(NS_ERROR_UNEXPECTED);
02368        host.Truncate(slashOffset2 + 1);
02369 
02370        nsCOMPtr<nsIRDFLiteral>     urlLiteral;
02371        if (NS_FAILED(rv = gRDFService->GetLiteral(host.get(), getter_AddRefs(urlLiteral)))
02372               || (urlLiteral == nsnull))  return(NS_ERROR_UNEXPECTED);
02373 
02374        rv = mLocalstore->HasAssertion(kNC_FilterSearchSitesRoot, kNC_Child, urlLiteral,
02375               PR_TRUE, &filterStatus);
02376 
02377        return(filterStatus);
02378 }
02379 
02380 
02381 
02382 NS_IMETHODIMP
02383 InternetSearchDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
02384                                 nsIRDFResource*   aCommand,
02385                                 nsISupportsArray/*<nsIRDFResource>*/* aArguments)
02386 {
02387        nsresult             rv = NS_OK;
02388        PRInt32                     loop;
02389        PRUint32             numSources;
02390        if (NS_FAILED(rv = aSources->Count(&numSources)))       return(rv);
02391        if (numSources < 1)
02392        {
02393               return(NS_ERROR_ILLEGAL_VALUE);
02394        }
02395 
02396        for (loop=((PRInt32)numSources)-1; loop>=0; loop--)
02397        {
02398               nsCOMPtr<nsIRDFResource> src (do_QueryElementAt(aSources, loop));
02399               if (!src)     return(NS_ERROR_NO_INTERFACE);
02400 
02401               if (aCommand == kNC_SearchCommand_AddToBookmarks)
02402               {
02403                      if (NS_FAILED(rv = addToBookmarks(src)))
02404                             return(rv);
02405               }
02406               else if (aCommand == kNC_SearchCommand_AddQueryToBookmarks)
02407               {
02408                 if (NS_FAILED(rv = addQueryToBookmarks(src)))
02409                   return(rv);
02410               }
02411               else if (aCommand == kNC_SearchCommand_FilterResult)
02412               {
02413                      if (NS_FAILED(rv = filterResult(src)))
02414                             return(rv);
02415               }
02416               else if (aCommand == kNC_SearchCommand_FilterSite)
02417               {
02418                      if (NS_FAILED(rv = filterSite(src)))
02419                             return(rv);
02420               }
02421               else if (aCommand == kNC_SearchCommand_ClearFilters)
02422               {
02423                      if (NS_FAILED(rv = clearFilters()))
02424                             return(rv);
02425               }
02426        }
02427        return(NS_OK);
02428 }
02429 
02430 NS_IMETHODIMP
02431 InternetSearchDataSource::BeginUpdateBatch()
02432 {
02433         return mInner->BeginUpdateBatch();
02434 }
02435 
02436 NS_IMETHODIMP
02437 InternetSearchDataSource::EndUpdateBatch()
02438 {
02439         return mInner->EndUpdateBatch();
02440 }
02441 
02442 NS_IMETHODIMP
02443 InternetSearchDataSource::AddSearchEngine(const char *engineURL, const char *iconURL,
02444                                      const PRUnichar *suggestedTitle, const PRUnichar *suggestedCategory)
02445 {
02446         return AddSearchEngineInternal(engineURL, iconURL, suggestedTitle,
02447                                        suggestedCategory, nsnull);
02448 }
02449 
02450 nsresult
02451 InternetSearchDataSource::AddSearchEngineInternal(const char *engineURL, const char *iconURL,
02452                                                   const PRUnichar *suggestedTitle,
02453                                                   const PRUnichar *suggestedCategory,
02454                                                   nsIRDFResource *aOldEngineResource)
02455 {
02456        NS_PRECONDITION(engineURL != nsnull, "null ptr");
02457        if (!engineURL)      return(NS_ERROR_NULL_POINTER);
02458        // Note: iconURL, suggestedTitle & suggestedCategory
02459        // can be null or empty strings, which is OK
02460 
02461 #ifdef DEBUG_SEARCH_OUTPUT
02462        printf("AddSearchEngine: engine='%s'\n", engineURL);
02463 #endif
02464 
02465        nsresult      rv = NS_OK;
02466 
02467        // mBackgroundLoadGroup is a dynamically created singleton
02468        if (!mBackgroundLoadGroup)
02469        {
02470               if (NS_FAILED(rv = NS_NewLoadGroup(getter_AddRefs(mBackgroundLoadGroup), nsnull)))
02471                      return(rv);
02472               if (!mBackgroundLoadGroup)
02473                      return(NS_ERROR_UNEXPECTED);
02474        }
02475 
02476        // download engine
02477        nsCOMPtr<nsIInternetSearchContext> engineContext;
02478   rv = NS_NewInternetSearchContext
02479          (aOldEngineResource? nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT:
02480                               nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT,
02481           nsnull, aOldEngineResource, nsnull, suggestedCategory,
02482           getter_AddRefs(engineContext));
02483   NS_ENSURE_SUCCESS(rv, rv);
02484 
02485        if (!engineContext)  return(NS_ERROR_UNEXPECTED);
02486 
02487        nsCOMPtr<nsIURI>     engineURI;
02488        if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(engineURI), engineURL)))
02489               return(rv);
02490 
02491        nsCOMPtr<nsIChannel> engineChannel;
02492        if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(engineChannel), engineURI, nsnull, mBackgroundLoadGroup)))
02493               return(rv);
02494     
02495        if (NS_FAILED(rv = engineChannel->AsyncOpen(this, engineContext)))
02496               return(rv);
02497 
02498        // download icon
02499        nsCOMPtr<nsIInternetSearchContext> iconContext;
02500   rv = NS_NewInternetSearchContext
02501          (aOldEngineResource? nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT:
02502                               nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT,
02503           nsnull, aOldEngineResource, nsnull, suggestedCategory,
02504           getter_AddRefs(iconContext));
02505   NS_ENSURE_SUCCESS(rv, rv);
02506 
02507        if (!iconContext)    return(NS_ERROR_UNEXPECTED);
02508 
02509        if (iconURL && (*iconURL))
02510        {
02511               nsCOMPtr<nsIURI>     iconURI;
02512               if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(iconURI), iconURL)))
02513                      return(rv);
02514 
02515               nsCOMPtr<nsIChannel> iconChannel;
02516               if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(iconChannel), iconURI, nsnull, mBackgroundLoadGroup)))
02517                      return(rv);
02518               if (NS_FAILED(rv = iconChannel->AsyncOpen(this, iconContext)))
02519                      return(rv);
02520        }
02521        return(NS_OK);
02522 }
02523 
02524 
02525 
02526 nsresult
02527 InternetSearchDataSource::saveContents(nsIChannel* channel, nsIInternetSearchContext *context, PRUint32  contextType)
02528 {
02529     NS_ASSERTION(contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT ||
02530                  contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT ||
02531                  contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT ||
02532                  contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT,
02533                  "unexpected context");
02534        nsresult      rv = NS_OK;
02535 
02536        if (!channel) return(NS_ERROR_UNEXPECTED);
02537        if (!context) return(NS_ERROR_UNEXPECTED);
02538 
02539        // get real URI
02540        nsCOMPtr<nsIURI>     channelURI;
02541        if (NS_FAILED(rv = channel->GetURI(getter_AddRefs(channelURI))))
02542               return(rv);
02543        if (!channelURI)
02544               return(NS_ERROR_NULL_POINTER);
02545 
02546        nsCAutoString baseName;
02547        if (NS_FAILED(rv = channelURI->GetSpec(baseName)))
02548               return(rv);
02549 
02550        PRInt32                     slashOffset = baseName.RFindChar(PRUnichar('/'));
02551        if (slashOffset < 0)        return(NS_ERROR_UNEXPECTED);
02552        baseName.Cut(0, slashOffset+1);
02553        if (baseName.IsEmpty())     return(NS_ERROR_UNEXPECTED);
02554 
02555        // make sure that search engines are .src files
02556        PRInt32       extensionOffset;
02557        if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT ||
02558               contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT)
02559        {
02560               extensionOffset = baseName.RFind(".src", PR_TRUE);
02561               if ((extensionOffset < 0) || (extensionOffset != (PRInt32)(baseName.Length()-4)))
02562               {
02563                      return(NS_ERROR_UNEXPECTED);
02564               }
02565        }
02566 
02567     nsCOMPtr<nsIFile> outFile;
02568   // If the mode is "UPDATE", the output dir is same as the original file
02569   // location. Otherwise ("NEW" mode), located in NS_APP_USER_SEARCH_DIR.
02570   nsCOMPtr<nsIRDFResource> oldResource;
02571   rv = context->GetEngine(getter_AddRefs(oldResource));
02572 
02573   if (oldResource) {
02574     nsCOMPtr<nsILocalFile> oldEngineFile;
02575     rv = EngineFileFromResource(oldResource, getter_AddRefs(oldEngineFile));
02576     NS_ENSURE_SUCCESS(rv, rv);
02577 
02578     rv = oldEngineFile->GetParent(getter_AddRefs(outFile));
02579     NS_ENSURE_SUCCESS(rv, rv);
02580   }
02581   else {
02582     rv = NS_GetSpecialDirectory(NS_APP_USER_SEARCH_DIR, getter_AddRefs(outFile));
02583     if (NS_FAILED(rv))
02584         return rv;
02585   }
02586 
02587     PRBool exists;
02588     rv = outFile->Exists(&exists);
02589     if (NS_FAILED(rv)) return(rv);
02590     if (!exists)
02591     {
02592         rv = outFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
02593         if (NS_FAILED(rv)) return(rv);
02594     }
02595 
02596        const PRUnichar      *dataBuf = nsnull;
02597        if (NS_FAILED(rv = context->GetBufferConst(&dataBuf)))  return(rv);
02598 
02599        // if no data, then nothing to do
02600        // Note: do this before opening file, as it would be truncated
02601        PRInt32              bufferLength = 0;
02602        if (NS_FAILED(context->GetBufferLength(&bufferLength))) return(rv);
02603        if (bufferLength < 1)       return(NS_OK);
02604        
02605        rv = outFile->Append(NS_ConvertUTF8toUCS2(baseName));
02606        if (NS_FAILED(rv)) return rv;
02607        
02608        // save data to file
02609        // Note: write out one character at a time, as we might be dealing
02610        //       with binary data (such as 0x00) [especially for images]
02611     //
02612     // XXX - It appears that this is done in order to discard the upper
02613     // byte of each PRUnichar.  I hope that's OK!!
02614     //
02615     if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT ||
02616         contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT) {
02617         // This is an update operation that we triggered.  Remove the old one.
02618         outFile->Remove(PR_FALSE);
02619     } else {
02620         PRBool exists;
02621         rv = outFile->Exists(&exists);
02622         if (NS_FAILED(rv) || exists) {
02623             // We already have a search plugin with this filename; don't
02624             // replace it (bug 290038).
02625             return NS_ERROR_UNEXPECTED;
02626         }
02627     }
02628 
02629     nsCOMPtr<nsIOutputStream> outputStream, fileOutputStream;
02630     rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutputStream), outFile);
02631     if (NS_FAILED(rv)) return rv;
02632     rv = NS_NewBufferedOutputStream(getter_AddRefs(outputStream), fileOutputStream, 4096);
02633     if (NS_FAILED(rv)) return rv;
02634 
02635     PRUint32 bytesWritten;
02636     for (PRInt32 loop=0; loop < bufferLength; loop++)
02637     {
02638         const char b = (const char) dataBuf[loop];
02639         outputStream->Write(&b, 1, &bytesWritten);
02640     }
02641     outputStream->Flush();         
02642     outputStream->Close();
02643 
02644     if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT ||
02645         contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT)
02646     {
02647         // check suggested category hint
02648         const PRUnichar     *hintUni = nsnull;
02649         rv = context->GetHintConst(&hintUni);
02650 
02651         // update graph with various required info
02652         SaveEngineInfoIntoGraph(outFile, nsnull, hintUni, dataBuf, PR_FALSE);
02653     }
02654     else if (contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT ||
02655              contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT)
02656     {
02657         // update graph with icon info
02658         SaveEngineInfoIntoGraph(nsnull, outFile, nsnull, nsnull, PR_FALSE);
02659     }
02660 
02661        // after we're all done with the data buffer, get rid of it
02662        context->Truncate();
02663 
02664        return(rv);
02665 }
02666 
02667 
02668 
02669 NS_IMETHODIMP
02670 InternetSearchDataSource::GetInternetSearchURL(const char *searchEngineURI,
02671   const PRUnichar *searchStr, PRInt16 direction, PRUint16 pageNumber, 
02672   PRUint16 *whichButtons, char **resultURL)
02673 {
02674        if (!resultURL)      return(NS_ERROR_NULL_POINTER);
02675        *resultURL = nsnull;
02676 
02677        // if we haven't already, load in the engines
02678   if (!gEngineListBuilt)
02679     DeferredInit();
02680 
02681        nsresult                    rv;
02682        nsCOMPtr<nsIRDFResource>    engine;
02683        if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(searchEngineURI), getter_AddRefs(engine))))
02684               return(rv);
02685        if (!engine)  return(NS_ERROR_UNEXPECTED);
02686 
02687        validateEngine(engine);
02688        
02689        // if its a engine from a search category, then get its "#Name",
02690        // and try to map from that back to the real engine reference
02691        if (isSearchCategoryEngineURI(engine))
02692        {
02693               nsCOMPtr<nsIRDFResource>    trueEngine;
02694               rv = resolveSearchCategoryEngineURI(engine, getter_AddRefs(trueEngine));
02695               if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
02696               if (!trueEngine)     return(NS_RDF_NO_VALUE);
02697 
02698               engine = trueEngine;
02699        }
02700 
02701        nsCOMPtr<nsIRDFLiteral>     dataLit;
02702        rv = FindData(engine, getter_AddRefs(dataLit));
02703        if (NS_FAILED(rv) ||
02704            (rv == NS_RDF_NO_VALUE))       return(rv);
02705        if (!dataLit) return(NS_ERROR_UNEXPECTED);
02706 
02707        const PRUnichar      *dataUni = nsnull;
02708        dataLit->GetValueConst(&dataUni);
02709        if (!dataUni) return(NS_RDF_NO_VALUE);
02710 
02711        nsAutoString   text(searchStr), encodingStr, queryEncodingStr;
02712 
02713        // first look for "search/queryCharset"... if that isn't specified,
02714        // then fall back to looking for "search/queryEncoding" (a decimal)
02715        GetData(dataUni, "search", 0, "queryCharset", queryEncodingStr);
02716        if (queryEncodingStr.IsEmpty())
02717        {
02718               GetData(dataUni, "search", 0, "queryEncoding", encodingStr);          // decimal string values
02719               MapEncoding(encodingStr, queryEncodingStr);
02720        }
02721 
02722        if (!queryEncodingStr.IsEmpty())
02723        {
02724               // remember query charset string
02725               mQueryEncodingStr = queryEncodingStr;
02726               // convert from escaped-UTF_8, to unicode, and then to
02727               // the charset indicated by the dataset in question
02728 
02729               char   *utf8data = ToNewUTF8String(text);
02730               if (utf8data)
02731               {
02732                      nsCOMPtr<nsITextToSubURI> textToSubURI = 
02733                               do_GetService(kTextToSubURICID, &rv);
02734                      if (NS_SUCCEEDED(rv) && (textToSubURI))
02735                      {
02736                             PRUnichar     *uni = nsnull;
02737                             if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert("UTF-8", utf8data, &uni)) && (uni))
02738                             {
02739                                    char          *charsetData = nsnull;
02740                                    nsCAutoString queryencodingstrC;
02741                                    queryencodingstrC.AssignWithConversion(queryEncodingStr);
02742                                    if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape(queryencodingstrC.get(), uni, &charsetData)) && (charsetData))
02743                                    {
02744                                           text.AssignWithConversion(charsetData);
02745                                           Recycle(charsetData);
02746                                    }
02747                                    Recycle(uni);
02748                             }
02749                      }
02750                      Recycle(utf8data);
02751               }
02752        }
02753        
02754        nsAutoString  action, input, method, userVar, name;
02755        if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action)))
02756            return(rv);
02757 
02758     // Search only supports the http protocol
02759     if (!StringBeginsWith(action, NS_LITERAL_STRING("http:")) &&
02760         !StringBeginsWith(action, NS_LITERAL_STRING("https:")))
02761         return NS_ERROR_UNEXPECTED;
02762 
02763        if (NS_FAILED(rv = GetData(dataUni, "search", 0, "method", method)))
02764            return(rv);
02765        if (NS_FAILED(rv = GetData(dataUni, "search", 0, "name", name)))
02766            return(rv);
02767        if (NS_FAILED(rv = GetInputs(dataUni, name, userVar, text, input, direction, pageNumber, whichButtons)))
02768            return(rv);
02769        if (input.IsEmpty())                      return(NS_ERROR_UNEXPECTED);
02770 
02771        // we can only handle HTTP GET
02772        if (!method.LowerCaseEqualsLiteral("get"))       return(NS_ERROR_UNEXPECTED);
02773        // HTTP Get method support
02774        action += input;
02775 
02776        // return a copy of the resulting search URL
02777        *resultURL = ToNewCString(action);
02778        return(NS_OK);
02779 }
02780 
02781 
02782 
02783 NS_IMETHODIMP
02784 InternetSearchDataSource::RememberLastSearchText(const PRUnichar *escapedSearchStr)
02785 {
02786        nsresult             rv;
02787 
02788        nsCOMPtr<nsIRDFNode> textNode;
02789        if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_LastText, PR_TRUE,
02790               getter_AddRefs(textNode))))
02791        {
02792               if (escapedSearchStr != nsnull)
02793               {
02794                      nsresult             temprv;
02795                      nsCOMPtr<nsIRDFLiteral>     textLiteral;
02796                      if (NS_SUCCEEDED(temprv = gRDFService->GetLiteral(escapedSearchStr, getter_AddRefs(textLiteral))))
02797                      {
02798                             if (rv != NS_RDF_NO_VALUE)
02799                             {
02800                                    mInner->Change(kNC_LastSearchRoot, kNC_LastText, textNode, textLiteral);
02801                             }
02802                             else
02803                             {
02804                                    mInner->Assert(kNC_LastSearchRoot, kNC_LastText, textLiteral, PR_TRUE);
02805                             }
02806                      }
02807               }
02808               else if (rv != NS_RDF_NO_VALUE)
02809               {
02810                      rv = mInner->Unassert(kNC_LastSearchRoot, kNC_LastText, textNode);
02811               }
02812        }
02813        return(rv);
02814 }
02815 
02816 
02817 
02818 NS_IMETHODIMP
02819 InternetSearchDataSource::FindInternetSearchResults(const char *url, PRBool *searchInProgress)
02820 {
02821        *searchInProgress = PR_FALSE;
02822 
02823        if (!mInner)  return(NS_OK);
02824 
02825        // if the url doesn't look like a HTTP GET query, just return,
02826        // otherwise strip off the query data
02827        nsAutoString         shortURL;
02828        shortURL.AssignWithConversion(url);
02829        PRInt32                     optionsOffset;
02830        if ((optionsOffset = shortURL.FindChar(PRUnichar('?'))) < 0)   return(NS_OK);
02831        shortURL.Truncate(optionsOffset);
02832 
02833        // if we haven't already, load in the engines
02834   if (!gEngineListBuilt)
02835     DeferredInit();
02836 
02837        // look in available engines to see if any of them appear
02838        // to match this url (minus the GET options)
02839        PRBool                      foundEngine = PR_FALSE;
02840        nsresult                    rv;
02841        nsCOMPtr<nsIRDFResource>    engine;
02842        nsCOMPtr<nsISimpleEnumerator>      arcs;
02843        nsAutoString                engineURI;
02844        nsCOMPtr<nsIRDFLiteral>            dataLit;
02845        const PRUnichar                    *dataUni = nsnull;
02846 
02847        if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_SearchEngineRoot, kNC_Child,
02848               PR_TRUE, getter_AddRefs(arcs))))
02849        {
02850               PRBool               hasMore = PR_TRUE;
02851     while (hasMore)
02852               {
02853       if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
02854                             break;
02855                      nsCOMPtr<nsISupports>       arc;
02856                      if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
02857                             break;
02858 
02859                      engine = do_QueryInterface(arc);
02860                      if (!engine)  continue;
02861 
02862                      const  char   *uri = nsnull;
02863                      engine->GetValueConst(&uri);
02864                      if (uri)
02865                      {
02866                             engineURI.AssignWithConversion(uri);
02867                      }
02868 
02869                      if (NS_FAILED(rv = FindData(engine, getter_AddRefs(dataLit))) ||
02870                             (rv == NS_RDF_NO_VALUE))    continue;
02871                      if (!dataLit) continue;
02872 
02873                      dataLit->GetValueConst(&dataUni);
02874                      if (!dataUni) continue;
02875 
02876                      nsAutoString         action;
02877                      if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action)))  continue;
02878                      if (shortURL.Equals(action, nsCaseInsensitiveStringComparator()))
02879                      {
02880                             foundEngine = PR_TRUE;
02881                             break;
02882                      }
02883 
02884                      // extension for engines which can have multiple "actions"
02885                      if (NS_FAILED(rv = GetData(dataUni, "browser", 0, "alsomatch", action)))     continue;
02886                      if (nsString_Find(shortURL, action, PR_TRUE) >= 0)
02887                      {
02888                             foundEngine = PR_TRUE;
02889                             break;
02890                      }
02891               }
02892        }
02893   if (foundEngine)
02894        {
02895               nsAutoString  searchURL;
02896               searchURL.AssignWithConversion(url);
02897 
02898               // look for query option which is the string the user is searching for
02899               nsAutoString  userVar, inputUnused, engineNameStr;
02900        GetData(dataUni, "search", 0, "name", engineNameStr);
02901 
02902     if (NS_FAILED(rv = GetInputs(dataUni, engineNameStr, userVar, EmptyString(), inputUnused, 0, 0, 0)))  return(rv);
02903               if (userVar.IsEmpty())      return(NS_RDF_NO_VALUE);
02904 
02905               nsAutoString  queryStr;
02906               queryStr = NS_LITERAL_STRING("?") +
02907                          userVar +
02908                          NS_LITERAL_STRING("=");
02909 
02910               PRInt32              queryOffset;
02911               if ((queryOffset = nsString_Find(queryStr, searchURL, PR_TRUE )) < 0)
02912               {
02913                      queryStr = NS_LITERAL_STRING("&") +
02914                                 userVar +
02915                                 NS_LITERAL_STRING("=");
02916                      queryOffset = nsString_Find(queryStr, searchURL, PR_TRUE);
02917               }
02918 
02919               nsAutoString  searchText;
02920               if (queryOffset >= 0)
02921               {
02922                      PRInt32              andOffset;
02923                      searchURL.Right(searchText, searchURL.Length() - queryOffset - queryStr.Length());
02924 
02925                      if ((andOffset = searchText.FindChar(PRUnichar('&'))) >= 0)
02926                      {
02927                             searchText.Truncate(andOffset);
02928                      }
02929               }
02930               if (!searchText.IsEmpty())
02931               {
02932                      // apply charset conversion to the search text
02933                      if (!mQueryEncodingStr.IsEmpty())
02934                      {
02935                             nsCOMPtr<nsITextToSubURI> textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
02936                             if (NS_SUCCEEDED(rv))
02937                             {
02938                                    nsCAutoString escapedSearchText;
02939                                    escapedSearchText.AssignWithConversion(searchText);
02940 
02941                                    // encoding +'s so as to preserve distinction between + and %2B
02942                                    escapedSearchText.ReplaceSubstring("%25", "%2B25");
02943                                    escapedSearchText.ReplaceSubstring("+", "%25");
02944 
02945                                    nsCAutoString aCharset;
02946                                    aCharset.AssignWithConversion(mQueryEncodingStr);
02947                                    PRUnichar     *uni = nsnull;
02948                                    if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert(aCharset.get(), escapedSearchText.get(), &uni)) && (uni))
02949                                    {
02950                                           char   *convertedSearchText = nsnull;
02951                                           if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape("UTF-8", uni, &convertedSearchText)))
02952                                           {
02953 
02954                                                  // decoding +'s thereby preserving distinction between + and %2B
02955                                                  nsCAutoString unescapedSearchText(convertedSearchText);
02956                                                  unescapedSearchText.ReplaceSubstring("%25", "+");
02957                                                  unescapedSearchText.ReplaceSubstring("%2B25", "%25");
02958 
02959                                                  searchText.AssignWithConversion(unescapedSearchText.get());
02960 
02961                                                  Recycle(convertedSearchText);
02962                                           }
02963                                           Recycle(uni);
02964                                    }
02965                             }
02966                      }
02967                      // remember the text of the last search
02968                      RememberLastSearchText(searchText.get());
02969 
02970                      // construct the search query uri
02971                      engineURI.Assign(NS_LITERAL_STRING("internetsearch:engine=") + engineURI +
02972                                       NS_LITERAL_STRING("&text=") + searchText);
02973 
02974 #ifdef DEBUG_SEARCH_OUTPUT
02975                      char   *engineMatch = ToNewCString(searchText);
02976                      if (engineMatch)
02977                      {
02978                             printf("FindInternetSearchResults: search for: '%s'\n\n",
02979                                    engineMatch);
02980                             Recycle(engineMatch);
02981                             engineMatch = nsnull;
02982                      }
02983 #endif
02984               }
02985               else
02986               {
02987                      // not able to determine engine URI, so just use the search URL
02988                      engineURI = searchURL;
02989 
02990                      // clear the text of the last search
02991                      RememberLastSearchText(nsnull);
02992               }
02993 
02994               // update "#Ref" on LastSearchRoot
02995               nsCOMPtr<nsIRDFNode> oldNode;
02996               if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref, PR_TRUE,
02997                      getter_AddRefs(oldNode))))
02998               {
02999                      if (!engineURI.IsEmpty())
03000                      {
03001                             const PRUnichar      *uriUni = engineURI.get();
03002                             nsCOMPtr<nsIRDFLiteral>     uriLiteral;
03003                             nsresult             temprv;
03004                             if ((uriUni) && (NS_SUCCEEDED(temprv = gRDFService->GetLiteral(uriUni,
03005                                    getter_AddRefs(uriLiteral)))))
03006                             {
03007                                    if (rv != NS_RDF_NO_VALUE)
03008                                    {
03009                                           rv = mInner->Change(kNC_LastSearchRoot, kNC_Ref, oldNode, uriLiteral);
03010                                    }
03011                                    else
03012                                    {
03013                                           rv = mInner->Assert(kNC_LastSearchRoot, kNC_Ref, uriLiteral, PR_TRUE);
03014                                    }
03015                             }
03016                      }
03017                      else
03018                      {
03019                             rv = mInner->Unassert(kNC_LastSearchRoot, kNC_Ref, oldNode);
03020                      }
03021               }
03022 
03023               // forget about any previous search results
03024               ClearResults(PR_FALSE);
03025 
03026               // do the search
03027               DoSearch(nsnull, engine, searchURL, EmptyString());
03028 
03029               *searchInProgress = PR_TRUE;
03030        }
03031 
03032        return(NS_OK);
03033 }
03034 
03035 
03036 
03037 NS_IMETHODIMP
03038 InternetSearchDataSource::ClearResults(PRBool flushLastSearchRef)
03039 {
03040        if (!mInner)  return(NS_ERROR_UNEXPECTED);
03041 
03042        // forget any nodes under the last search root
03043        nsresult                    rv;
03044        nsCOMPtr<nsISimpleEnumerator>      arcs;
03045        if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_LastSearchRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs))))
03046        {
03047               PRBool               hasMore = PR_TRUE;
03048     while (hasMore)
03049               {
03050       if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
03051                             break;
03052                      nsCOMPtr<nsISupports>       arc;
03053                      if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
03054                             break;
03055                      nsCOMPtr<nsIRDFResource> child (do_QueryInterface(arc));
03056                      if (child)
03057                      {
03058                             mInner->Unassert(kNC_LastSearchRoot, kNC_Child, child);
03059                      }
03060 
03061                      // *after* (so that we won't thrash the XUL template builder) unasserting
03062                      // child node, determine if there are any other references to the child
03063                      // node in the graph
03064 
03065                      PRBool hasInArcs = PR_FALSE;
03066                      nsCOMPtr<nsISimpleEnumerator>      inArcs;
03067                      if (NS_FAILED(mInner->ArcLabelsIn(child, getter_AddRefs(inArcs))) ||
03068                             (!inArcs))
03069                             continue;
03070       if (NS_FAILED(inArcs->HasMoreElements(&hasInArcs)) || hasInArcs)
03071                             continue;
03072 
03073                      // no other references, so also unassert any outgoing arcs
03074 
03075                      nsCOMPtr<nsISimpleEnumerator>      outArcs;
03076                      if (NS_FAILED(mInner->ArcLabelsOut(child, getter_AddRefs(outArcs))) ||
03077                             (!outArcs))
03078                             continue;
03079                      PRBool hasMoreOutArcs = PR_TRUE;
03080       while (hasMoreOutArcs)
03081                      {
03082         if (NS_FAILED(outArcs->HasMoreElements(&hasMoreOutArcs)) ||
03083             !hasMoreOutArcs)
03084                                    break;
03085                             nsCOMPtr<nsISupports>       outArc;
03086                             if (NS_FAILED(outArcs->GetNext(getter_AddRefs(outArc))))
03087                                    break;
03088                             nsCOMPtr<nsIRDFResource> property (do_QueryInterface(outArc));
03089                             if (!property)
03090                                    continue;
03091                             nsCOMPtr<nsIRDFNode> target;
03092                             if (NS_FAILED(mInner->GetTarget(child, property, PR_TRUE,
03093                                    getter_AddRefs(target))) || (!target))
03094                                    continue;
03095                             mInner->Unassert(child, property, target);
03096                      }
03097               }
03098        }
03099 
03100   if (flushLastSearchRef)
03101        {
03102               // forget the last search query
03103               nsCOMPtr<nsIRDFNode> lastTarget;
03104               if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref,
03105                      PR_TRUE, getter_AddRefs(lastTarget))) && (rv != NS_RDF_NO_VALUE))
03106               {
03107                      nsCOMPtr<nsIRDFLiteral>     lastLiteral (do_QueryInterface(lastTarget));
03108                      if (lastLiteral)
03109                      {
03110                             rv = mInner->Unassert(kNC_LastSearchRoot, kNC_Ref, lastLiteral);
03111                      }
03112               }
03113        }
03114 
03115        return(NS_OK);
03116 }
03117 
03118 
03119 
03120 NS_IMETHODIMP
03121 InternetSearchDataSource::ClearResultSearchSites(void)
03122 {
03123        // forget about any previous search sites
03124 
03125        if (mInner)
03126        {
03127               nsresult                    rv;
03128               nsCOMPtr<nsISimpleEnumerator>      arcs;
03129               if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_SearchResultsSitesRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs))))
03130               {
03131                      PRBool               hasMore = PR_TRUE;
03132       while (hasMore)
03133                      {
03134         if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
03135                                    break;
03136                             nsCOMPtr<nsISupports>       arc;
03137                             if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
03138                                    break;
03139                             nsCOMPtr<nsIRDFResource> child (do_QueryInterface(arc));
03140                             if (child)
03141                             {
03142                                    mInner->Unassert(kNC_SearchResultsSitesRoot, kNC_Child, child);
03143                             }
03144                      }
03145               }
03146        }
03147        return(NS_OK);
03148 }
03149 
03150 
03151 
03152 NS_IMETHODIMP
03153 InternetSearchDataSource::GetCategoryDataSource(nsIRDFDataSource **ds)
03154 {
03155        nsresult      rv;
03156 
03157        if (!categoryDataSource)
03158        {
03159               if (NS_FAILED(rv = GetCategoryList()))
03160               {
03161                      *ds = nsnull;
03162                      return(rv);
03163               }
03164        }
03165        if (categoryDataSource)
03166        {
03167               *ds = categoryDataSource.get();
03168               NS_IF_ADDREF(*ds);
03169               return(NS_OK);
03170        }
03171        *ds = nsnull;
03172        return(NS_ERROR_FAILURE);
03173 }
03174 
03175 
03176 
03177 NS_IMETHODIMP
03178 InternetSearchDataSource::Stop()
03179 {
03180        nsresult             rv;
03181 
03182        // cancel any outstanding connections
03183        if (mLoadGroup)
03184        {
03185               nsCOMPtr<nsISimpleEnumerator>      requests;
03186               if (NS_SUCCEEDED(rv = mLoadGroup->GetRequests(getter_AddRefs(requests))))
03187               {
03188                      PRBool               more;
03189       while (NS_SUCCEEDED(rv = requests->HasMoreElements(&more)) && more)
03190                      {
03191                             nsCOMPtr<nsISupports>       isupports;
03192                             if (NS_FAILED(rv = requests->GetNext(getter_AddRefs(isupports))))
03193                                    break;
03194                             nsCOMPtr<nsIRequest> request (do_QueryInterface(isupports));
03195                             if (!request) continue;
03196                             request->Cancel(NS_BINDING_ABORTED);
03197                      }
03198               }
03199               mLoadGroup->Cancel(NS_BINDING_ABORTED);
03200        }
03201 
03202        // remove any loading icons
03203        nsCOMPtr<nsISimpleEnumerator>      arcs;
03204        if (NS_SUCCEEDED(rv = mInner->GetSources(kNC_loading, kTrueLiteral, PR_TRUE,
03205               getter_AddRefs(arcs))))
03206        {
03207               PRBool               hasMore = PR_TRUE;
03208     while (hasMore)
03209               {
03210       if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore)
03211                             break;
03212                      nsCOMPtr<nsISupports>       arc;
03213                      if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc))))
03214                             break;
03215                      nsCOMPtr<nsIRDFResource> src (do_QueryInterface(arc));
03216                      if (src)
03217                      {
03218                             mInner->Unassert(src, kNC_loading, kTrueLiteral);
03219                      }
03220               }
03221        }
03222 
03223        return(NS_OK);
03224 }
03225 
03226 
03227 
03228 nsresult
03229 InternetSearchDataSource::BeginSearchRequest(nsIRDFResource *source, PRBool doNetworkRequest)
03230 {
03231         nsresult            rv = NS_OK;
03232        const char           *sourceURI = nsnull;
03233 
03234        if (NS_FAILED(rv = source->GetValueConst(&sourceURI)))
03235               return(rv);
03236        nsAutoString         uri;
03237        uri.AssignWithConversion(sourceURI);
03238 
03239        if (uri.Find("internetsearch:") != 0)
03240               return(NS_ERROR_FAILURE);
03241 
03242        // forget about any previous search results
03243        ClearResults(PR_TRUE);
03244 
03245        // forget about any previous search sites
03246        ClearResultSearchSites();
03247 
03248        // remember the last search query
03249        const PRUnichar      *uriUni = uri.get();
03250        nsCOMPtr<nsIRDFLiteral>     uriLiteral;
03251        if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(uriUni, getter_AddRefs(uriLiteral))))
03252        {
03253               rv = mInner->Assert(kNC_LastSearchRoot, kNC_Ref, uriLiteral, PR_TRUE);
03254        }
03255 
03256        uri.Cut(0, strlen("internetsearch:"));
03257 
03258        nsVoidArray   *engineArray = new nsVoidArray;
03259        if (!engineArray)
03260               return(NS_ERROR_FAILURE);
03261 
03262        nsAutoString  text;
03263 
03264        // parse up attributes
03265 
03266        while(!uri.IsEmpty())
03267        {
03268               nsAutoString  item;
03269 
03270               PRInt32 andOffset = uri.Find("&");
03271               if (andOffset >= 0)
03272               {
03273                      uri.Left(item, andOffset);
03274                      uri.Cut(0, andOffset + 1);
03275               }
03276               else
03277               {
03278                      item = uri;
03279                      uri.Truncate();
03280               }
03281 
03282               PRInt32 equalOffset = item.Find("=");
03283               if (equalOffset < 0) break;
03284               
03285               nsAutoString  attrib, value;
03286               item.Left(attrib, equalOffset);
03287               value = item;
03288               value.Cut(0, equalOffset + 1);
03289               
03290               if (!attrib.IsEmpty() && !value.IsEmpty())
03291               {
03292                      if (attrib.LowerCaseEqualsLiteral("engine"))
03293                      {
03294                             if ((value.Find(kEngineProtocol) == 0) ||
03295                                    (value.Find(kURINC_SearchCategoryEnginePrefix) == 0))
03296                             {
03297                                    char   *val = ToNewCString(value);
03298                                    if (val)
03299                                    {
03300                                           engineArray->AppendElement(val);
03301                                    }
03302                             }
03303                      }
03304                      else if (attrib.LowerCaseEqualsLiteral("text"))
03305                      {
03306                             text = value;
03307                      }
03308               }
03309        }
03310 
03311        mInner->Assert(source, kNC_loading, kTrueLiteral, PR_TRUE);
03312 
03313        PRBool requestInitiated = PR_FALSE;
03314 
03315        // loop over specified search engines
03316        while (engineArray->Count() > 0)
03317        {
03318               char *baseFilename = (char *)(engineArray->ElementAt(0));
03319               engineArray->RemoveElementAt(0);
03320               if (!baseFilename)   continue;
03321 
03322 #ifdef DEBUG_SEARCH_OUTPUT
03323               printf("Search engine to query: '%s'\n", baseFilename);
03324 #endif
03325 
03326               nsCOMPtr<nsIRDFResource>    engine;
03327               gRDFService->GetResource(nsDependentCString(baseFilename), getter_AddRefs(engine));
03328               nsCRT::free(baseFilename);
03329               baseFilename = nsnull;
03330               if (!engine)  continue;
03331 
03332               // if its a engine from a search category, then get its "#Name",
03333               // and map from that back to the real engine reference; if an
03334               // error occurs, finish processing the rest of the engines,
03335               // don't just break/return out
03336               if (isSearchCategoryEngineURI(engine))
03337               {
03338                      nsCOMPtr<nsIRDFResource>    trueEngine;
03339                      rv = resolveSearchCategoryEngineURI(engine, getter_AddRefs(trueEngine));
03340                      if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
03341                      if (!trueEngine)     continue;
03342 
03343                      engine = trueEngine;
03344               }
03345 
03346               // mark this as a search site
03347               if (mInner)
03348               {
03349                      mInner->Assert(kNC_SearchResultsSitesRoot, kNC_Child, engine, PR_TRUE);
03350               }
03351 
03352     if (doNetworkRequest)
03353               {
03354                      DoSearch(source, engine, EmptyString(), text);
03355                      requestInitiated = PR_TRUE;
03356               }
03357        }
03358        
03359        delete engineArray;
03360        engineArray = nsnull;
03361 
03362   if (!requestInitiated)
03363        {
03364               Stop();
03365        }
03366 
03367        return(rv);
03368 }
03369 
03370 
03371 
03372 nsresult
03373 InternetSearchDataSource::FindData(nsIRDFResource *engine, nsIRDFLiteral **dataLit)
03374 {
03375        if (!engine)  return(NS_ERROR_NULL_POINTER);
03376        if (!dataLit) return(NS_ERROR_NULL_POINTER);
03377 
03378        *dataLit = nsnull;
03379 
03380        if (!mInner)  return(NS_RDF_NO_VALUE);
03381 
03382        nsresult             rv;
03383 
03384        nsCOMPtr<nsIRDFNode> dataTarget = nsnull;
03385        if (NS_SUCCEEDED((rv = mInner->GetTarget(engine, kNC_Data, PR_TRUE,
03386               getter_AddRefs(dataTarget)))) && (dataTarget))
03387        {
03388               nsCOMPtr<nsIRDFLiteral>     aLiteral (do_QueryInterface(dataTarget));
03389               if (!aLiteral)
03390                      return(NS_ERROR_UNEXPECTED);
03391               *dataLit = aLiteral;
03392               NS_IF_ADDREF(*dataLit);
03393               return(NS_OK);
03394        }
03395 
03396         nsCOMPtr<nsILocalFile> engineFile;
03397         rv = EngineFileFromResource(engine, getter_AddRefs(engineFile));
03398         if (NS_FAILED(rv)) return rv;
03399 
03400         nsString     data;
03401         rv = ReadFileContents(engineFile, data);
03402 
03403        if (NS_FAILED(rv))
03404        {
03405               return(rv);
03406        }
03407 
03408        // save file contents
03409        if (data.IsEmpty())  return(NS_ERROR_UNEXPECTED);
03410 
03411        rv = updateDataHintsInGraph(engine, data.get());
03412 
03413        nsCOMPtr<nsIRDFLiteral>     aLiteral;
03414        if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(data.get(), getter_AddRefs(aLiteral))))
03415        {
03416               *dataLit = aLiteral;
03417               NS_IF_ADDREF(*dataLit);
03418        }
03419        
03420        return(rv);
03421 }
03422 
03423 nsresult
03424 InternetSearchDataSource::EngineFileFromResource(nsIRDFResource *aResource,
03425                                                  nsILocalFile **aResult)
03426 {
03427   nsresult rv = NS_OK;
03428 
03429   // get resource uri
03430   const char *engineURI = nsnull;
03431   rv = aResource->GetValueConst(&engineURI);
03432   NS_ENSURE_SUCCESS(rv, rv);
03433 
03434   // remove protocol from uri and get escaped file path
03435   nsCAutoString nativePath;
03436   nativePath.Assign(engineURI);
03437 
03438   NS_ENSURE_TRUE(StringBeginsWith(nativePath,
03439                                   NS_LITERAL_CSTRING(kEngineProtocol)),
03440                  NS_ERROR_FAILURE);
03441   nativePath.Cut(0, sizeof(kEngineProtocol) - 1);
03442 
03443   // unescape it
03444   NS_UnescapeURL(nativePath);
03445 
03446 #ifdef DEBUG_SEARCH_OUTPUT
03447   printf("InternetSearchDataSource::EngineFileFromResource\n"
03448          "File Path: %s\n",
03449          nativePath.get());
03450 #endif
03451 
03452   rv = NS_NewNativeLocalFile(nativePath, PR_TRUE, aResult);
03453 
03454   return rv;
03455 }
03456 
03457 nsresult
03458 InternetSearchDataSource::DecodeData(const char *aCharset, const PRUnichar *aInString, PRUnichar **aOutString)
03459 {
03460        nsresult rv;
03461     
03462        nsCOMPtr <nsICharsetConverterManager> charsetConv = 
03463           do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
03464        NS_ENSURE_SUCCESS(rv, rv);
03465 
03466        nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
03467        rv = charsetConv->GetUnicodeDecoder(aCharset, getter_AddRefs(unicodeDecoder));
03468 
03469        // Use the sherlock default charset in case of failure
03470        if (NS_FAILED(rv))
03471               rv = charsetConv->GetUnicodeDecoderRaw("x-mac-roman", getter_AddRefs(unicodeDecoder));
03472        NS_ENSURE_SUCCESS(rv, rv);
03473 
03474        // This fixes the corruption occured in InternetSearchDataSource::ReadFileContents()
03475        // (eg. aValue contains "0x0082 0x00a1" for "0x82 0xa1" shift_jis double-byte char)
03476        NS_LossyConvertUCS2toASCII value(aInString);
03477 
03478        PRInt32 srcLength = value.Length();
03479        PRInt32 outUnicodeLen;
03480        rv = unicodeDecoder->GetMaxLength(value.get(), srcLength, &outUnicodeLen);
03481        NS_ENSURE_SUCCESS(rv, rv);
03482 
03483        *aOutString = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc((outUnicodeLen + 1) * sizeof(PRUnichar)));
03484        NS_ENSURE_TRUE(*aOutString, NS_ERROR_OUT_OF_MEMORY);
03485 
03486        rv = unicodeDecoder->Convert(value.get(), &srcLength, *aOutString, &outUnicodeLen);
03487        NS_ENSURE_SUCCESS(rv, rv);
03488        (*aOutString)[outUnicodeLen] = (PRUnichar)'\0';
03489 
03490        return rv;
03491 }
03492 
03493 nsresult
03494 InternetSearchDataSource::updateDataHintsInGraph(nsIRDFResource *engine, const PRUnichar *dataUni)
03495 {
03496        nsresult      rv = NS_OK;
03497 
03498        // save/update search engine data
03499        nsCOMPtr<nsIRDFLiteral>     dataLiteral;
03500        if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(dataUni, getter_AddRefs(dataLiteral))))
03501        {
03502               updateAtom(mInner, engine, kNC_Data, dataLiteral, nsnull);
03503        }
03504 
03505        // save/update name of search engine (as specified in file)
03506        nsAutoString scriptCodeValue;
03507        const char * charsetName = MapScriptCodeToCharsetName(0);
03508        nsXPIDLString decodedValue;
03509 
03510        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "sourceTextEncoding", scriptCodeValue)) && 
03511               !scriptCodeValue.IsEmpty())
03512        {
03513               PRInt32 err;
03514               PRInt32 scriptCode = scriptCodeValue.ToInteger(&err);
03515               if (NS_SUCCEEDED(err))
03516                      charsetName = MapScriptCodeToCharsetName(scriptCode);
03517        }
03518 
03519        nsAutoString  nameValue;
03520        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "name", nameValue)))
03521        {
03522               rv = DecodeData(charsetName, nameValue.get(), getter_Copies(decodedValue));
03523               nsCOMPtr<nsIRDFLiteral>     nameLiteral;
03524               if (NS_SUCCEEDED(rv) &&
03525                             NS_SUCCEEDED(rv = gRDFService->GetLiteral(decodedValue.get(),
03526                                                                       getter_AddRefs(nameLiteral))))
03527               {
03528                      rv = updateAtom(mInner, engine, kNC_Name, nameLiteral, nsnull);
03529               }
03530        }
03531 
03532        // save/update description of search engine (if specified)
03533        nsAutoString  descValue;
03534        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "description", descValue)))
03535        {
03536               rv = DecodeData(charsetName, descValue.get(), getter_Copies(decodedValue));
03537               nsCOMPtr<nsIRDFLiteral>     descLiteral;
03538               if (NS_SUCCEEDED(rv) &&
03539                             NS_SUCCEEDED(rv = gRDFService->GetLiteral(decodedValue.get(),
03540                                                                       getter_AddRefs(descLiteral))))
03541               {
03542                      rv = updateAtom(mInner, engine, kNC_Description, descLiteral, nsnull);
03543               }
03544        }
03545 
03546        // save/update version of search engine (if specified)
03547        nsAutoString  versionValue;
03548        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "version", versionValue)))
03549        {
03550               nsCOMPtr<nsIRDFLiteral>     versionLiteral;
03551               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(versionValue.get(),
03552                             getter_AddRefs(versionLiteral))))
03553               {
03554                      rv = updateAtom(mInner, engine, kNC_Version, versionLiteral, nsnull);
03555               }
03556        }
03557 
03558        nsAutoString  buttonValue;
03559        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "actionButton", buttonValue)))
03560        {
03561               nsCOMPtr<nsIRDFLiteral>     buttonLiteral;
03562               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(buttonValue.get(),
03563                             getter_AddRefs(buttonLiteral))))
03564               {
03565                      rv = updateAtom(mInner, engine, kNC_actionButton, buttonLiteral, nsnull);
03566               }
03567        }
03568 
03569        nsAutoString  barValue;
03570        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "actionBar", barValue)))
03571        {
03572               nsCOMPtr<nsIRDFLiteral>     barLiteral;
03573               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(barValue.get(),
03574                             getter_AddRefs(barLiteral))))
03575               {
03576                      rv = updateAtom(mInner, engine, kNC_actionBar, barLiteral, nsnull);
03577               }
03578        }
03579 
03580        nsAutoString  searchFormValue;
03581        if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "searchForm", searchFormValue)))
03582        {
03583               nsCOMPtr<nsIRDFLiteral>     searchFormLiteral;
03584               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(searchFormValue.get(),
03585                             getter_AddRefs(searchFormLiteral))))
03586               {
03587                      rv = updateAtom(mInner, engine, kNC_searchForm, searchFormLiteral, nsnull);
03588               }
03589        }
03590 
03591 
03592        PRBool updatePrivateFiles = PR_FALSE;
03593 
03594   rv = mInner->HasAssertion(engine, kNC_SearchType, kNC_Engine, PR_TRUE,
03595                             &updatePrivateFiles);
03596   if (NS_SUCCEEDED(rv) && updatePrivateFiles)
03597        {
03598               // rjc says: so here is our strategy. The spec says that the "search"|"update"
03599               // attribute MUST refer to a binhex-ed file (i.e. ends with ".src.hqx"). We don't
03600               // support binhex (due to being cross-platform minded folks) and, even if we did,
03601               // its not enough info to figure out what the appropriate icon should be.
03602               // The answer: we're add additional attributes in our private <BROWSER> section
03603               // to re-define these values. If they aren't there, we'll fallback to the <SEARCH>
03604               // section values and try and make logical choices:  for example, if we have an
03605               // "update" URL which ends with ".src.hqx", we'll strip off the ".hqx" part and
03606               // check to see if it exists... which at least makes it possible for a web site
03607               // to put up both a binhexed version and a straight text version of the search file.
03608 
03609               // get update URL and # of days to check for updates
03610               // Note: only check for updates on our private search files
03611               nsAutoString  updateStr, updateIconStr, updateCheckDaysStr;
03612 
03613               GetData(dataUni, "browser", 0, "update", updateStr);
03614               if (updateStr.IsEmpty())
03615               {
03616                      // fallback to trying "search"|"updateCheckDays"
03617                      GetData(dataUni, "search", 0, "update", updateStr);
03618 
03619                      // if we have a ".hqx" extension, strip it off
03620                      nsAutoString  extension;
03621                      updateStr.Right(extension, 4);
03622                      if (extension.LowerCaseEqualsLiteral(".hqx"))
03623                      {
03624                             updateStr.Truncate(updateStr.Length() - 4);
03625                      }
03626 
03627                      // now, either way, ensure that we have a ".src" file
03628                      updateStr.Right(extension, 4);
03629       if (!extension.LowerCaseEqualsLiteral(".src"))
03630                      {
03631                             // and if we don't, toss it
03632                             updateStr.Truncate();
03633                      }
03634               }
03635               else
03636               {
03637                      // note: its OK if the "updateIcon" isn't specified
03638                      GetData(dataUni, "browser", 0, "updateIcon", updateIconStr);
03639               }
03640               if (!updateStr.IsEmpty())
03641               {
03642                      GetData(dataUni, "browser", 0, "updateCheckDays", updateCheckDaysStr);
03643                      if (updateCheckDaysStr.IsEmpty())
03644                      {
03645                             // fallback to trying "search"|"updateCheckDays"
03646                             GetData(dataUni, "search", 0, "updateCheckDays", updateCheckDaysStr);
03647                      }
03648               }
03649 
03650               if (!updateStr.IsEmpty() && !updateCheckDaysStr.IsEmpty())
03651               {
03652                      nsCOMPtr<nsIRDFLiteral>     updateLiteral;
03653                      if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(updateStr.get(),
03654                                    getter_AddRefs(updateLiteral))))
03655                      {
03656                             rv = updateAtom(mInner, engine, kNC_Update, updateLiteral, nsnull);
03657                      }
03658 
03659                      PRInt32       err;
03660                      PRInt32       updateDays = updateCheckDaysStr.ToInteger(&err);
03661                      if ((err) || (updateDays < 1))
03662                      {
03663                             // default to something sane
03664                             updateDays = 3;
03665                      }
03666 
03667                      nsCOMPtr<nsIRDFInt>  updateCheckDaysLiteral;
03668                      if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral(updateDays,
03669                                    getter_AddRefs(updateCheckDaysLiteral))))
03670                      {
03671                             rv = updateAtom(mInner, engine, kNC_UpdateCheckDays, updateCheckDaysLiteral, nsnull);
03672                      }
03673 
03674                      if (!updateIconStr.IsEmpty())
03675                      {
03676                             nsCOMPtr<nsIRDFLiteral>     updateIconLiteral;
03677                             if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(updateIconStr.get(),
03678                                           getter_AddRefs(updateIconLiteral))))
03679                             {
03680                                    rv = updateAtom(mInner, engine, kNC_UpdateIcon, updateIconLiteral, nsnull);
03681                             }
03682                      }
03683               }
03684        }
03685 
03686        return(rv);
03687 }
03688 
03689 
03690 
03691 nsresult
03692 InternetSearchDataSource::updateAtom(nsIRDFDataSource *db, nsIRDFResource *src,
03693                      nsIRDFResource *prop, nsIRDFNode *newValue, PRBool *dirtyFlag)
03694 {
03695        nsresult             rv;
03696        nsCOMPtr<nsIRDFNode> oldValue;
03697 
03698        if (dirtyFlag != nsnull)
03699        {
03700               *dirtyFlag = PR_FALSE;
03701        }
03702 
03703        if (NS_SUCCEEDED(rv = db->GetTarget(src, prop, PR_TRUE, getter_AddRefs(oldValue))) &&
03704               (rv != NS_RDF_NO_VALUE))
03705        {
03706               rv = db->Change(src, prop, oldValue, newValue);
03707 
03708               if ((oldValue.get() != newValue) && (dirtyFlag != nsnull))
03709               {
03710                      *dirtyFlag = PR_TRUE;
03711               }
03712        }
03713        else
03714        {
03715               rv = db->Assert(src, prop, newValue, PR_TRUE);
03716               if (dirtyFlag != nsnull)
03717               {
03718                   *dirtyFlag = PR_TRUE;
03719               }
03720        }
03721        return(rv);
03722 }
03723 
03724 
03725 
03726 struct encodings
03727 {
03728        const char    *numericEncoding;
03729        const char    *stringEncoding;
03730 };
03731 
03732 
03733 
03734 nsresult
03735 InternetSearchDataSource::MapEncoding(const nsString &numericEncoding, 
03736                                       nsString &stringEncoding)
03737 {
03738        // XXX we need to have a full table of numeric --> string conversions
03739 
03740        struct encodings     encodingList[] =
03741        {
03742               {      "0", "x-mac-roman"   },
03743               {      "6", "x-mac-greek"   },
03744               {      "35", "x-mac-turkish"       },
03745               {      "513", "ISO-8859-1"  },
03746               {      "514", "ISO-8859-2"  },
03747               {      "517", "ISO-8859-5"  },
03748               {      "518", "ISO-8859-6"  },
03749               {      "519", "ISO-8859-7"  },
03750               {      "520", "ISO-8859-8"  },
03751               {      "521", "ISO-8859-9"  },
03752               {      "1049", "IBM864"     },
03753               {      "1280", "windows-1252"      },
03754               {      "1281", "windows-1250"      },
03755               {      "1282", "windows-1251"      },
03756               {      "1283", "windows-1253"      },
03757               {      "1284", "windows-1254"      },
03758               {      "1285", "windows-1255"      },
03759               {      "1286", "windows-1256"      },
03760               {      "1536", "us-ascii"   },
03761               {      "1584", "GB2312"     },
03762               {      "1585", "x-gbk"             },
03763               {      "1600", "EUC-KR"     },
03764               {      "2080", "ISO-2022-JP"       },
03765               {      "2096", "ISO-2022-CN"       },
03766               {      "2112", "ISO-2022-KR"       },
03767               {      "2336", "EUC-JP"     },
03768               {      "2352", "GB2312"     },
03769               {      "2353", "x-euc-tw"   },
03770               {      "2368", "EUC-KR"     },
03771               {      "2561", "Shift_JIS"  },
03772               {      "2562", "KOI8-R"     },
03773               {      "2563", "Big5"              },
03774               {      "2565", "HZ-GB-2312" },
03775 
03776               {      nsnull, nsnull              }
03777        };
03778 
03779   if (!numericEncoding.IsEmpty())  {
03780     for (PRUint32 i = 0; encodingList[i].numericEncoding != nsnull; i++)
03781     {
03782       if (numericEncoding.EqualsASCII(encodingList[i].numericEncoding)) 
03783       {
03784         stringEncoding.AssignASCII(encodingList[i].stringEncoding);
03785         return NS_OK;
03786       }
03787     }
03788   }
03789 
03790   // Still no encoding, fall back to default charset if possible
03791   nsXPIDLString defCharset;
03792   nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
03793   if (prefs)
03794     prefs->GetLocalizedUnicharPref("intl.charset.default", getter_Copies(defCharset));
03795 
03796   if (!defCharset.IsEmpty())
03797     stringEncoding = defCharset;
03798   else
03799     // make "ISO-8859-1" as the default (not "UTF-8")
03800     stringEncoding.AssignLiteral("ISO-8859-1");
03801 
03802   return(NS_OK);
03803 }
03804 
03805 
03806 
03807 const char * const
03808 InternetSearchDataSource::MapScriptCodeToCharsetName(PRUint32 aScriptCode)
03809 {
03810        // Script codes listed here are taken from Inside Macintosh Text.
03811        // Used TECGetTextEncodingInternetName to map script code to charset name.
03812        // Some are edited to match with standard name (e.g. "x-mac-japanese" -> "Shift_JIS").
03813        // In case no converter can be found for a charset name, 
03814        // the default sherlock charset "x-mac-roman" should be used.
03815        // 
03816         static const char* const scriptList[] =
03817        {
03818               "x-mac-roman",           // 0
03819               "Shift_JIS",             // 1
03820               "Big5",                  // 2
03821               "EUC-KR",                // 3
03822               "X-MAC-ARABIC",          // 4
03823               "X-MAC-HEBREW",          // 5
03824               "X-MAC-GREEK",           // 6
03825               "X-MAC-CYRILLIC",        // 7
03826               "X-MAC-DEVANAGARI" ,     // 9
03827               "X-MAC-GURMUKHI",        // 10
03828               "X-MAC-GUJARATI",        // 11
03829               "X-MAC-ORIYA",           // 12
03830               "X-MAC-BENGALI",         // 13
03831               "X-MAC-TAMIL",           // 14
03832               "X-MAC-TELUGU",          // 15
03833               "X-MAC-KANNADA",         // 16
03834               "X-MAC-MALAYALAM",       // 17
03835               "X-MAC-SINHALESE",       // 18
03836               "X-MAC-BURMESE",         // 19
03837               "X-MAC-KHMER",           // 20
03838               "X-MAC-THAI",            // 21
03839               "X-MAC-LAOTIAN",         // 22
03840               "X-MAC-GEORGIAN",        // 23
03841               "X-MAC-ARMENIAN",        // 24
03842               "GB2312",                // 25
03843               "X-MAC-TIBETAN",         // 26
03844               "X-MAC-MONGOLIAN",       // 27
03845               "X-MAC-ETHIOPIC",        // 28
03846               "X-MAC-CENTRALEURROMAN", // 29
03847               "X-MAC-VIETNAMESE",      // 30
03848               "X-MAC-EXTARABIC",       // 31
03849        };
03850 
03851         if (aScriptCode >= NS_ARRAY_LENGTH(scriptList))
03852           aScriptCode = 0;
03853 
03854        return scriptList[aScriptCode];
03855 }
03856 
03857 
03858 nsresult
03859 InternetSearchDataSource::validateEngine(nsIRDFResource *engine)
03860 {
03861        nsresult      rv;
03862 
03863   // confirm whether the user wants to update plugins.
03864   nsCOMPtr<nsIPrefBranch>
03865     prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
03866   NS_ENSURE_SUCCESS(rv, rv);
03867 
03868   PRBool userAllowed = PR_TRUE;
03869   rv = prefBranch->GetBoolPref("browser.search.update", &userAllowed);
03870   // if the pref value is not set or wrong type, don't stop here.
03871   if (NS_SUCCEEDED(rv) && !userAllowed)
03872     return NS_OK;
03873 
03874 #ifdef DEBUG_SEARCH_UPDATES
03875        const char    *engineURI = nsnull;
03876        engine->GetValueConst(&engineURI);
03877 #endif
03878 
03879        // get the engines "updateCheckDays" value
03880        nsCOMPtr<nsIRDFNode> updateCheckDaysNode;
03881        rv = mInner->GetTarget(engine, kNC_UpdateCheckDays, PR_TRUE, getter_AddRefs(updateCheckDaysNode));
03882        if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE))    return(rv);
03883        nsCOMPtr<nsIRDFInt> updateCheckDaysLiteral (do_QueryInterface(updateCheckDaysNode));
03884        PRInt32              updateCheckDays;
03885        updateCheckDaysLiteral->GetValue(&updateCheckDays);
03886        // convert updateCheckDays from days to seconds;
03887 
03888 #ifndef       DEBUG_SEARCH_UPDATES
03889        PRInt32              updateCheckSecs = updateCheckDays * (60 * 60 * 24);
03890 #else
03891        // rjc note: for debugging, use as minutes instead days
03892        PRInt32              updateCheckSecs = updateCheckDays * 60;
03893 #endif
03894 
03895        nsCOMPtr<nsIRDFNode> aNode;
03896        rv = mLocalstore->GetTarget(engine, kWEB_LastPingDate, PR_TRUE, getter_AddRefs(aNode));
03897        if (NS_FAILED(rv))   return(rv);
03898 
03899   // if aNode is a valid entry, we should check the durationSecs.
03900   if (rv != NS_RDF_NO_VALUE) {
03901     // get last validate date/time
03902     nsCOMPtr<nsIRDFLiteral> lastCheckLiteral(do_QueryInterface(aNode));
03903     if (!lastCheckLiteral)
03904       return NS_ERROR_UNEXPECTED;
03905 
03906     const PRUnichar *lastCheckUni = nsnull;
03907     lastCheckLiteral->GetValueConst(&lastCheckUni);
03908     if (!lastCheckUni)
03909       return NS_ERROR_UNEXPECTED;
03910 
03911     PRInt32 lastCheckInt = 0, err = 0;
03912     lastCheckInt = nsDependentString(lastCheckUni).ToInteger(&err);
03913     // signed int32 -> unsigned int32
03914     rv = (nsresult) err;
03915     NS_ENSURE_SUCCESS(rv, rv);
03916 
03917     // get the current date/time [from microseconds (PRTime) to seconds]
03918     PRTime now64 = PR_Now(), temp64, million;
03919     LL_I2L(million, PR_USEC_PER_SEC);
03920     LL_DIV(temp64, now64, million);
03921     PRInt32 now32;
03922     LL_L2I(now32, temp64);
03923 
03924     // calculate duration since last validation
03925     // just return if it's too early to check again
03926     PRInt32 durationSecs = now32 - lastCheckInt;
03927 
03928     if (durationSecs < updateCheckSecs) {
03929 #ifdef DEBUG_SEARCH_UPDATES
03930       printf("    Search engine '%s' is valid for %d more seconds.\n",
03931              engineURI, (updateCheckSecs-durationSecs));
03932 #endif
03933       return NS_OK;
03934     }
03935   }
03936 
03937        // search engine needs to be checked again, so add it into the to-be-validated array
03938        PRInt32              elementIndex = mUpdateArray->IndexOf(engine);
03939        if (elementIndex < 0)
03940        {
03941               mUpdateArray->AppendElement(engine);
03942 
03943 #ifdef DEBUG_SEARCH_UPDATES
03944     printf("    Search engine '%s' is now queued to be validated"
03945            " via HTTP HEAD method.\n",
03946            engineURI);
03947 #endif
03948        }
03949        else
03950        {
03951 #ifdef DEBUG_SEARCH_UPDATES
03952               printf("    Search engine '%s' is already in queue to be validated.\n",
03953                      engineURI);
03954 #endif
03955        }
03956        return(NS_OK);
03957 }
03958 
03959 
03960 
03961 nsresult
03962 InternetSearchDataSource::DoSearch(nsIRDFResource *source, nsIRDFResource *engine,
03963                             const nsString &fullURL, const nsString &text)
03964 {
03965        nsresult      rv;
03966        nsAutoString  textTemp(text);
03967 
03968        if (!mInner)  return(NS_RDF_NO_VALUE);
03969 //     Note: source can be null
03970 //     if (!source)  return(NS_ERROR_NULL_POINTER);
03971        if (!engine)  return(NS_ERROR_NULL_POINTER);
03972 
03973        validateEngine(engine);
03974 
03975        nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
03976        nsAutoString                action, methodStr, input, userVar;
03977 
03978        nsCOMPtr<nsIRDFLiteral>            dataLit;
03979        if (NS_FAILED(rv = FindData(engine, getter_AddRefs(dataLit))) ||
03980               (rv == NS_RDF_NO_VALUE))    return(rv);
03981 
03982        const PRUnichar                    *dataUni = nsnull;
03983        dataLit->GetValueConst(&dataUni);
03984        if (!dataUni)               return(NS_RDF_NO_VALUE);
03985 
03986        if (!fullURL.IsEmpty())
03987        {
03988               action.Assign(fullURL);
03989               methodStr.AssignLiteral("get");
03990        }
03991        else
03992        {
03993               if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action)))  return(rv);
03994               if (NS_FAILED(rv = GetData(dataUni, "search", 0, "method", methodStr)))      return(rv);
03995        }
03996 
03997        nsAutoString  encodingStr, resultEncodingStr;
03998 
03999        // first look for "interpret/charset"... if that isn't specified,
04000        // then fall back to looking for "interpret/resultEncoding" (a decimal)
04001        GetData(dataUni, "interpret", 0, "charset", resultEncodingStr);
04002        if (resultEncodingStr.IsEmpty())
04003        {
04004               GetData(dataUni, "interpret", 0, "resultEncoding", encodingStr);      // decimal string values
04005               MapEncoding(encodingStr, resultEncodingStr);
04006        }
04007        // rjc note: ignore "interpret/resultTranslationEncoding" as well as
04008        // "interpret/resultTranslationFont" since we always convert results to Unicode
04009        if (!resultEncodingStr.IsEmpty())
04010        {
04011               nsCOMPtr <nsICharsetConverterManager> charsetConv = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
04012               if (NS_SUCCEEDED(rv))
04013               {
04014                   NS_LossyConvertUCS2toASCII charset(resultEncodingStr);
04015                   rv = charsetConv->GetUnicodeDecoder(charset.get(),
04016                                                       getter_AddRefs(unicodeDecoder));
04017               }
04018        }
04019 
04020        // first look for "search/queryCharset"... if that isn't specified,
04021        // then fall back to looking for "search/queryEncoding" (a decimal)
04022        nsAutoString    queryEncodingStr;
04023        GetData(dataUni, "search", 0, "queryCharset", queryEncodingStr);
04024        if (queryEncodingStr.IsEmpty())
04025        {
04026               GetData(dataUni, "search", 0, "queryEncoding", encodingStr);          // decimal string values
04027               MapEncoding(encodingStr, queryEncodingStr);
04028        }
04029        if (!queryEncodingStr.IsEmpty())
04030        {
04031               // convert from escaped-UTF_8, to unicode, and then to
04032               // the charset indicated by the dataset in question
04033 
04034               char   *utf8data = ToNewUTF8String(textTemp);
04035               if (utf8data)
04036               {
04037                      nsCOMPtr<nsITextToSubURI> textToSubURI = 
04038                               do_GetService(kTextToSubURICID, &rv);
04039                      if (NS_SUCCEEDED(rv) && (textToSubURI))
04040                      {
04041                             PRUnichar     *uni = nsnull;
04042                             if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert("UTF-8", utf8data, &uni)) && (uni))
04043                             {
04044                                    char          *charsetData = nsnull;
04045                                    nsCAutoString queryencodingstrC;
04046                                    queryencodingstrC.AssignWithConversion(queryEncodingStr);
04047                                    if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape(queryencodingstrC.get(), uni, &charsetData))
04048                                            && (charsetData))
04049                                    {
04050                                           textTemp.AssignWithConversion(charsetData);
04051                                           Recycle(charsetData);
04052                                    }
04053                                    Recycle(uni);
04054                             }
04055                      }
04056                      Recycle(utf8data);
04057               }
04058        }
04059 
04060        if (fullURL.IsEmpty() && methodStr.LowerCaseEqualsLiteral("get"))
04061        {
04062     nsAutoString engineNameStr;
04063        GetData(dataUni, "search", 0, "name", engineNameStr);
04064 
04065     if (NS_FAILED(rv = GetInputs(dataUni, engineNameStr, userVar, textTemp, input, 0, 0, 0)))  return(rv);
04066               if (input.IsEmpty())                      return(NS_ERROR_UNEXPECTED);
04067 
04068               // HTTP Get method support
04069               action += input;
04070        }
04071 
04072        nsCOMPtr<nsIInternetSearchContext> context;
04073        if (NS_FAILED(rv = NS_NewInternetSearchContext(nsIInternetSearchContext::WEB_SEARCH_CONTEXT,
04074               source, engine, unicodeDecoder, nsnull, getter_AddRefs(context))))
04075               return(rv);
04076        if (!context) return(NS_ERROR_UNEXPECTED);
04077 
04078        nsCOMPtr<nsIURI>     url;
04079        if (NS_SUCCEEDED(rv = NS_NewURI(getter_AddRefs(url), action)))
04080        {
04081               nsCOMPtr<nsIChannel> channel;
04082               if (NS_SUCCEEDED(rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull, mLoadGroup)))
04083               {
04084 
04085                      // send a "MultiSearch" header
04086                      nsCOMPtr<nsIHttpChannel> httpMultiChannel (do_QueryInterface(channel));
04087                      if (httpMultiChannel)
04088                      {
04089                 httpMultiChannel->SetRequestHeader(NS_LITERAL_CSTRING("MultiSearch"),
04090                                                    NS_LITERAL_CSTRING("true"),
04091                                                    PR_FALSE);
04092                      }
04093 
04094                      // get it just from the cache if we can (do not validate)
04095                      channel->SetLoadFlags(nsIRequest::LOAD_FROM_CACHE);
04096 
04097                      if (methodStr.LowerCaseEqualsLiteral("post"))
04098                      {
04099                             nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface(channel));
04100                             if (httpChannel)
04101                             {
04102                                 httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
04103                                 
04104                                 // construct post data to send
04105                                 nsAutoString     postStr;
04106                                 postStr.AssignASCII(POSTHEADER_PREFIX);
04107                                 postStr.AppendInt(input.Length(), 10);
04108                                 postStr.AppendASCII(POSTHEADER_SUFFIX);
04109                                 postStr += input;
04110                                 
04111                                 nsCOMPtr<nsIInputStream>       postDataStream;
04112                                 nsCAutoString                  poststrC;
04113                                 poststrC.AssignWithConversion(postStr);
04114                                 if (NS_SUCCEEDED(rv = NS_NewPostDataStream(getter_AddRefs(postDataStream),
04115                                                                       PR_FALSE, poststrC, 0)))
04116                                 {
04117                                    nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
04118                                    NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
04119                                    uploadChannel->SetUploadStream(postDataStream, EmptyCString(), -1);
04120                                 }
04121                             }
04122                      }
04123                      
04124                      nsCOMPtr<nsIRequest> request;
04125       rv = channel->AsyncOpen(this, context);
04126               }
04127        }
04128 
04129        // dispose of any last HTML results page
04130        if (mInner)
04131        {
04132               nsCOMPtr<nsIRDFNode> htmlNode;
04133               if (NS_SUCCEEDED(rv = mInner->GetTarget(engine, kNC_HTML, PR_TRUE, getter_AddRefs(htmlNode)))
04134                      && (rv != NS_RDF_NO_VALUE))
04135               {
04136                      rv = mInner->Unassert(engine, kNC_HTML, htmlNode);
04137               }
04138        }
04139 
04140        // start "loading" animation for this search engine
04141        if (NS_SUCCEEDED(rv) && (mInner))
04142        {
04143               // remove status icon so that loading icon style can be used
04144               nsCOMPtr<nsIRDFNode>        engineIconNode = nsnull;
04145               mInner->GetTarget(engine, kNC_StatusIcon, PR_TRUE, getter_AddRefs(engineIconNode));
04146               if (engineIconNode)
04147               {
04148                      rv = mInner->Unassert(engine, kNC_StatusIcon, engineIconNode);
04149               }
04150 
04151               mInner->Assert(engine, kNC_loading, kTrueLiteral, PR_TRUE);
04152        }
04153 
04154        return(rv);
04155 }
04156 
04157 nsresult
04158 InternetSearchDataSource::SaveEngineInfoIntoGraph(nsIFile *file, nsIFile *icon,
04159                                                   const PRUnichar *categoryHint,
04160                                                   const PRUnichar *dataUni,
04161                                                   PRBool isSystemSearchFile)
04162 {
04163        nsresult                    rv = NS_OK;
04164 
04165        if (!file && !icon)  return(NS_ERROR_UNEXPECTED);
04166 
04167        nsCOMPtr<nsIRDFResource>    searchRes;
04168        nsCOMPtr<nsIRDFResource>    categoryRes;
04169        nsCOMPtr<nsIFile>           native;
04170 
04171        if (icon != nsnull)
04172        {
04173               native = icon;
04174        }
04175 
04176        if (file != nsnull)
04177        {
04178               native = file;
04179        }
04180 
04181   PRBool exists;
04182   rv = native->Exists(&exists);
04183        if (NS_FAILED(rv)) return(rv);
04184        if (!exists) return(NS_ERROR_UNEXPECTED);
04185 
04186        nsAutoString basename;
04187        rv = native->GetLeafName(basename);
04188        if (NS_FAILED(rv)) return rv;
04189 
04190        // ensure that the basename points to the search engine file
04191        PRInt32              extensionOffset;
04192        if ((extensionOffset = basename.RFindChar(PRUnichar('.'))) > 0)
04193        {
04194               basename.Truncate(extensionOffset);
04195               basename.AppendLiteral(".src");
04196        }
04197 
04198   nsCAutoString filePath;
04199   rv = native->GetNativePath(filePath);
04200   if (NS_FAILED(rv)) return rv;
04201   
04202        nsAutoString  searchURL;
04203        searchURL.AssignASCII(kEngineProtocol);
04204        char          *uriCescaped = nsEscape(filePath.get(), url_Path);
04205        if (!uriCescaped)    return(NS_ERROR_NULL_POINTER);
04206        searchURL.AppendASCII(uriCescaped);
04207        nsCRT::free(uriCescaped);
04208 
04209        if ((extensionOffset = searchURL.RFindChar(PRUnichar('.'))) > 0)
04210        {
04211               searchURL.Truncate(extensionOffset);
04212               searchURL.AppendLiteral(".src");
04213        }
04214 
04215        if (NS_FAILED(rv = gRDFService->GetUnicodeResource(searchURL,
04216               getter_AddRefs(searchRes))))       return(rv);
04217 
04218        // save the basename reference
04219        if (!basename.IsEmpty())
04220        {
04221               basename.Insert(NS_ConvertASCIItoUTF16(kURINC_SearchCategoryEngineBasenamePrefix), 0);
04222 
04223               if (NS_FAILED(rv = gRDFService->GetUnicodeResource(basename,
04224                      getter_AddRefs(categoryRes))))     return(rv);
04225 
04226               nsCOMPtr<nsIRDFLiteral>     searchLiteral;
04227               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(basename.get(),
04228                             getter_AddRefs(searchLiteral))))
04229               {
04230                      if (file)
04231                      {
04232                             updateAtom(mInner, searchRes, kNC_URL, searchLiteral, nsnull);
04233                      }
04234               }
04235        }
04236 
04237        if (!searchRes)             return(NS_ERROR_UNEXPECTED);
04238        if (!categoryRes)    return(NS_ERROR_UNEXPECTED);
04239 
04240        nsAutoString  iconURL;
04241        if (icon)
04242        {
04243               nsCAutoString iconFileURL;
04244               if (NS_FAILED(rv = NS_GetURLSpecFromFile(icon, iconFileURL)))
04245                      return(rv);
04246               AppendUTF8toUTF16(iconFileURL, iconURL);
04247        }
04248 
04249        // save icon url (if we have one)
04250        if (iconURL.Length() > 0)
04251        {
04252               nsCOMPtr<nsIRDFLiteral>     iconLiteral;
04253               if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(iconURL.get(),
04254                             getter_AddRefs(iconLiteral))))
04255               {
04256                      updateAtom(mInner, searchRes, kNC_Icon, iconLiteral, nsnull);
04257               }
04258        }
04259 
04260   if (!isSystemSearchFile)
04261        {
04262               // mark our private search files, so that we can distinguish
04263               // between ours and any that are included with the OS
04264               updateAtom(mInner, searchRes, kNC_SearchType, kNC_Engine, nsnull);
04265        }
04266 
04267        if (dataUni != nsnull)
04268        {
04269               updateDataHintsInGraph(searchRes, dataUni);
04270 
04271               // finally, if we have a category hint, add this new engine into the category (if it exists)
04272               if (categoryHint && categoryDataSource)
04273               {
04274                      nsCOMPtr<nsIRDFLiteral>     catLiteral;
04275                      rv = gRDFService->GetLiteral(categoryHint, getter_AddRefs(catLiteral));
04276 
04277                      nsCOMPtr<nsIRDFResource>    catSrc;
04278                      if (catLiteral)
04279                      {
04280                             rv = categoryDataSource->GetSource(kNC_Title, catLiteral,
04281                                    PR_TRUE, getter_AddRefs(catSrc));
04282                      }
04283 
04284                      const char           *catURI = nsnull;
04285                      if (catSrc)                               
04286                      {
04287                             rv = catSrc->GetValueConst(&catURI);
04288                      }
04289 
04290                      nsCOMPtr<nsIRDFResource>    catRes;
04291                      if (catURI)
04292                      {
04293                             nsAutoString  catList;
04294                             catList.AssignASCII(kURINC_SearchCategoryPrefix);
04295                             catList.AppendWithConversion(catURI);
04296                             gRDFService->GetUnicodeResource(catList, getter_AddRefs(catRes));
04297                      }
04298 
04299                      nsCOMPtr<nsIRDFContainer> container;
04300                      if (catRes)
04301                      {
04302                             container = do_CreateInstance(kRDFContainerCID, &rv);
04303                      }
04304                      if (container)
04305                      {
04306                             rv = container->Init(categoryDataSource, catRes);
04307                             if (NS_SUCCEEDED(rv))
04308                             {
04309                                    rv = gRDFC->MakeSeq(categoryDataSource, catRes, nsnull);
04310                             }
04311                             if (NS_SUCCEEDED(rv))
04312                             {
04313                                    PRInt32              searchIndex = -1;
04314                                    if (NS_SUCCEEDED(rv = container->IndexOf(categoryRes, &searchIndex))
04315                                           && (searchIndex < 0))
04316                                    {
04317                                           rv = container->AppendElement(categoryRes);
04318                                    }
04319                             }
04320                             if (NS_SUCCEEDED(rv))
04321                             {
04322                                    // flush categoryDataSource
04323                                    nsCOMPtr<nsIRDFRemoteDataSource>   remoteCategoryStore;
04324                                    remoteCategoryStore = do_QueryInterface(categoryDataSource);
04325                                    if (remoteCategoryStore)
04326                                    {
04327                                           remoteCategoryStore->Flush();
04328                                    }
04329                             }
04330                      }
04331               }
04332        }
04333 
04334        // Note: add the child relationship last
04335        PRBool hasChildFlag = PR_FALSE;
04336   rv = mInner->HasAssertion(kNC_SearchEngineRoot, kNC_Child, searchRes,
04337                             PR_TRUE, &hasChildFlag);
04338   if (NS_SUCCEEDED(rv) && !hasChildFlag)
04339        {
04340               mInner->Assert(kNC_SearchEngineRoot, kNC_Child, searchRes, PR_TRUE);
04341        }
04342 
04343        return(NS_OK);
04344 }
04345 
04346 nsresult
04347 InternetSearchDataSource::GetSearchEngineList(nsIFile *searchDir,
04348               PRBool isSystemSearchFile)
04349 {
04350         nsresult                   rv = NS_OK;
04351 
04352     if (!mInner)
04353     {
04354        return(NS_RDF_NO_VALUE);
04355     }
04356 
04357     PRBool hasMore = PR_FALSE;
04358     nsCOMPtr<nsISimpleEnumerator> dirIterator;
04359     rv = searchDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
04360     if (NS_FAILED(rv)) return rv;
04361 
04362     nsCOMPtr<nsIFile> dirEntry;
04363        while ((rv = dirIterator->HasMoreElements(&hasMore)) == NS_OK && hasMore)
04364        {
04365               rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
04366         if (NS_FAILED(rv))
04367           continue;
04368 
04369         // Ignore hidden files/directories
04370         PRBool isHidden;
04371         rv = dirEntry->IsHidden(&isHidden);
04372         if (NS_FAILED(rv) || isHidden)
04373           continue;
04374 
04375         PRBool isDirectory;
04376         rv = dirEntry->IsDirectory(&isDirectory);
04377         if (NS_FAILED(rv))
04378           continue;
04379         if (isDirectory)
04380         {
04381           GetSearchEngineList(dirEntry, isSystemSearchFile);
04382           continue;
04383         }
04384 
04385         // Skip over empty files
04386         // Note: use GetFileSize even on Mac [instead of GetFileSizeWithResFork()]
04387         // as we want the size of ONLY the data fork
04388         PRInt64 fileSize;
04389         rv = dirEntry->GetFileSize(&fileSize);
04390         if (NS_FAILED(rv) || (fileSize == 0))
04391             continue;
04392     
04393         nsAutoString uri;
04394         rv = dirEntry->GetPath(uri);
04395         if (NS_FAILED(rv))
04396         continue;
04397 
04398               PRInt32              len = uri.Length();
04399               if (len < 5)
04400               {
04401                      continue;
04402               }
04403 
04404               // check the extension (must be ".src")
04405               nsAutoString  extension;
04406               if ((uri.Right(extension, 4) != 4) || (!extension.LowerCaseEqualsLiteral(".src")))
04407               {
04408                      continue;
04409               }
04410 
04411               // check for various icons
04412               PRBool        foundIconFlag = PR_FALSE;
04413               nsAutoString  temp;
04414               
04415               nsCOMPtr<nsILocalFile> iconFile, loopFile;
04416 
04417                 static const char *extensions[] = {
04418                         ".gif",
04419                         ".jpg",
04420                         ".jpeg",
04421                         ".png",
04422                         nsnull,
04423                 };
04424 
04425                 for (int ext_count = 0; extensions[ext_count] != nsnull; ext_count++) {
04426                         temp = Substring(uri, 0, uri.Length()-4);
04427                         temp.Append(NS_ConvertASCIItoUCS2(extensions[ext_count]));
04428                         rv = NS_NewLocalFile(temp, PR_TRUE, getter_AddRefs(loopFile));
04429                         if (NS_FAILED(rv)) return rv;
04430                         rv = loopFile->Exists(&foundIconFlag);
04431                         if (NS_FAILED(rv)) return rv;
04432                         if (!foundIconFlag) continue;
04433                         rv = loopFile->IsFile(&foundIconFlag);
04434                         if (NS_FAILED(rv)) return rv;
04435                         if (foundIconFlag) 
04436                         {
04437                                 iconFile = loopFile;
04438                                 break;
04439                         } 
04440                 }
04441               
04442               SaveEngineInfoIntoGraph(dirEntry, iconFile, nsnull, nsnull, isSystemSearchFile);
04443        }
04444 
04445 #ifdef MOZ_PHOENIX
04446     if (!gReorderedEngineList)
04447       ReorderEngineList();
04448 #endif
04449        return(rv);
04450 }
04451 
04452 nsresult
04453 InternetSearchDataSource::ReadFileContents(nsILocalFile *localFile, nsString& sourceContents)
04454 {
04455        nsresult                    rv = NS_ERROR_FAILURE;
04456        PRInt64                            contentsLen, total = 0;
04457        char                        *contents;
04458 
04459         NS_ENSURE_ARG_POINTER(localFile);
04460 
04461         sourceContents.Truncate();
04462 
04463         rv = localFile->GetFileSize(&contentsLen);
04464         if (NS_FAILED(rv)) return rv;
04465         if (contentsLen > 0)
04466         {
04467                 contents = new char [contentsLen + 1];
04468                 if (contents)
04469                 {
04470                         nsCOMPtr<nsIInputStream> inputStream;
04471                         rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), localFile);
04472                         if (NS_FAILED(rv)) {
04473                             delete [] contents;
04474                             return rv;
04475                         }
04476                         PRUint32 howMany;
04477                         while (total < contentsLen) {
04478                                 rv = inputStream->Read(contents+total, 
04479                                                        PRUint32(contentsLen),
04480                                                        &howMany);
04481                                 if (NS_FAILED(rv)) {
04482                                         delete [] contents;
04483                                         return rv;
04484                                 }
04485                                 total += howMany;
04486                         }
04487                         if (total == contentsLen)
04488                       {
04489                             contents[contentsLen] = '\0';
04490                             sourceContents.AssignWithConversion(contents, contentsLen);
04491                             rv = NS_OK;
04492                       }
04493                      delete [] contents;
04494                      contents = nsnull;
04495               }
04496        }
04497        return(rv);
04498 }
04499 
04500 
04501 
04502 nsresult
04503 InternetSearchDataSource::GetNumInterpretSections(const PRUnichar *dataUni, PRUint32 &numInterpretSections)
04504 {
04505        numInterpretSections = 0;
04506 
04507        nsString      buffer(dataUni);
04508 
04509        NS_NAMED_LITERAL_STRING(section, "<interpret");
04510        PRBool        inSection = PR_FALSE;
04511 
04512        while(!buffer.IsEmpty())
04513        {
04514               PRInt32 eol = buffer.FindCharInSet("\r\n", 0);
04515               if (eol < 0)  break;
04516               nsAutoString  line;
04517               if (eol > 0)
04518               {
04519                      buffer.Left(line, eol);
04520               }
04521               buffer.Cut(0, eol+1);
04522               if (line.IsEmpty())  continue;            // skip empty lines
04523               if (line[0] == PRUnichar('#'))     continue;     // skip comments
04524               line.Trim(" \t");
04525     if (!inSection)
04526               {
04527                      PRInt32       sectionOffset = nsString_Find(section, line, PR_TRUE);
04528                      if (sectionOffset < 0)      continue;
04529                      line.Cut(0, sectionOffset + section.Length() + 1);
04530                      inSection = PR_TRUE;
04531                      ++numInterpretSections;                   // increment # of sections
04532               }
04533               line.Trim(" \t");
04534               PRInt32       len = line.Length();
04535               if (len > 0)
04536               {
04537                      if (line[len-1] == PRUnichar('>'))
04538                      {
04539                             inSection = PR_FALSE;
04540                             line.SetLength(len-1);
04541                      }
04542               }
04543        }
04544        return(NS_OK);
04545 }
04546 
04547 
04548 nsresult
04549 InternetSearchDataSource::GetData(const PRUnichar *dataUni, const char *sectionToFind, PRUint32 sectionNum,
04550                               const char *attribToFind, nsString &value)
04551 {
04552        nsString      buffer(dataUni);
04553 
04554        nsresult      rv = NS_RDF_NO_VALUE;
04555        PRBool        inSection = PR_FALSE;
04556 
04557        nsAutoString  section;
04558        section.AssignLiteral("<");
04559        section.AppendWithConversion(sectionToFind);
04560 
04561        while(!buffer.IsEmpty())
04562        {
04563               PRInt32 eol = buffer.FindCharInSet("\r\n", 0);
04564               if (eol < 0)  break;
04565               nsAutoString  line;
04566               if (eol > 0)
04567               {
04568                      buffer.Left(line, eol);
04569               }
04570               buffer.Cut(0, eol+1);
04571               if (line.IsEmpty())  continue;            // skip empty lines
04572               if (line[0] == PRUnichar('#'))     continue;     // skip comments
04573               line.Trim(" \t");
04574     if (!inSection)
04575               {
04576                      PRInt32       sectionOffset = nsString_Find(section, line, PR_TRUE);
04577                      if (sectionOffset < 0)      continue;
04578                      if (sectionNum > 0)
04579                      {
04580                             --sectionNum;
04581                             continue;
04582                      }
04583                      line.Cut(0, sectionOffset + section.Length() + 1);
04584                      inSection = PR_TRUE;
04585               }
04586               line.Trim(" \t");
04587               PRInt32       len = line.Length();
04588               if (len > 0)
04589               {
04590                      if (line[len-1] == PRUnichar('>'))
04591                      {
04592                             inSection = PR_FALSE;
04593                             line.SetLength(len-1);
04594                      }
04595               }
04596               PRInt32 equal = line.FindChar(PRUnichar('='));
04597               if (equal < 0)       continue;                   // skip lines with no equality
04598               
04599               nsAutoString  attrib;
04600               if (equal > 0)
04601               {
04602                      line.Left(attrib, equal /* - 1 */);
04603               }
04604               attrib.Trim(" \t");
04605               if (attrib.EqualsIgnoreCase(attribToFind))
04606               {
04607                      line.Cut(0, equal+1);
04608                      line.Trim(" \t");
04609                      value = line;
04610 
04611                      // strip of any enclosing quotes and trailing comments
04612                      if ((value[0] == PRUnichar('\"')) || (value[0] == PRUnichar('\'')))
04613                      {
04614                             PRUnichar quoteChar = value[0];
04615                             value.Cut(0,1);
04616                             if (!value.IsEmpty())
04617                             {
04618                                    PRInt32 quoteEnd = value.FindChar(quoteChar);
04619                                    if (quoteEnd >= 0)
04620                                    {
04621                                           value.Truncate(quoteEnd);
04622                                    }
04623                             }
04624                      }
04625                      else
04626                      {
04627                             PRInt32 commentOffset = value.FindCharInSet("# \t", 0);
04628                             if (commentOffset >= 0)
04629                             {
04630                                    value.Truncate(commentOffset);
04631                             }
04632                             value.Trim(" \t");
04633                      }
04634                      rv = NS_OK;
04635                      break;
04636               }
04637        }
04638        return(rv);
04639 }
04640 
04641 
04642 
04643 nsresult
04644 InternetSearchDataSource::GetInputs(const PRUnichar *dataUni, nsString &engineName, nsString &userVar,
04645   const nsString &text, nsString &input, PRInt16 direction, PRUint16 pageNumber,  PRUint16 *whichButtons)
04646 {
04647        nsString      buffer(dataUni);
04648 
04649        nsresult      rv = NS_OK;
04650        PRBool        inSection = PR_FALSE;
04651   PRBool    inDirInput; // directional input: "inputnext" or "inputprev"
04652   PRBool    foundInput = PR_FALSE;
04653 
04654        while(!buffer.IsEmpty())
04655        {
04656               PRInt32 eol = buffer.FindCharInSet("\r\n", 0);
04657               if (eol < 0)  break;
04658               nsAutoString  line;
04659               if (eol > 0)
04660               {
04661                      buffer.Left(line, eol);
04662               }
04663               buffer.Cut(0, eol+1);
04664               if (line.IsEmpty())  continue;            // skip empty lines
04665               if (line[0] == PRUnichar('#'))     continue;     // skip comments
04666               line.Trim(" \t");
04667     if (!inSection)
04668               {
04669                      if (line[0] != PRUnichar('<'))     continue;
04670                      line.Cut(0, 1);
04671                      inSection = PR_TRUE;
04672               }
04673               PRInt32       len = line.Length();
04674               if (len > 0)
04675               {
04676                      if (line[len-1] == PRUnichar('>'))
04677                      {
04678                             inSection = PR_FALSE;
04679                             line.SetLength(len-1);
04680                      }
04681               }
04682     if (inSection)
04683       continue;
04684 
04685               // look for inputs
04686               if (line.Find("input", PR_TRUE) == 0)
04687               {
04688       line.Cut(0, 5);
04689 
04690       // look for "inputnext" or "inputprev"
04691       inDirInput = PR_FALSE;
04692 
04693       if (line.Find("next", PR_TRUE) == 0)
04694       {
04695         inDirInput = PR_TRUE;
04696         if (whichButtons)
04697           *whichButtons |= kHaveNext;
04698       }
04699 
04700       if (line.Find("prev", PR_TRUE) == 0)
04701       {
04702         inDirInput = PR_TRUE;
04703         if (whichButtons)
04704           *whichButtons |= kHavePrev;
04705       }
04706 
04707       if (inDirInput)
04708         line.Cut(0, 4);
04709       
04710                      line.Trim(" \t");
04711                      
04712                      // first look for name attribute
04713                      nsAutoString  nameAttrib;
04714 
04715                      PRInt32       nameOffset = line.Find("name", PR_TRUE);
04716                      if (nameOffset >= 0)
04717                      {
04718                             PRInt32 equal = line.FindChar(PRUnichar('='), nameOffset);
04719                             if (equal >= 0)
04720                             {
04721                                    PRInt32       startQuote = line.FindChar(PRUnichar('\"'), equal + 1);
04722                                    if (startQuote >= 0)
04723                                    {
04724                                           PRInt32       endQuote = line.FindChar(PRUnichar('\"'), startQuote + 1);
04725                                           if (endQuote > 0)
04726                                           {
04727                                                  line.Mid(nameAttrib, startQuote+1, endQuote-startQuote-1);
04728                                                  line.Cut(0, endQuote + 1);
04729                                           }
04730                                    }
04731                                    else
04732                                    {
04733                                           nameAttrib = line;
04734                                           nameAttrib.Cut(0, equal+1);
04735                                           nameAttrib.Trim(" \t");
04736                                           PRInt32 space = nameAttrib.FindCharInSet(" \t", 0);
04737                                           if (space > 0)
04738                                           {
04739                                                  nameAttrib.Truncate(space);
04740                                                  line.Cut(0, equal+1+space);
04741                                           }
04742                                           else
04743                                           {
04744                                                  line.Truncate();
04745                                           }
04746                                    }
04747                             }
04748                      }
04749       if (foundInput && nameAttrib.IsEmpty()) 
04750         continue;
04751 
04752                      // first look for value attribute
04753                      nsAutoString  valueAttrib;
04754 
04755       PRInt32  valueOffset;
04756       if (!inDirInput)
04757         valueOffset = line.Find("value", PR_TRUE);
04758       else
04759         valueOffset = line.Find("factor", PR_TRUE);
04760                      if (valueOffset >= 0)
04761                      {
04762                             PRInt32 equal = line.FindChar(PRUnichar('='), valueOffset);
04763                             if (equal >= 0)
04764                             {
04765                                    PRInt32       startQuote = line.FindChar(PRUnichar('\"'), equal + 1);
04766                                    if (startQuote >= 0)
04767                                    {
04768                                           PRInt32       endQuote = line.FindChar(PRUnichar('\"'), startQuote + 1);
04769                                           if (endQuote >= 0)
04770                                           {
04771                                                  line.Mid(valueAttrib, startQuote+1, endQuote-startQuote-1);
04772                                           }
04773                                    }
04774                                    else
04775                                    {
04776                                           // if value attribute's "value" isn't quoted, get the first word... ?
04777                                           valueAttrib = line;
04778                                           valueAttrib.Cut(0, equal+1);
04779                                           valueAttrib.Trim(" \t");
04780                                           PRInt32 space = valueAttrib.FindCharInSet(" \t>", 0);
04781                                           if (space > 0)
04782                                           {
04783                                                  valueAttrib.Truncate(space);
04784                                           }
04785                                    }
04786                             }
04787                      }
04788                      else if (line.Find("user", PR_TRUE) >= 0)
04789                      {
04790                             userVar = nameAttrib;
04791                             valueAttrib.Assign(text);
04792                      }
04793                      
04794                      // XXX should ignore if  mode=browser  is specified
04795                      // XXX need to do this better
04796                      if (line.RFind("mode=browser", PR_TRUE) >= 0)
04797                             continue;
04798 
04799                      if (!valueAttrib.IsEmpty())
04800                      {
04801         // Here's how we construct the input string:
04802         // <input> is first: Name Attr: Prefix      Data           Example:
04803         // YES               EMPTY      None        <value>        ACTION<value>
04804         // YES               NON-EMPTY  ?           <name>=<value> ACTION?<name>=<value>
04805         // NO                EMPTY      ----------- <ignored> -------------
04806         // NO                NON-EMPTY  &           <name>=<value> ACTION?<n1>=<v1>&<n2>=<v2>
04807                             if (!input.IsEmpty())
04808                                    input.AppendLiteral("&");
04809         else if (!nameAttrib.IsEmpty()) 
04810           input.AppendLiteral("?");
04811 
04812         if (!nameAttrib.IsEmpty()) 
04813         {
04814                               input += nameAttrib;
04815           input.AppendLiteral("=");
04816         }
04817 
04818         // Indicate that we've already found an input, so we cannot have any 
04819         // inputs after this that do not have names. I could be more sophisticated
04820         // than this but I don't care right now since I'm only doing this for one
04821         // plugin. --ben
04822         foundInput = PR_TRUE;
04823 
04824         if (!inDirInput)
04825           input += valueAttrib;
04826         else
04827           input.AppendInt( computeIndex(valueAttrib, pageNumber, direction) );
04828                      }
04829               }
04830        }
04831 
04832   // Now add the default vs. non-default parameters, which come from 
04833   // preferences and are part of the pre-configuration.
04834   nsCOMPtr<nsIPrefService> pserv(do_QueryInterface(prefs));
04835   if (pserv) 
04836   {
04837     // If the pref "browser.search.defaultenginename" has a user value, that
04838     // means the user has changed the engine in the list. This implies that
04839     // the selected engine was _not_ configured as the default by the 
04840     // distributor, because if the value of the pref matched, prefHasUserValue
04841     // would return false. 
04842     PRBool engineIsNotDefault = PR_FALSE;
04843     nsCOMPtr<nsIPrefBranch> rootBranch(do_QueryInterface(pserv));
04844     nsCOMPtr<nsIPrefBranch> defaultBranch;
04845     pserv->GetDefaultBranch("", getter_AddRefs(defaultBranch));
04846 
04847     if (defaultBranch) 
04848     {
04849       nsXPIDLString defaultEngineNameStr;
04850       nsCOMPtr<nsIPrefLocalizedString> defaultEngineName;
04851       rv = defaultBranch->GetComplexValue("browser.search.defaultenginename", 
04852                                           NS_GET_IID(nsIPrefLocalizedString),
04853                                           getter_AddRefs(defaultEngineName));
04854       if (NS_SUCCEEDED(rv)) {
04855         defaultEngineName->GetData(getter_Copies(defaultEngineNameStr));
04856 
04857         nsXPIDLString selectedEngineNameStr;
04858         nsCOMPtr<nsIPrefLocalizedString> selectedEngineName;
04859         rv = rootBranch->GetComplexValue("browser.search.selectedEngine", 
04860                                          NS_GET_IID(nsIPrefLocalizedString),
04861                                          getter_AddRefs(selectedEngineName));
04862         if (NS_SUCCEEDED(rv) && selectedEngineName) {
04863           selectedEngineName->GetData(getter_Copies(selectedEngineNameStr));
04864           engineIsNotDefault = !defaultEngineNameStr.Equals(selectedEngineNameStr);
04865         }
04866         else {
04867           engineIsNotDefault = PR_FALSE; // The selected engine *is* the default
04868                                          // since the user has not changed the
04869                                          // selected item in the list causing
04870                                          // the selectedEngine pref to be set.
04871         }
04872       }
04873     }
04874 
04875     PRInt32 i = 0;
04876     char prefNameBuf[1096];
04877     do
04878     {
04879       ++i;
04880       sprintf(prefNameBuf, "browser.search.param.%s.%d.", 
04881               NS_ConvertUCS2toUTF8(engineName).get(), i);
04882 
04883       nsCOMPtr<nsIPrefBranch> pb;
04884       rv = pserv->GetBranch(prefNameBuf, getter_AddRefs(pb));
04885       if (NS_FAILED(rv)) 
04886         break;
04887 
04888       nsCOMPtr<nsIPrefLocalizedString> parameter;
04889       nsXPIDLString parameterStr;
04890       rv = pb->GetComplexValue(engineIsNotDefault ? "custom" : "default", 
04891                                NS_GET_IID(nsIPrefLocalizedString), 
04892                                getter_AddRefs(parameter));
04893       if (NS_FAILED(rv))
04894         break;
04895 
04896       parameter->GetData(getter_Copies(parameterStr));
04897       
04898       if (!parameterStr.IsEmpty()) 
04899       {
04900         if (!input.IsEmpty())
04901           input.Append(NS_LITERAL_STRING("&"));
04902         input += parameterStr;
04903       }
04904     }
04905     while (1);
04906 
04907     // Now add the release identifier
04908     nsCOMPtr<nsIStringBundleService> stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
04909     nsCOMPtr<nsIStringBundle> bundle;
04910     rv = stringService->CreateBundle(SEARCHCONFIG_PROPERTIES, getter_AddRefs(bundle));
04911     nsCOMPtr<nsIStringBundle> intlBundle;
04912     rv = stringService->CreateBundle(INTL_PROPERTIES, getter_AddRefs(intlBundle));
04913 
04914     nsXPIDLString langName;
04915     intlBundle->GetStringFromName(NS_LITERAL_STRING("general.useragent.locale").get(), 
04916                                   getter_Copies(langName));
04917 
04918     nsAutoString keyTemplate(NS_LITERAL_STRING("browser.search.param."));
04919     keyTemplate += engineName;
04920     keyTemplate.Append(NS_LITERAL_STRING(".release"));
04921 
04922     nsXPIDLString releaseValue;
04923          NS_NAMED_LITERAL_STRING(distributionID, MOZ_DISTRIBUTION_ID);
04924     const PRUnichar* strings[] = { distributionID.get(), langName.get() };
04925     bundle->FormatStringFromName(keyTemplate.get(), strings, 2, getter_Copies(releaseValue));
04926 
04927     if (!releaseValue.IsEmpty()) 
04928     {
04929       if (!input.IsEmpty())
04930         input.Append(NS_LITERAL_STRING("&"));
04931       input += releaseValue;
04932     }
04933 
04934     // Now add order parameters.
04935     nsCOMPtr<nsIPrefBranch> pb;
04936     rv = pserv->GetBranch("", getter_AddRefs(pb));
04937     if (NS_FAILED(rv)) return rv;
04938 
04939     i = 0;
04940     do {
04941       ++i;
04942       sprintf(prefNameBuf, "browser.search.order.%d", i);
04943 
04944       nsCOMPtr<nsIPrefLocalizedString> orderEngineName;
04945       rv = pb->GetComplexValue(prefNameBuf, 
04946                                NS_GET_IID(nsIPrefLocalizedString),
04947                                getter_AddRefs(orderEngineName));
04948       if (NS_FAILED(rv)) 
04949         break;
04950 
04951       nsXPIDLString orderEngineNameStr;
04952       orderEngineName->GetData(getter_Copies(orderEngineNameStr));
04953       if (orderEngineNameStr.Equals(engineName))
04954         break;
04955     }
04956     while (PR_TRUE);
04957 
04958     if (NS_SUCCEEDED(rv))
04959     {
04960       sprintf(prefNameBuf, "browser.search.order.%s.%d",
04961               NS_ConvertUCS2toUTF8(engineName).get(), i);
04962       
04963       nsCOMPtr<nsIPrefLocalizedString> orderParam;
04964       rv = rootBranch->GetComplexValue(prefNameBuf, 
04965                                        NS_GET_IID(nsIPrefLocalizedString),
04966                                        getter_AddRefs(orderParam));
04967       if (NS_FAILED(rv))
04968       {
04969         sprintf(prefNameBuf, "browser.search.order.%s",
04970                 NS_ConvertUCS2toUTF8(engineName).get());
04971         rv = rootBranch->GetComplexValue(prefNameBuf, 
04972                                          NS_GET_IID(nsIPrefLocalizedString),
04973                                          getter_AddRefs(orderParam));
04974       }
04975     
04976       if (NS_SUCCEEDED(rv)) 
04977       {
04978         nsXPIDLString orderParamStr;
04979         orderParam->GetData(getter_Copies(orderParamStr));
04980 
04981         if (!orderParamStr.IsEmpty())
04982         {
04983           if (!input.IsEmpty())
04984             input.Append(NS_LITERAL_STRING("&"));
04985           input += orderParamStr;
04986         }
04987       }
04988     }
04989 
04990     rv = NS_OK;
04991   }
04992 
04993        return(rv);
04994 }
04995 
04996 PRInt32
04997 InternetSearchDataSource::computeIndex(nsAutoString &factor, 
04998                                        PRUint16 page, PRInt16 direction)
04999 {
05000   // XXX get page
05001   PRInt32 errorCode, index = 0;
05002   PRInt32 factorInt = factor.ToInteger(&errorCode);
05003   
05004   if (NS_SUCCEEDED(errorCode))
05005   {
05006     // if factor is garbled assume 10
05007     if (factorInt <= 0)
05008       factorInt = 10;
05009 
05010     if (direction < 0)
05011     {
05012       // don't pass back a negative index!
05013       if (0 <= (page - 1))
05014         --page;
05015     }
05016     index = factorInt * page;
05017   }
05018 
05019   return index;
05020 }
05021 
05022 
05023 
05024 nsresult
05025 InternetSearchDataSource::GetURL(nsIRDFResource *source, nsIRDFLiteral** aResult)
05026 {
05027         const char   *uri = nsnull;
05028        source->GetValueConst( &uri );
05029        nsAutoString  url;
05030        url.AssignWithConversion(uri);
05031        nsIRDFLiteral *literal;
05032        gRDFService->GetLiteral(url.get(), &literal);
05033         *aResult = literal;
05034         return NS_OK;
05035 }
05036 
05037 
05038 
05039 // stream observer methods
05040 
05041 
05042 
05043 NS_IMETHODIMP
05044 InternetSearchDataSource::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
05045 {
05046 #ifdef DEBUG_SEARCH_OUTPUT
05047        printf("InternetSearchDataSourceCallback::OnStartRequest entered.\n");
05048 #endif
05049        return(NS_OK);
05050 }
05051 
05052 
05053 
05054 NS_IMETHODIMP
05055 InternetSearchDataSource::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
05056                             nsIInputStream *aIStream, PRUint32 sourceOffset, PRUint32 aLength)
05057 {
05058        if (!ctxt)    return(NS_ERROR_NO_INTERFACE);
05059        nsCOMPtr<nsIInternetSearchContext> context (do_QueryInterface(ctxt));
05060        if (!context) return(NS_ERROR_NO_INTERFACE);
05061 
05062        nsresult      rv = NS_OK;
05063 
05064        if (aLength < 1)     return(rv);
05065 
05066        PRUint32      count;
05067        char          *buffer = new char[ aLength ];
05068        if (!buffer)  return(NS_ERROR_OUT_OF_MEMORY);
05069 
05070        if (NS_FAILED(rv = aIStream->Read(buffer, aLength, &count)) || count == 0)
05071        {
05072 #ifdef DEBUG
05073               printf("Search datasource read failure.\n");
05074 #endif
05075               delete []buffer;
05076               return(rv);
05077        }
05078        if (count != aLength)
05079        {
05080 #ifdef DEBUG
05081               printf("Search datasource read # of bytes failure.\n");
05082 #endif
05083               delete []buffer;
05084               return(NS_ERROR_UNEXPECTED);
05085        }
05086 
05087        nsCOMPtr<nsIUnicodeDecoder> decoder;
05088        context->GetUnicodeDecoder(getter_AddRefs(decoder));
05089        if (decoder)
05090        {
05091               char                 *aBuffer = buffer;
05092               PRInt32                     unicharBufLen = 0;
05093               decoder->GetMaxLength(aBuffer, aLength, &unicharBufLen);
05094               PRUnichar            *unichars = new PRUnichar [ unicharBufLen+1 ];
05095               do
05096               {
05097                      PRInt32              srcLength = aLength;
05098                      PRInt32              unicharLength = unicharBufLen;
05099                      rv = decoder->Convert(aBuffer, &srcLength, unichars, &unicharLength);
05100                      unichars[unicharLength]=0;  //add this since the unicode converters can't be trusted to do so.
05101 
05102                      // Move the nsParser.cpp 00 -> space hack to here so it won't break UCS2 file
05103 
05104                      // Hack Start
05105                      for(PRInt32 i=0;i < unicharLength; i++)
05106                      {
05107                             if(0x0000 == unichars[i])
05108                             {
05109                                    unichars[i] = PRUnichar(' ');
05110                             }
05111                      }
05112                      // Hack End
05113 
05114                      context->AppendUnicodeBytes(unichars, unicharLength);
05115                      // if we failed, we consume one byte by replace it with U+FFFD
05116                      // and try conversion again.
05117                      if(NS_FAILED(rv))
05118                      {
05119                             decoder->Reset();
05120                             unsigned char smallBuf[2];
05121                             smallBuf[0] = 0xFF;
05122                             smallBuf[1] = 0xFD;
05123                             context->AppendBytes( (const char *)&smallBuf, 2L);
05124                             if(((PRUint32) (srcLength + 1)) > aLength)
05125                                    srcLength = aLength;
05126                             else 
05127                                    srcLength++;
05128                             aBuffer += srcLength;
05129                             aLength -= srcLength;
05130                      }
05131               } while (NS_FAILED(rv) && (aLength > 0));
05132               delete [] unichars;
05133               unichars = nsnull;
05134        }
05135        else
05136        {
05137               context->AppendBytes(buffer, aLength);
05138        }
05139 
05140        delete [] buffer;
05141        buffer = nsnull;
05142        return(rv);
05143 }
05144 
05145 
05146 
05147 NS_IMETHODIMP
05148 InternetSearchDataSource::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
05149                                         nsresult status)
05150 {
05151        if (!mInner)  return(NS_OK);
05152 
05153   nsCOMPtr<nsIChannel> channel (do_QueryInterface(request));
05154        nsCOMPtr<nsIInternetSearchContext> context (do_QueryInterface(ctxt));
05155        if (!ctxt)    return(NS_ERROR_NO_INTERFACE);
05156 
05157        nsresult      rv;
05158        PRUint32      contextType = 0;
05159        if (NS_FAILED(rv = context->GetContextType(&contextType)))            return(rv);
05160 
05161        if (contextType == nsIInternetSearchContext::WEB_SEARCH_CONTEXT)
05162        {
05163               // continue to process nsIInternetSearchContext::WEB_SEARCH_CONTEXT
05164               rv = webSearchFinalize(channel, context);
05165        }
05166        else if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT ||
05167                 contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT ||
05168                 contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT ||
05169                 contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT)
05170        {
05171               nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface(channel));
05172               if (!httpChannel)    return(NS_ERROR_UNEXPECTED);
05173 
05174               // check HTTP status to ensure success
05175               PRUint32      httpStatus = 0;
05176               if (NS_SUCCEEDED(rv = httpChannel->GetResponseStatus(&httpStatus)) &&
05177                      (httpStatus == 200))
05178               {
05179                      rv = saveContents(channel, context, contextType);
05180               }
05181        }
05182        else if (contextType == nsIInternetSearchContext::ENGINE_UPDATE_HEAD_CONTEXT)
05183        {
05184               nsCOMPtr<nsIRDFResource>    theEngine;
05185               if (NS_FAILED(rv = context->GetEngine(getter_AddRefs(theEngine))))    return(rv);
05186               if (!theEngine)      return(NS_ERROR_NO_INTERFACE);
05187 
05188 #ifdef DEBUG_SEARCH_UPDATES
05189               const char    *engineURI = nsnull;
05190               theEngine->GetValueConst(&engineURI);
05191 #endif
05192 
05193               // free up "busy" info now & mark as non-busy
05194               busySchedule = PR_FALSE;
05195               busyResource = nsnull;
05196 
05197               // mark now as the last time we stat'ted the search engine
05198               // regardless of HTTP status
05199               rv = validateEngineNow(theEngine);
05200               NS_ENSURE_SUCCESS(rv, rv);
05201 
05202               // we only have HTTP "HEAD" information when doing updates
05203               nsCOMPtr<nsIHttpChannel> httpChannel (do_QueryInterface(channel));
05204               if (!httpChannel)    return(NS_ERROR_UNEXPECTED);
05205 
05206               // check HTTP status to ensure success
05207               PRUint32      httpStatus = 0;
05208               if (NS_FAILED(rv = httpChannel->GetResponseStatus(&httpStatus)))
05209                      return(rv);
05210               if (httpStatus != 200)      return(NS_ERROR_UNEXPECTED);
05211 
05212               // get last-modified & content-length info
05213               nsCAutoString               lastModValue, contentLengthValue;
05214 
05215         if (NS_FAILED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Last-Modified"), lastModValue)))
05216             lastModValue.Truncate();
05217         if (NS_FAILED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthValue)))
05218             contentLengthValue.Truncate();
05219 
05220               // should we fetch the entire file?
05221               PRBool        updateSearchEngineFile = PR_FALSE;
05222 
05223               // save out new search engine state data into localstore
05224               PRBool               tempDirty = PR_FALSE;
05225               nsCOMPtr<nsIRDFLiteral>     newValue;
05226               if (!lastModValue.IsEmpty())
05227               {
05228                      gRDFService->GetLiteral(NS_ConvertASCIItoUCS2(lastModValue).get(),
05229                             getter_AddRefs(newValue));
05230                      if (newValue)
05231                      {
05232                             updateAtom(mLocalstore, theEngine, kWEB_LastPingModDate, newValue,
05233                                    &tempDirty);
05234         if (tempDirty)
05235           updateSearchEngineFile = PR_TRUE;
05236                      }
05237               }
05238               if (!contentLengthValue.IsEmpty())
05239               {
05240                      gRDFService->GetLiteral(NS_ConvertASCIItoUCS2(contentLengthValue).get(),
05241                             getter_AddRefs(newValue));
05242                      if (newValue)
05243                      {
05244                             updateAtom(mLocalstore, theEngine, kWEB_LastPingContentLen, newValue,
05245                                    &tempDirty);
05246         if (tempDirty)
05247                             {
05248                                    updateSearchEngineFile = PR_TRUE;
05249                             }
05250                             else
05251                             {
05252                                    // worst case: compare local data size vs. remote content size
05253                                    nsCOMPtr<nsIRDFLiteral>     dataLit;
05254                                    if (NS_SUCCEEDED(rv = FindData(theEngine, getter_AddRefs(dataLit))) &&
05255                                           (rv != NS_RDF_NO_VALUE))
05256                                    {
05257                                           const PRUnichar      *dataUni = nsnull;
05258                                           dataLit->GetValueConst(&dataUni);
05259                                           nsAutoString  dataStr(dataUni);
05260                                           PRInt32              dataLen=dataStr.Length();
05261 #ifdef DEBUG_SEARCH_UPDATES
05262                                           printf("    Search engine='%s' data length='%d'\n", engineURI, dataLen);
05263 #endif
05264                                           PRInt32       contentLen=0, err=0;
05265                                           contentLen = contentLengthValue.ToInteger(&err);
05266                                           if ((!err) && (dataLen != contentLen))
05267                                           {
05268 #ifdef DEBUG_SEARCH_UPDATES
05269                                                  printf("    Search engine '%s' data length != remote content length, so update\n",
05270                                                         engineURI, dataLen);
05271 #endif
05272                                                  updateSearchEngineFile = PR_TRUE;
05273                                           }
05274                                    }
05275                             }
05276                      }
05277               }
05278 
05279     if (updateSearchEngineFile)
05280               {
05281 #ifdef DEBUG_SEARCH_UPDATES
05282                      printf("    Search engine='%s' needs updating, so fetching it\n", engineURI);
05283 #endif
05284                      // get update URL
05285                      nsCString            updateURL;
05286                      nsCOMPtr<nsIRDFNode> aNode;
05287                      if (NS_SUCCEEDED(rv = mInner->GetTarget(theEngine, kNC_Update, PR_TRUE, getter_AddRefs(aNode)))
05288                             && (rv != NS_RDF_NO_VALUE))
05289                      {
05290                             nsCOMPtr<nsIRDFLiteral>     aLiteral (do_QueryInterface(aNode));
05291                             if (aLiteral)
05292                             {
05293                                    const PRUnichar      *updateUni = nsnull;
05294                                    aLiteral->GetValueConst(&updateUni);
05295                                    if (updateUni)
05296                                    {
05297                                           updateURL.AssignWithConversion(updateUni);
05298                                    }
05299                             }
05300                      }
05301 
05302                      // get update icon
05303                      nsCString            updateIconURL;
05304                      if (NS_SUCCEEDED(rv = mInner->GetTarget(theEngine, kNC_UpdateIcon, PR_TRUE, getter_AddRefs(aNode)))
05305                             && (rv != NS_RDF_NO_VALUE))
05306                      {
05307                             nsCOMPtr<nsIRDFLiteral>     aIconLiteral (do_QueryInterface(aNode));
05308                             if (aIconLiteral)
05309                             {
05310                                    const PRUnichar      *updateIconUni = nsnull;
05311                                    aIconLiteral->GetValueConst(&updateIconUni);
05312                                    if (updateIconUni)
05313                                    {
05314                                           updateIconURL.AssignWithConversion(updateIconUni);
05315                                    }
05316                             }
05317                      }
05318 
05319                      // download it!
05320       AddSearchEngineInternal(updateURL.get(), updateIconURL.get(),
05321                               nsnull, nsnull, theEngine);
05322               }
05323               else
05324               {
05325 #ifdef DEBUG_SEARCH_UPDATES
05326                      printf("    Search engine='%s' is current and requires no updating\n", engineURI);
05327 #endif
05328               }
05329        }
05330        else
05331        {
05332               rv = NS_ERROR_UNEXPECTED;
05333        }
05334        return(rv);
05335 }
05336 
05337 
05338 
05339 nsresult
05340 InternetSearchDataSource::validateEngineNow(nsIRDFResource *engine)
05341 {
05342        // get the current date/time [from microseconds (PRTime) to seconds]
05343        // also, need to convert from 64 bites to 32 bites as we don't have an easy
05344        // way to convert from 64 bit number to a string like we do for 32 bit numbers
05345        PRTime        now64 = PR_Now(), temp64, million;
05346        LL_I2L(million, PR_USEC_PER_SEC);
05347        LL_DIV(temp64, now64, million);
05348        PRInt32              now32;
05349        LL_L2I(now32, temp64);
05350 
05351        // validate this engine as of now (save as string
05352        // literal as that's all RDF can currently serialize)
05353        nsAutoString  nowStr;
05354        nowStr.AppendInt(now32);
05355 
05356        nsresult             rv;
05357        nsCOMPtr<nsIRDFLiteral>     nowLiteral;
05358        if (NS_FAILED(rv = gRDFService->GetLiteral(nowStr.get(),
05359                      getter_AddRefs(nowLiteral))))      return(rv);
05360        updateAtom(mLocalstore, engine, kWEB_LastPingDate, nowLiteral, nsnull);
05361 
05362        // flush localstore
05363        nsCOMPtr<nsIRDFRemoteDataSource> remoteLocalStore (do_QueryInterface(mLocalstore));
05364        if (remoteLocalStore)
05365        {
05366               remoteLocalStore->Flush();
05367        }
05368        return(NS_OK);
05369 }
05370 
05371 
05372 
05373 nsresult
05374 InternetSearchDataSource::webSearchFinalize(nsIChannel* channel, nsIInternetSearchContext *context)
05375 {
05376        nsresult                    rv;
05377        nsCOMPtr<nsIRDFResource>    mParent;
05378        if (NS_FAILED(rv = context->GetParent(getter_AddRefs(mParent))))      return(rv);
05379 //     Note: mParent can be null
05380 //     if (!mParent) return(NS_ERROR_NO_INTERFACE);
05381 
05382        nsCOMPtr<nsIRDFResource>    mEngine;
05383        if (NS_FAILED(rv = context->GetEngine(getter_AddRefs(mEngine))))      return(rv);
05384        if (!mEngine) return(NS_ERROR_NO_INTERFACE);
05385 
05386        nsCOMPtr<nsIURI> aURL;
05387        rv = channel->GetURI(getter_AddRefs(aURL));
05388        if (NS_FAILED(rv)) return rv;
05389 
05390        // copy the engine's icon reference (if it has one) onto the result node
05391        nsCOMPtr<nsIRDFNode>        engineIconStatusNode = nsnull;
05392        mInner->GetTarget(mEngine, kNC_Icon, PR_TRUE, getter_AddRefs(engineIconStatusNode));
05393        if (engineIconStatusNode)
05394        {
05395               rv = mInner->Assert(mEngine, kNC_StatusIcon, engineIconStatusNode, PR_TRUE);
05396        }
05397 
05398        const PRUnichar      *uniBuf = nsnull;
05399        if (NS_SUCCEEDED(rv = context->GetBufferConst(&uniBuf)) && (uniBuf))
05400        {
05401               if (mParent && (gBrowserSearchMode>0))
05402               {
05403                      // save HTML result page for this engine
05404                      nsCOMPtr<nsIRDFLiteral>     htmlLiteral;
05405                      if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(uniBuf, getter_AddRefs(htmlLiteral))))
05406                      {
05407                             rv = mInner->Assert(mEngine, kNC_HTML, htmlLiteral, PR_TRUE);
05408                      }
05409               }
05410 
05411               // parse up HTML results
05412               PRInt32 uniBufLen = 0L;
05413               if (NS_SUCCEEDED(rv = context->GetBufferLength(&uniBufLen)))
05414               {
05415                      rv = ParseHTML(aURL, mParent, mEngine, uniBuf, uniBufLen);
05416               }
05417        }
05418        else
05419        {
05420 #ifdef DEBUG_SEARCH_OUTPUT
05421               printf(" *** InternetSearchDataSourceCallback::OnStopRequest:  no data.\n\n");
05422 #endif
05423        }
05424 
05425        // after we're all done with the html buffer, get rid of it
05426        context->Truncate();
05427 
05428        // (do this last) potentially remove the loading attribute
05429        mInner->Unassert(mEngine, kNC_loading, kTrueLiteral);
05430 
05431        if (mLoadGroup)
05432        {
05433               PRUint32      count = 0;
05434               if (NS_SUCCEEDED(rv = mLoadGroup->GetActiveCount(&count)))
05435               {
05436                      // is this the last connection in the loadgroup?
05437                      if (count <= 1)
05438                      {
05439                             Stop();
05440                      }
05441               }
05442        }
05443 
05444        return(NS_OK);
05445 }
05446 
05447 
05448 
05449 nsresult
05450 InternetSearchDataSource::ParseHTML(nsIURI *aURL, nsIRDFResource *mParent,
05451                             nsIRDFResource *mEngine, const PRUnichar *htmlPage, PRInt32 htmlPageSize)
05452 {
05453        // get data out of graph
05454        nsresult      rv;
05455        nsCOMPtr<nsIRDFNode> dataNode;
05456        if (NS_FAILED(rv = mInner->GetTarget(mEngine, kNC_Data, PR_TRUE, getter_AddRefs(dataNode))))
05457        {
05458               return(rv);
05459        }
05460        nsCOMPtr<nsIRDFLiteral>     dataLiteral (do_QueryInterface(dataNode));
05461        if (!dataLiteral)    return(NS_ERROR_NULL_POINTER);
05462 
05463        const PRUnichar      *dataUni = nsnull;
05464        if (NS_FAILED(rv = dataLiteral->GetValueConst(&dataUni)))
05465               return(rv);
05466        if (!dataUni) return(NS_ERROR_NULL_POINTER);
05467 
05468        // get name of this engine once
05469        nsAutoString  engineStr;
05470        GetData(dataUni, "search", 0, "name", engineStr);
05471 
05472        // pre-compute host (we might discard URLs that match this)
05473        nsCAutoString hostName;
05474        aURL->GetAsciiHost(hostName);
05475 
05476        // pre-compute server path (we might discard URLs that match this)
05477        nsAutoString  serverPathStr;
05478        nsCAutoString serverPath;
05479        aURL->GetPath(serverPath);
05480        if (!serverPath.IsEmpty())
05481        {
05482         AppendUTF8toUTF16(serverPath, serverPathStr);
05483         serverPath.Truncate();
05484 
05485               PRInt32 serverOptionsOffset = serverPathStr.FindChar(PRUnichar('?'));
05486               if (serverOptionsOffset >= 0)      serverPathStr.Truncate(serverOptionsOffset);
05487        }
05488 
05489        PRBool        hasPriceFlag = PR_FALSE, hasAvailabilityFlag = PR_FALSE, hasRelevanceFlag = PR_FALSE;
05490        PRBool        hasDateFlag = PR_FALSE;
05491        PRBool        skipLocalFlag = PR_FALSE, useAllHREFsFlag = PR_FALSE;
05492        PRInt32              pageRank = 1;
05493        PRUint32      numInterpretSections, numResults = 0;
05494 
05495        GetNumInterpretSections(dataUni, numInterpretSections);
05496        if (numInterpretSections < 1)
05497        {
05498               // if no <interpret> sections, use all the HREFS on the page
05499               numInterpretSections = 1;
05500               useAllHREFsFlag = PR_TRUE;
05501               skipLocalFlag = PR_TRUE;
05502        }
05503 
05504 #ifdef DEBUG
05505        PRTime        now;
05506        now = PR_Now();
05507   printf("\nStart processing search results:   %u bytes \n", htmlPageSize); 
05508 #endif
05509 
05510        // need to handle multiple <interpret> sections, per spec
05511        for (PRUint32 interpretSectionNum=0; interpretSectionNum < numInterpretSections; interpretSectionNum++)
05512        {
05513               nsAutoString  resultListStartStr, resultListEndStr;
05514               nsAutoString  resultItemStartStr, resultItemEndStr;
05515               nsAutoString  relevanceStartStr, relevanceEndStr;
05516               nsAutoString  bannerStartStr, bannerEndStr, skiplocalStr;
05517               nsAutoString  priceStartStr, priceEndStr, availStartStr, availEndStr;
05518               nsAutoString  dateStartStr, dateEndStr;
05519               nsAutoString  nameStartStr, nameEndStr;
05520               nsAutoString  emailStartStr, emailEndStr;
05521               nsAutoString  browserResultTypeStr;
05522               browserResultTypeStr.AssignLiteral("result");           // default to "result"
05523 
05524               // use a nsDependentString so that "htmlPage" data isn't copied
05525               nsDependentString  htmlResults(htmlPage, htmlPageSize);
05526               PRUint32           startIndex = 0L, stopIndex = htmlPageSize;
05527 
05528     if (!useAllHREFsFlag)
05529               {
05530                      GetData(dataUni, "interpret", interpretSectionNum, "resultListStart", resultListStartStr);
05531                      GetData(dataUni, "interpret", interpretSectionNum, "resultListEnd", resultListEndStr);
05532                      GetData(dataUni, "interpret", interpretSectionNum, "resultItemStart", resultItemStartStr);
05533                      GetData(dataUni, "interpret", interpretSectionNum, "resultItemEnd", resultItemEndStr);
05534                      GetData(dataUni, "interpret", interpretSectionNum, "relevanceStart", relevanceStartStr);
05535                      GetData(dataUni, "interpret", interpretSectionNum, "relevanceEnd", relevanceEndStr);
05536                      GetData(dataUni, "interpret", interpretSectionNum, "bannerStart", bannerStartStr);
05537                      GetData(dataUni, "interpret", interpretSectionNum, "bannerEnd", bannerEndStr);
05538                      GetData(dataUni, "interpret", interpretSectionNum, "skiplocal", skiplocalStr);
05539                      skipLocalFlag = (skiplocalStr.LowerCaseEqualsLiteral("true")) ? PR_TRUE : PR_FALSE;
05540 
05541                      // shopping channel support
05542                      GetData(dataUni, "interpret", interpretSectionNum, "priceStart", priceStartStr);
05543                      GetData(dataUni, "interpret", interpretSectionNum, "priceEnd", priceEndStr);
05544                      GetData(dataUni, "interpret", interpretSectionNum, "availStart", availStartStr);
05545                      GetData(dataUni, "interpret", interpretSectionNum, "availEnd", availEndStr);
05546 
05547                      // news channel support
05548                      GetData(dataUni, "interpret", interpretSectionNum, "dateStart", dateStartStr);
05549                      GetData(dataUni, "interpret", interpretSectionNum, "dateEnd", dateEndStr);
05550 
05551                      // people channel support
05552                      GetData(dataUni, "interpret", interpretSectionNum, "nameStart", nameStartStr);
05553                      GetData(dataUni, "interpret", interpretSectionNum, "nameEnd", nameEndStr);
05554                      GetData(dataUni, "interpret", interpretSectionNum, "emailStart", emailStartStr);
05555                      GetData(dataUni, "interpret", interpretSectionNum, "emailEnd", emailEndStr);
05556 
05557                      // special browser support
05558                      GetData(dataUni, "interpret", interpretSectionNum, "browserResultType", browserResultTypeStr);
05559                      if (browserResultTypeStr.IsEmpty())
05560                      {
05561                             browserResultTypeStr.AssignLiteral("result");    // default to "result"
05562                      }
05563               }
05564 
05565               // look for banner
05566               nsCOMPtr<nsIRDFLiteral>     bannerLiteral;
05567               if ((!bannerStartStr.IsEmpty()) && (!bannerEndStr.IsEmpty()))
05568               {
05569                      PRInt32       bannerStart = nsString_Find(bannerStartStr, htmlResults, PR_TRUE);
05570                      if (bannerStart >= 0)
05571                      {
05572                             startIndex = bannerStart;
05573 
05574                             PRInt32       bannerEnd = nsString_Find(bannerEndStr, htmlResults, PR_TRUE, bannerStart + bannerStartStr.Length());
05575                             if (bannerEnd > bannerStart)
05576                             {
05577                                    stopIndex = bannerEnd - 1;
05578 
05579                                    nsAutoString  htmlBanner;
05580                                    htmlResults.Mid(htmlBanner, bannerStart, bannerEnd - bannerStart - 1);
05581                                    if (!htmlBanner.IsEmpty())
05582                                    {
05583                                           const PRUnichar      *bannerUni = htmlBanner.get();
05584                                           if (bannerUni)
05585                                           {
05586                                                  gRDFService->GetLiteral(bannerUni, getter_AddRefs(bannerLiteral));
05587                                           }
05588                                    }
05589                             }
05590                      }
05591               }
05592 
05593               if (!resultListStartStr.IsEmpty())
05594               {
05595                      PRInt32       resultListStart = nsString_Find(resultListStartStr, htmlResults, PR_TRUE);
05596                      if (resultListStart >= 0)
05597                      {
05598         startIndex = resultListStart + resultListStartStr.Length();
05599                      }
05600       else if (!useAllHREFsFlag)
05601                      {
05602                             // if we have multiple <INTERPRET> sections but can't find the startIndex
05603                             // of a result list block, just continue on with the the next block
05604                             continue;
05605                      }
05606               }
05607               if (!resultListEndStr.IsEmpty())
05608               {
05609                      // rjc note: use RFind to find the LAST
05610                      // occurrence of resultListEndStr
05611 
05612                   nsAString::const_iterator originalStart, start, end;
05613                   htmlResults.BeginReading(start);
05614                   htmlResults.EndReading(end);
05615                   originalStart = start;
05616                   
05617                   if (RFindInReadable(resultListEndStr, start, end))
05618                      stopIndex = Distance(originalStart, start);
05619               }
05620 
05621               PRBool trimItemStart = PR_TRUE;
05622               PRBool trimItemEnd = PR_FALSE;            // rjc note: testing shows we should NEVER trim end???
05623 
05624               // if resultItemStartStr is not specified, try making it just be "HREF="
05625               if (resultItemStartStr.IsEmpty())
05626               {
05627                      resultItemStartStr.AssignLiteral("HREF=");
05628                      trimItemStart = PR_FALSE;
05629               }
05630 
05631               // if resultItemEndStr is not specified, try making it the same as resultItemStartStr
05632               if (resultItemEndStr.IsEmpty())
05633               {
05634                      resultItemEndStr = resultItemStartStr;
05635                      trimItemEnd = PR_TRUE;
05636               }
05637 
05638               while(startIndex < stopIndex)
05639               {
05640                      PRInt32       resultItemStart;
05641                      resultItemStart = nsString_Find(resultItemStartStr, htmlResults, PR_TRUE, startIndex);
05642                      if (resultItemStart < 0)    break;
05643 
05644                      PRInt32       resultItemEnd;
05645       if (trimItemStart)
05646                      {
05647                             resultItemStart += resultItemStartStr.Length();
05648                             resultItemEnd = nsString_Find(resultItemEndStr, htmlResults, PR_TRUE, resultItemStart);
05649                      }
05650                      else
05651                      {
05652                             resultItemEnd = nsString_Find(resultItemEndStr, htmlResults, PR_TRUE, resultItemStart + resultItemStartStr.Length());
05653                      }
05654 
05655                      if (resultItemEnd < 0)
05656                      {
05657                             resultItemEnd = stopIndex;
05658                      }
05659       else if (!trimItemEnd && resultItemEnd >= 0)
05660                      {
05661                             resultItemEnd += resultItemEndStr.Length();
05662                      }
05663 
05664                      // forced to use an nsAutoString (which copies)
05665                      // as CBufDescriptor doesn't guarantee null terminator
05666                      if (resultItemEnd - resultItemStart - 1 <= 0)    break;
05667                      nsAutoString resultItem(&htmlPage[resultItemStart],
05668                             resultItemEnd - resultItemStart - 1);
05669 
05670                      if (resultItem.IsEmpty())   break;
05671 
05672                      // advance startIndex here so that, from this point onward, "continue" can be used
05673                      startIndex = resultItemEnd;
05674 
05675 #ifdef DEBUG_SEARCH_OUTPUT
05676                      char   *results = ToNewCString(resultItem);
05677                      if (results)
05678                      {
05679                             printf("\n----- Search result: '%s'\n\n", results);
05680                             nsCRT::free(results);
05681                             results = nsnull;
05682                      }
05683 #endif
05684 
05685                      // look for href
05686                      PRInt32       hrefOffset = resultItem.Find("HREF=", PR_TRUE);
05687                      if (hrefOffset < 0)
05688                      {
05689 #ifdef DEBUG_SEARCH_OUTPUT
05690                             printf("\n***** Unable to find HREF!\n\n");
05691 #endif
05692                             continue;
05693                      }
05694 
05695                      nsAutoString  hrefStr;
05696                      PRInt32              quoteStartOffset = resultItem.FindCharInSet("\"\'>", hrefOffset);
05697                      PRInt32              quoteEndOffset;
05698                      if (quoteStartOffset < hrefOffset)
05699                      {
05700                             // handle case where HREF isn't quoted
05701                             quoteStartOffset = hrefOffset + strlen("HREF=");
05702                             quoteEndOffset = resultItem.FindChar('>', quoteStartOffset);
05703                             if (quoteEndOffset < quoteStartOffset)    continue;
05704                      }
05705                      else
05706                      {
05707                             if (resultItem[quoteStartOffset] == PRUnichar('>'))
05708                             {
05709                                    // handle case where HREF isn't quoted
05710                                    quoteEndOffset = quoteStartOffset;
05711                                    quoteStartOffset = hrefOffset + strlen("HREF=") -1;
05712                             }
05713                             else
05714                             {
05715                                    quoteEndOffset = resultItem.FindCharInSet("\"\'", quoteStartOffset + 1);
05716                                    if (quoteEndOffset < hrefOffset)   continue;
05717                             }
05718                      }
05719                      resultItem.Mid(hrefStr, quoteStartOffset + 1, quoteEndOffset - quoteStartOffset - 1);
05720 
05721                      ConvertEntities(hrefStr, PR_FALSE, PR_TRUE, PR_FALSE);
05722 
05723                      if (hrefStr.IsEmpty())      continue;
05724 
05725                      char          *absURIStr = nsnull;
05726                      nsCAutoString hrefstrC;
05727                      hrefstrC.AssignWithConversion(hrefStr);
05728 
05729                      if (NS_SUCCEEDED(rv = NS_MakeAbsoluteURI(&absURIStr, hrefstrC.get(), aURL))
05730                          && (absURIStr))
05731                      {
05732                             hrefStr.AssignWithConversion(absURIStr);
05733 
05734                             nsCOMPtr<nsIURI>     absURI;
05735                             rv = NS_NewURI(getter_AddRefs(absURI), absURIStr);
05736                             nsCRT::free(absURIStr);
05737                             absURIStr = nsnull;
05738 
05739         if (absURI && skipLocalFlag)
05740                             {
05741                                    nsCAutoString absPath;
05742                                    absURI->GetPath(absPath);
05743                                    if (!absPath.IsEmpty())
05744                                    {
05745                         NS_ConvertUTF8toUCS2 absPathStr(absPath);
05746                                           PRInt32 pathOptionsOffset = absPathStr.FindChar(PRUnichar('?'));
05747                                           if (pathOptionsOffset >= 0)
05748                                                  absPathStr.Truncate(pathOptionsOffset);
05749                                           PRBool pathsMatchFlag = serverPathStr.Equals(absPathStr, nsCaseInsensitiveStringComparator());
05750             if (pathsMatchFlag)
05751               continue;
05752                                    }
05753 
05754                                    if (!hostName.IsEmpty())
05755                                    {
05756                                           nsCAutoString absHost;
05757                                           absURI->GetAsciiHost(absHost);
05758                                           if (!absHost.IsEmpty())
05759                                           {
05760                                                  PRBool hostsMatchFlag = !nsCRT::strcasecmp(hostName.get(), absHost.get());
05761               if (hostsMatchFlag)
05762                 continue;
05763                                           }
05764                                    }
05765                             }
05766                      }
05767 
05768                      // if this result is to be filtered out, notice it now
05769       if (isSearchResultFiltered(hrefStr))
05770                             continue;
05771 
05772                      nsAutoString  site(hrefStr);
05773 
05774 #ifdef DEBUG_SEARCH_OUTPUT
05775                      char *hrefCStr = ToNewCString(hrefStr);
05776                      if (hrefCStr)
05777                      {
05778                             printf("HREF: '%s'\n", hrefCStr);
05779                             nsCRT::free(hrefCStr);
05780                             hrefCStr = nsnull;
05781                      }
05782 #endif
05783 
05784                      nsCOMPtr<nsIRDFResource>    res;
05785 
05786                      // save HREF attribute as URL
05787                      if (NS_SUCCEEDED(rv = gRDFService->GetAnonymousResource(getter_AddRefs(res))))
05788                      {
05789                             const PRUnichar      *hrefUni = hrefStr.get();
05790                             if (hrefUni)
05791                             {
05792                                    nsCOMPtr<nsIRDFLiteral>     hrefLiteral;
05793                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(hrefUni, getter_AddRefs(hrefLiteral))))
05794                                    {
05795                                           mInner->Assert(res, kNC_URL, hrefLiteral, PR_TRUE);
05796                                    }
05797                             }
05798                      }
05799 
05800                      if (NS_FAILED(rv))   continue;
05801                      
05802                      // set HTML response chunk
05803                      const PRUnichar      *htmlResponseUni = resultItem.get();
05804                      if (htmlResponseUni && (gBrowserSearchMode>0))
05805                      {
05806                             nsCOMPtr<nsIRDFLiteral>     htmlResponseLiteral;
05807                             if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(htmlResponseUni, getter_AddRefs(htmlResponseLiteral))))
05808                             {
05809                                    if (htmlResponseLiteral)
05810                                    {
05811                                           mInner->Assert(res, kNC_HTML, htmlResponseLiteral, PR_TRUE);
05812                                    }
05813                             }
05814                      }
05815                      
05816                      // set banner (if we have one)
05817                      if (bannerLiteral)
05818                      {
05819                             mInner->Assert(res, kNC_Banner, bannerLiteral, PR_TRUE);
05820                      }
05821 
05822                      // look for Site (if it isn't already set)
05823                      nsCOMPtr<nsIRDFNode>        oldSiteRes = nsnull;
05824                      mInner->GetTarget(res, kNC_Site, PR_TRUE, getter_AddRefs(oldSiteRes));
05825                      if (!oldSiteRes)
05826                      {
05827                             PRInt32       protocolOffset = site.FindChar(':', 0);
05828                             if (protocolOffset >= 0)
05829                             {
05830                                    site.Cut(0, protocolOffset+1);
05831                                    while (site[0] == PRUnichar('/'))
05832                                    {
05833                                           site.Cut(0, 1);
05834                                    }
05835                                    PRInt32       slashOffset = site.FindChar('/', 0);
05836                                    if (slashOffset >= 0)
05837                                    {
05838                                           site.Truncate(slashOffset);
05839                                    }
05840                                    if (!site.IsEmpty())
05841                                    {
05842                                           const PRUnichar      *siteUni = site.get();
05843                                           if (siteUni)
05844                                           {
05845                                                  nsCOMPtr<nsIRDFLiteral>     siteLiteral;
05846                                                  if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(siteUni, getter_AddRefs(siteLiteral))))
05847                                                  {
05848                                                         if (siteLiteral)
05849                                                         {
05850                                                                mInner->Assert(res, kNC_Site, siteLiteral, PR_TRUE);
05851                                                         }
05852                                                  }
05853                                           }
05854                                    }
05855                             }
05856                      }
05857 
05858                      // look for name
05859                      nsAutoString  nameStr;
05860 
05861                      if ((!nameStartStr.IsEmpty()) && (!nameEndStr.IsEmpty()))
05862                      {
05863                             PRInt32              nameStart;
05864                             if ((nameStart = nsString_Find(nameStartStr, resultItem, PR_TRUE)) >= 0)
05865                             {
05866                                    nameStart += nameStartStr.Length();
05867                                    PRInt32       nameEnd = nsString_Find(nameEndStr, resultItem, PR_TRUE, nameStart);
05868                                    if (nameEnd > nameStart)
05869                                    {
05870                                           resultItem.Mid(nameStr, nameStart, nameEnd - nameStart);
05871                                    }
05872                             }
05873                      }
05874 
05875                      if (nameStr.IsEmpty())
05876                      {
05877                             PRInt32       anchorEnd = resultItem.FindChar('>', quoteEndOffset);
05878                             if (anchorEnd < quoteEndOffset)
05879                             {
05880 #ifdef DEBUG_SEARCH_OUTPUT
05881                                    printf("\n\nSearch: Unable to find ending > when computing name.\n\n");
05882 #endif
05883                                    continue;
05884                             }
05885                             PRInt32       anchorStop = resultItem.Find("</A>", PR_TRUE, quoteEndOffset);
05886                             if (anchorStop < anchorEnd)
05887                             {
05888 #ifdef DEBUG_SEARCH_OUTPUT
05889                                    printf("\n\nSearch: Unable to find </A> tag to compute name.\n\n");
05890 #endif
05891                                    continue;
05892                             }
05893                             resultItem.Mid(nameStr, anchorEnd + 1, anchorStop - anchorEnd - 1);
05894                      }
05895 
05896                      ConvertEntities(nameStr);
05897 
05898                      // look for Name (if it isn't already set)
05899                      nsCOMPtr<nsIRDFNode>        oldNameRes = nsnull;
05900                      if (!oldNameRes)
05901                      {
05902                             if (!nameStr.IsEmpty())
05903                             {
05904                                    const PRUnichar      *nameUni = nameStr.get();
05905                                    if (nameUni)
05906                                    {
05907                                           nsCOMPtr<nsIRDFLiteral>     nameLiteral;
05908                                           if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(nameUni, getter_AddRefs(nameLiteral))))
05909                                           {
05910                                                  if (nameLiteral)
05911                                                  {
05912                                                         mInner->Assert(res, kNC_Name, nameLiteral, PR_TRUE);
05913                                                  }
05914                                           }
05915                                    }
05916                             }
05917                      }
05918 
05919                      // look for date
05920                      if (!dateStartStr.IsEmpty())
05921                      {
05922                             nsAutoString  dateItem;
05923                             PRInt32              dateStart;
05924                             if ((dateStart = nsString_Find(dateStartStr, resultItem, PR_TRUE)) >= 0)
05925                             {
05926                                    dateStart += dateStartStr.Length();
05927                                    PRInt32       dateEnd = nsString_Find(dateEndStr, resultItem, PR_TRUE, dateStart);
05928                                    if (dateEnd > dateStart)
05929                                    {
05930                                           resultItem.Mid(dateItem, dateStart, dateEnd - dateStart);
05931                                    }
05932                             }
05933                             
05934                             // strip out any html tags
05935                             PRInt32              ltOffset, gtOffset;
05936                             while ((ltOffset = dateItem.FindChar(PRUnichar('<'))) >= 0)
05937                             {
05938                                    if ((gtOffset = dateItem.FindChar(PRUnichar('>'), ltOffset)) <= ltOffset)
05939                                           break;
05940                                    dateItem.Cut(ltOffset, gtOffset - ltOffset + 1);
05941                             }
05942 
05943                             // strip out whitespace and any CR/LFs
05944                             dateItem.Trim("\n\r\t ");
05945 
05946                             if (!dateItem.IsEmpty())
05947                             {
05948                                    const PRUnichar             *dateUni = dateItem.get();
05949                                    nsCOMPtr<nsIRDFLiteral>     dateLiteral;
05950                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(dateUni, getter_AddRefs(dateLiteral))))
05951                                    {
05952                                           if (dateLiteral)
05953                                           {
05954                                                  mInner->Assert(res, kNC_Date, dateLiteral, PR_TRUE);
05955                                                  hasDateFlag = PR_TRUE;
05956                                           }
05957                                    }
05958                             }
05959                      }
05960 
05961                      // look for price
05962                      if (!priceStartStr.IsEmpty())
05963                      {
05964                             nsAutoString  priceItem;
05965                             PRInt32              priceStart;
05966                             if ((priceStart = nsString_Find(priceStartStr, resultItem, PR_TRUE)) >= 0)
05967                             {
05968                                    priceStart += priceStartStr.Length();
05969                                    PRInt32       priceEnd = nsString_Find(priceEndStr, resultItem, PR_TRUE, priceStart);
05970                                    if (priceEnd > priceStart)
05971                                    {
05972                                           resultItem.Mid(priceItem, priceStart, priceEnd - priceStart);
05973                                           ConvertEntities(priceItem);
05974                                    }
05975                             }
05976                             if (!priceItem.IsEmpty())
05977                             {
05978                                    const PRUnichar             *priceUni = priceItem.get();
05979                                    nsCOMPtr<nsIRDFLiteral>     priceLiteral;
05980                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(priceUni, getter_AddRefs(priceLiteral))))
05981                                    {
05982                                           if (priceLiteral)
05983                                           {
05984                                                  mInner->Assert(res, kNC_Price, priceLiteral, PR_TRUE);
05985                                                  hasPriceFlag = PR_TRUE;
05986                                           }
05987                                    }
05988 
05989                                    PRInt32       priceCharStartOffset = priceItem.FindCharInSet("1234567890");
05990                                    if (priceCharStartOffset >= 0)
05991                                    {
05992                                           priceItem.Cut(0, priceCharStartOffset);
05993                                           PRInt32       priceErr;
05994                                           float  val = priceItem.ToFloat(&priceErr);
05995                                           if (priceItem.FindChar(PRUnichar('.')) >= 0)     val *= 100;
05996 
05997                                           nsCOMPtr<nsIRDFInt>  priceSortLiteral;
05998                                           if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral((PRInt32)val, getter_AddRefs(priceSortLiteral))))
05999                                           {
06000                                                  if (priceSortLiteral)
06001                                                  {
06002                                                         mInner->Assert(res, kNC_PriceSort, priceSortLiteral, PR_TRUE);
06003                                                  }
06004                                           }
06005                                    }
06006                             }
06007                             // look for availability (if we looked for price)
06008                             if (!availStartStr.IsEmpty())
06009                             {
06010                                    nsAutoString  availItem;
06011                                    PRInt32              availStart;
06012                                    if ((availStart = nsString_Find(availStartStr, resultItem, PR_TRUE)) >= 0)
06013                                    {
06014                                           availStart += availStartStr.Length();
06015                                           PRInt32       availEnd = nsString_Find(availEndStr, resultItem, PR_TRUE, availStart);
06016                                           if (availEnd > availStart)
06017                                           {
06018                                                  resultItem.Mid(availItem, availStart, availEnd - availStart);
06019                                                  ConvertEntities(availItem);
06020                                           }
06021                                    }
06022                                    if (!availItem.IsEmpty())
06023                                    {
06024                                           const PRUnichar             *availUni = availItem.get();
06025                                           nsCOMPtr<nsIRDFLiteral>     availLiteral;
06026                                           if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(availUni, getter_AddRefs(availLiteral))))
06027                                           {
06028                                                  if (availLiteral)
06029                                                  {
06030                                                         mInner->Assert(res, kNC_Availability, availLiteral, PR_TRUE);
06031                                                         hasAvailabilityFlag = PR_TRUE;
06032                                                  }
06033                                           }
06034                                    }
06035                             }
06036                      }
06037 
06038                      // look for relevance
06039                      nsAutoString  relItem;
06040                      PRInt32              relStart;
06041                      if ((relStart = nsString_Find(relevanceStartStr, resultItem, PR_TRUE)) >= 0)
06042                      {
06043                             relStart += relevanceStartStr.Length();
06044                             PRInt32       relEnd = nsString_Find(relevanceEndStr, resultItem, PR_TRUE);
06045                             if (relEnd > relStart)
06046                             {
06047                                    resultItem.Mid(relItem, relStart, relEnd - relStart);
06048                             }
06049                      }
06050 
06051                      // look for Relevance (if it isn't already set)
06052                      nsCOMPtr<nsIRDFNode>        oldRelRes = nsnull;
06053                      if (!oldRelRes)
06054                      {
06055                             if (!relItem.IsEmpty())
06056                             {
06057                                    // save real relevance
06058                                    const PRUnichar      *relUni = relItem.get();
06059                                    if (relUni)
06060                                    {
06061                                           nsAutoString  relStr(relUni);
06062                                           // take out any characters that aren't numeric or "%"
06063                                           PRInt32       len = relStr.Length();
06064                                           for (PRInt32 x=len-1; x>=0; x--)
06065                                           {
06066                                                  PRUnichar     ch;
06067                                                  ch = relStr.CharAt(x);
06068                                                  if ((ch != PRUnichar('%')) &&
06069                                                         ((ch < PRUnichar('0')) || (ch > PRUnichar('9'))))
06070                                                  {
06071                                                         relStr.Cut(x, 1);
06072                                                  }
06073                                           }
06074                                           // make sure it ends with a "%"
06075                                           len = relStr.Length();
06076                                           if (len > 0)
06077                                           {
06078                                                  PRUnichar     ch;
06079                                                  ch = relStr.CharAt(len - 1);
06080                                                  if (ch != PRUnichar('%'))
06081                                                  {
06082                                                         relStr += PRUnichar('%');
06083                                                  }
06084                                                  relItem = relStr;
06085                                                  hasRelevanceFlag = PR_TRUE;
06086                                           }
06087                                           else
06088                                           {
06089                                                  relItem.Truncate();
06090                                           }
06091                                    }
06092                             }
06093                             if (relItem.IsEmpty())
06094                             {
06095                                    relItem.AssignLiteral("-");
06096                             }
06097 
06098                             const PRUnichar *relItemUni = relItem.get();
06099                             nsCOMPtr<nsIRDFLiteral>     relLiteral;
06100                             if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(relItemUni, getter_AddRefs(relLiteral))))
06101                             {
06102                                    if (relLiteral)
06103                                    {
06104                                           mInner->Assert(res, kNC_Relevance, relLiteral, PR_TRUE);
06105                                    }
06106                             }
06107 
06108                             if ((!relItem.IsEmpty()) && (!relItem.EqualsLiteral("-")))
06109                             {
06110                                    // If its a percentage, remove "%"
06111                                    if (relItem[relItem.Length()-1] == PRUnichar('%'))
06112                                    {
06113                                           relItem.Cut(relItem.Length()-1, 1);
06114                                    }
06115 
06116                                    // left-pad with "0"s and set special sorting value
06117                                    nsAutoString  zero;
06118                                    zero.AssignLiteral("000");
06119                                    if (relItem.Length() < 3)
06120                                    {
06121                                           relItem.Insert(zero.get(), 0, zero.Length() - relItem.Length()); 
06122                                    }
06123                             }
06124                             else
06125                             {
06126                                    relItem.AssignLiteral("000");
06127                             }
06128 
06129                             const PRUnichar      *relSortUni = relItem.get();
06130                             if (relSortUni)
06131                             {
06132                                    nsCOMPtr<nsIRDFLiteral>     relSortLiteral;
06133                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(relSortUni, getter_AddRefs(relSortLiteral))))
06134                                    {
06135                                           if (relSortLiteral)
06136                                           {
06137                                                  mInner->Assert(res, kNC_RelevanceSort, relSortLiteral, PR_TRUE);
06138                                           }
06139                                    }
06140                             }
06141                      }
06142 
06143                      // set reference to engine this came from (if it isn't already set)
06144                      nsCOMPtr<nsIRDFNode>        oldEngineRes = nsnull;
06145                      if (!oldEngineRes)
06146                      {
06147                             if (!engineStr.IsEmpty())
06148                             {
06149                                    const PRUnichar             *engineUni = engineStr.get();
06150                                    nsCOMPtr<nsIRDFLiteral>     engineLiteral;
06151                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(engineUni, getter_AddRefs(engineLiteral))))
06152                                    {
06153                                           if (engineLiteral)
06154                                           {
06155                                                  mInner->Assert(res, kNC_Engine, engineLiteral, PR_TRUE);
06156                                           }
06157                                    }
06158                             }
06159                      }
06160 
06161                      // copy the engine's icon reference (if it has one) onto the result node
06162                      nsCOMPtr<nsIRDFNode>        engineIconNode = nsnull;
06163                      mInner->GetTarget(mEngine, kNC_Icon, PR_TRUE, getter_AddRefs(engineIconNode));
06164 
06165                      // if no branding icon, use some default icons
06166                      nsAutoString  iconChromeDefault;
06167 
06168                      if (browserResultTypeStr.LowerCaseEqualsLiteral("category"))
06169                             iconChromeDefault.AssignLiteral("chrome://communicator/skin/search/category.gif");
06170                      else if ((browserResultTypeStr.LowerCaseEqualsLiteral("result")) && (!engineIconNode))
06171                             iconChromeDefault.AssignLiteral("chrome://communicator/skin/search/result.gif");
06172 
06173                      if (!iconChromeDefault.IsEmpty())
06174                      {
06175                             const PRUnichar             *iconUni = iconChromeDefault.get();
06176                             nsCOMPtr<nsIRDFLiteral>     iconLiteral;
06177                             if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(iconUni, getter_AddRefs(iconLiteral))))
06178                             {
06179                                    if (iconLiteral)
06180                                    {
06181                                           mInner->Assert(res, kNC_Icon, iconLiteral, PR_TRUE);
06182                                    }
06183                             }
06184                      }
06185                      else if (engineIconNode)
06186                      {
06187                             rv = mInner->Assert(res, kNC_Icon, engineIconNode, PR_TRUE);
06188                      }
06189 
06190                      // set result page rank
06191                      nsCOMPtr<nsIRDFInt>  pageRankLiteral;
06192                      if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral(pageRank++, getter_AddRefs(pageRankLiteral))))
06193                      {
06194                             rv = mInner->Assert(res, kNC_PageRank, pageRankLiteral, PR_TRUE);
06195                      }
06196 
06197                      // set the result type
06198                      if (!browserResultTypeStr.IsEmpty())
06199                      {
06200                             const PRUnichar             *resultTypeUni = browserResultTypeStr.get();
06201                             nsCOMPtr<nsIRDFLiteral>     resultTypeLiteral;
06202                             if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(resultTypeUni, getter_AddRefs(resultTypeLiteral))))
06203                             {
06204                                    if (resultTypeLiteral)
06205                                    {
06206                                           mInner->Assert(res, kNC_SearchType, resultTypeLiteral, PR_TRUE);
06207                                    }
06208                             }
06209                      }
06210 
06211                      // set the node type
06212                      rv = mInner->Assert(res, kRDF_type, kNC_SearchResult, PR_TRUE);
06213 
06214                      // Note: always add in parent-child relationship last!  (if it isn't already set)
06215 #ifdef OLDWAY
06216                      PRBool        parentHasChildFlag = PR_FALSE;
06217                      if (mParent)
06218                      {
06219                             mInner->HasAssertion(mParent, kNC_Child, res, PR_TRUE, &parentHasChildFlag);
06220                      }
06221       if (!parentHasChildFlag)
06222 #endif
06223                      {
06224                             if (mParent)
06225                             {
06226                                    rv = mInner->Assert(mParent, kNC_Child, res, PR_TRUE);
06227                             }
06228                      }
06229 
06230                      // Persist this under kNC_LastSearchRoot
06231                      if (mInner)
06232                      {
06233                             rv = mInner->Assert(kNC_LastSearchRoot, kNC_Child, res, PR_TRUE);
06234                      }
06235 
06236                      ++numResults;
06237 
06238                      // place a cap on the # of results we can process
06239                      if (numResults >= MAX_SEARCH_RESULTS_ALLOWED)
06240                             break;
06241 
06242               }
06243        }
06244 
06245        // set hints so that the appropriate columns can be displayed
06246        if (mParent)
06247        {
06248     if (hasPriceFlag)
06249       SetHint(mParent, kNC_Price);
06250     if (hasAvailabilityFlag)
06251       SetHint(mParent, kNC_Availability);
06252     if (hasRelevanceFlag)
06253       SetHint(mParent, kNC_Relevance);
06254     if (hasDateFlag)
06255       SetHint(mParent, kNC_Date);
06256        }
06257 
06258 #ifdef DEBUG
06259        PRTime        now2;
06260        now2 = PR_Now();
06261        PRUint64      loadTime64;
06262        LL_SUB(loadTime64, now2, now);
06263        PRUint32      loadTime32;
06264        LL_L2UI(loadTime32, loadTime64);
06265        printf("Finished processing search results  (%u microseconds)\n", loadTime32);
06266 #endif
06267 
06268        return(NS_OK);
06269 }
06270 
06271 
06272 
06273 nsresult
06274 InternetSearchDataSource::SetHint(nsIRDFResource *mParent, nsIRDFResource *hintRes)
06275 {
06276        if (!mInner)  return(NS_OK);
06277 
06278        nsresult      rv;
06279        PRBool        hasAssertionFlag = PR_FALSE;
06280   rv = mInner->HasAssertion(mParent, hintRes, kTrueLiteral, PR_TRUE,
06281                             &hasAssertionFlag);
06282   if (NS_SUCCEEDED(rv) && !hasAssertionFlag)
06283        {
06284               rv = mInner->Assert(mParent, hintRes, kTrueLiteral, PR_TRUE);
06285        }
06286        return(rv);
06287 }
06288 
06289 
06290 
06291 nsresult
06292 InternetSearchDataSource::ConvertEntities(nsString &nameStr, PRBool removeHTMLFlag,
06293                                    PRBool removeCRLFsFlag, PRBool trimWhiteSpaceFlag)
06294 {
06295        PRInt32       startOffset = 0, ampOffset, semiOffset, offset;
06296 
06297        // do this before converting entities
06298   if (removeHTMLFlag)
06299        {
06300               // munge out anything inside of HTML "<" / ">" tags
06301               while ((offset = nameStr.FindChar(PRUnichar('<'), 0)) >= 0)
06302               {
06303                      PRInt32       offsetEnd = nameStr.FindChar(PRUnichar('>'), offset+1);
06304                      if (offsetEnd <= offset)    break;
06305                      nameStr.Cut(offset, offsetEnd - offset + 1);
06306               }
06307        }
06308        while ((ampOffset = nameStr.FindChar(PRUnichar('&'), startOffset)) >= 0)
06309        {
06310               if ((semiOffset = nameStr.FindChar(PRUnichar(';'), ampOffset+1)) <= ampOffset)
06311                      break;
06312 
06313               nsAutoString  entityStr;
06314               nameStr.Mid(entityStr, ampOffset, semiOffset-ampOffset+1);
06315               nameStr.Cut(ampOffset, semiOffset-ampOffset+1);
06316 
06317               PRUnichar     entityChar = 0;
06318               if (entityStr.LowerCaseEqualsLiteral("&quot;"))  entityChar = PRUnichar('\"');
06319               else if (entityStr.LowerCaseEqualsLiteral("&amp;"))     entityChar = PRUnichar('&');
06320               else if (entityStr.LowerCaseEqualsLiteral("&nbsp;"))    entityChar = PRUnichar(' ');
06321               else if (entityStr.LowerCaseEqualsLiteral("&lt;"))             entityChar = PRUnichar('<');
06322               else if (entityStr.LowerCaseEqualsLiteral("&gt;"))             entityChar = PRUnichar('>');
06323               else if (entityStr.LowerCaseEqualsLiteral("&iexcl;"))   entityChar = PRUnichar(161);
06324               else if (entityStr.LowerCaseEqualsLiteral("&cent;"))    entityChar = PRUnichar(162);
06325               else if (entityStr.LowerCaseEqualsLiteral("&pound;"))   entityChar = PRUnichar(163);
06326               else if (entityStr.LowerCaseEqualsLiteral("&curren;"))  entityChar = PRUnichar(164);
06327               else if (entityStr.LowerCaseEqualsLiteral("&yen;"))     entityChar = PRUnichar(165);
06328               else if (entityStr.LowerCaseEqualsLiteral("&brvbar;"))  entityChar = PRUnichar(166);
06329               else if (entityStr.LowerCaseEqualsLiteral("&sect;"))    entityChar = PRUnichar(167);
06330               else if (entityStr.LowerCaseEqualsLiteral("&uml;"))     entityChar = PRUnichar(168);
06331               else if (entityStr.LowerCaseEqualsLiteral("&copy;"))    entityChar = PRUnichar(169);
06332               else if (entityStr.LowerCaseEqualsLiteral("&ordf;"))    entityChar = PRUnichar(170);
06333               else if (entityStr.LowerCaseEqualsLiteral("&laquo;"))   entityChar = PRUnichar(171);
06334               else if (entityStr.LowerCaseEqualsLiteral("&not;"))     entityChar = PRUnichar(172);
06335               else if (entityStr.LowerCaseEqualsLiteral("&shy;"))     entityChar = PRUnichar(173);
06336               else if (entityStr.LowerCaseEqualsLiteral("&reg;"))     entityChar = PRUnichar(174);
06337               else if (entityStr.LowerCaseEqualsLiteral("&macr;"))    entityChar = PRUnichar(175);
06338               else if (entityStr.LowerCaseEqualsLiteral("&deg;"))     entityChar = PRUnichar(176);
06339               else if (entityStr.LowerCaseEqualsLiteral("&plusmn;"))  entityChar = PRUnichar(177);
06340               else if (entityStr.LowerCaseEqualsLiteral("&sup2;"))    entityChar = PRUnichar(178);
06341               else if (entityStr.LowerCaseEqualsLiteral("&sup3;"))    entityChar = PRUnichar(179);
06342               else if (entityStr.LowerCaseEqualsLiteral("&acute;"))   entityChar = PRUnichar(180);
06343               else if (entityStr.LowerCaseEqualsLiteral("&micro;"))   entityChar = PRUnichar(181);
06344               else if (entityStr.LowerCaseEqualsLiteral("&para;"))    entityChar = PRUnichar(182);
06345               else if (entityStr.LowerCaseEqualsLiteral("&middot;"))  entityChar = PRUnichar(183);
06346               else if (entityStr.LowerCaseEqualsLiteral("&cedil;"))   entityChar = PRUnichar(184);
06347               else if (entityStr.LowerCaseEqualsLiteral("&sup1;"))    entityChar = PRUnichar(185);
06348               else if (entityStr.LowerCaseEqualsLiteral("&ordm;"))    entityChar = PRUnichar(186);
06349               else if (entityStr.LowerCaseEqualsLiteral("&raquo;"))   entityChar = PRUnichar(187);
06350               else if (entityStr.LowerCaseEqualsLiteral("&frac14;"))  entityChar = PRUnichar(188);
06351               else if (entityStr.LowerCaseEqualsLiteral("&frac12;"))  entityChar = PRUnichar(189);
06352               else if (entityStr.LowerCaseEqualsLiteral("&frac34;"))  entityChar = PRUnichar(190);
06353               else if (entityStr.LowerCaseEqualsLiteral("&iquest;"))  entityChar = PRUnichar(191);
06354               else if (entityStr.LowerCaseEqualsLiteral("&agrave;"))  entityChar = PRUnichar(192);
06355               else if (entityStr.LowerCaseEqualsLiteral("&aacute;"))  entityChar = PRUnichar(193);
06356               else if (entityStr.LowerCaseEqualsLiteral("&acirc;"))   entityChar = PRUnichar(194);
06357               else if (entityStr.LowerCaseEqualsLiteral("&atilde;"))  entityChar = PRUnichar(195);
06358               else if (entityStr.LowerCaseEqualsLiteral("&auml;"))    entityChar = PRUnichar(196);
06359               else if (entityStr.LowerCaseEqualsLiteral("&aring;"))   entityChar = PRUnichar(197);
06360               else if (entityStr.LowerCaseEqualsLiteral("&aelig;"))   entityChar = PRUnichar(198);
06361               else if (entityStr.LowerCaseEqualsLiteral("&ccedil;"))  entityChar = PRUnichar(199);
06362               else if (entityStr.LowerCaseEqualsLiteral("&egrave;"))  entityChar = PRUnichar(200);
06363               else if (entityStr.LowerCaseEqualsLiteral("&eacute;"))  entityChar = PRUnichar(201);
06364               else if (entityStr.LowerCaseEqualsLiteral("&ecirc;"))   entityChar = PRUnichar(202);
06365               else if (entityStr.LowerCaseEqualsLiteral("&euml;"))    entityChar = PRUnichar(203);
06366               else if (entityStr.LowerCaseEqualsLiteral("&igrave;"))  entityChar = PRUnichar(204);
06367               else if (entityStr.LowerCaseEqualsLiteral("&iacute;"))  entityChar = PRUnichar(205);
06368               else if (entityStr.LowerCaseEqualsLiteral("&icirc;"))   entityChar = PRUnichar(206);
06369               else if (entityStr.LowerCaseEqualsLiteral("&iuml;"))    entityChar = PRUnichar(207);
06370               else if (entityStr.LowerCaseEqualsLiteral("&eth;"))     entityChar = PRUnichar(208);
06371               else if (entityStr.LowerCaseEqualsLiteral("&ntilde;"))  entityChar = PRUnichar(209);
06372               else if (entityStr.LowerCaseEqualsLiteral("&ograve;"))  entityChar = PRUnichar(210);
06373               else if (entityStr.LowerCaseEqualsLiteral("&oacute;"))  entityChar = PRUnichar(211);
06374               else if (entityStr.LowerCaseEqualsLiteral("&ocirc;"))   entityChar = PRUnichar(212);
06375               else if (entityStr.LowerCaseEqualsLiteral("&otilde;"))  entityChar = PRUnichar(213);
06376               else if (entityStr.LowerCaseEqualsLiteral("&ouml;"))    entityChar = PRUnichar(214);
06377               else if (entityStr.LowerCaseEqualsLiteral("&times;"))   entityChar = PRUnichar(215);
06378               else if (entityStr.LowerCaseEqualsLiteral("&oslash;"))  entityChar = PRUnichar(216);
06379               else if (entityStr.LowerCaseEqualsLiteral("&ugrave;"))  entityChar = PRUnichar(217);
06380               else if (entityStr.LowerCaseEqualsLiteral("&uacute;"))  entityChar = PRUnichar(218);
06381               else if (entityStr.LowerCaseEqualsLiteral("&ucirc;"))   entityChar = PRUnichar(219);
06382               else if (entityStr.LowerCaseEqualsLiteral("&uuml;"))    entityChar = PRUnichar(220);
06383               else if (entityStr.LowerCaseEqualsLiteral("&yacute;"))  entityChar = PRUnichar(221);
06384               else if (entityStr.LowerCaseEqualsLiteral("&thorn;"))   entityChar = PRUnichar(222);
06385               else if (entityStr.LowerCaseEqualsLiteral("&szlig;"))   entityChar = PRUnichar(223);
06386               else if (entityStr.LowerCaseEqualsLiteral("&agrave;"))  entityChar = PRUnichar(224);
06387               else if (entityStr.LowerCaseEqualsLiteral("&aacute;"))  entityChar = PRUnichar(225);
06388               else if (entityStr.LowerCaseEqualsLiteral("&acirc;"))   entityChar = PRUnichar(226);
06389               else if (entityStr.LowerCaseEqualsLiteral("&atilde;"))  entityChar = PRUnichar(227);
06390               else if (entityStr.LowerCaseEqualsLiteral("&auml;"))    entityChar = PRUnichar(228);
06391               else if (entityStr.LowerCaseEqualsLiteral("&aring;"))   entityChar = PRUnichar(229);
06392               else if (entityStr.LowerCaseEqualsLiteral("&aelig;"))   entityChar = PRUnichar(230);
06393               else if (entityStr.LowerCaseEqualsLiteral("&ccedil;"))  entityChar = PRUnichar(231);
06394               else if (entityStr.LowerCaseEqualsLiteral("&egrave;"))  entityChar = PRUnichar(232);
06395               else if (entityStr.LowerCaseEqualsLiteral("&eacute;"))  entityChar = PRUnichar(233);
06396               else if (entityStr.LowerCaseEqualsLiteral("&ecirc;"))   entityChar = PRUnichar(234);
06397               else if (entityStr.LowerCaseEqualsLiteral("&euml;"))    entityChar = PRUnichar(235);
06398               else if (entityStr.LowerCaseEqualsLiteral("&igrave;"))  entityChar = PRUnichar(236);
06399               else if (entityStr.LowerCaseEqualsLiteral("&iacute;"))  entityChar = PRUnichar(237);
06400               else if (entityStr.LowerCaseEqualsLiteral("&icirc;"))   entityChar = PRUnichar(238);
06401               else if (entityStr.LowerCaseEqualsLiteral("&iuml;"))    entityChar = PRUnichar(239);
06402               else if (entityStr.LowerCaseEqualsLiteral("&eth;"))     entityChar = PRUnichar(240);
06403               else if (entityStr.LowerCaseEqualsLiteral("&ntilde;"))  entityChar = PRUnichar(241);
06404               else if (entityStr.LowerCaseEqualsLiteral("&ograve;"))  entityChar = PRUnichar(242);
06405               else if (entityStr.LowerCaseEqualsLiteral("&oacute;"))  entityChar = PRUnichar(243);
06406               else if (entityStr.LowerCaseEqualsLiteral("&ocirc;"))   entityChar = PRUnichar(244);
06407               else if (entityStr.LowerCaseEqualsLiteral("&otilde;"))  entityChar = PRUnichar(245);
06408               else if (entityStr.LowerCaseEqualsLiteral("&ouml;"))    entityChar = PRUnichar(246);
06409               else if (entityStr.LowerCaseEqualsLiteral("&divide;"))  entityChar = PRUnichar(247);
06410               else if (entityStr.LowerCaseEqualsLiteral("&oslash;"))  entityChar = PRUnichar(248);
06411               else if (entityStr.LowerCaseEqualsLiteral("&ugrave;"))  entityChar = PRUnichar(249);
06412               else if (entityStr.LowerCaseEqualsLiteral("&uacute;"))  entityChar = PRUnichar(250);
06413               else if (entityStr.LowerCaseEqualsLiteral("&ucirc;"))   entityChar = PRUnichar(251);
06414               else if (entityStr.LowerCaseEqualsLiteral("&uuml;"))    entityChar = PRUnichar(252);
06415               else if (entityStr.LowerCaseEqualsLiteral("&yacute;"))  entityChar = PRUnichar(253);
06416               else if (entityStr.LowerCaseEqualsLiteral("&thorn;"))   entityChar = PRUnichar(254);
06417               else if (entityStr.LowerCaseEqualsLiteral("&yuml;"))    entityChar = PRUnichar(255);
06418 
06419               startOffset = ampOffset;
06420               if (entityChar != 0)
06421               {
06422                      nameStr.Insert(entityChar, ampOffset);
06423                      ++startOffset;
06424               }
06425        }
06426 
06427   if (removeCRLFsFlag)
06428        {
06429               // cut out any CRs or LFs
06430               while ((offset = nameStr.FindCharInSet("\n\r", 0)) >= 0)
06431               {
06432                      nameStr.Cut(offset, 1);
06433               }
06434        }
06435 
06436   if (trimWhiteSpaceFlag)
06437        {
06438               // trim name
06439               nameStr.Trim(" \t");
06440        }
06441 
06442        return(NS_OK);
06443 }
06444 
06445 NS_IMETHODIMP
06446 InternetSearchDataSource::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
06447 {
06448     nsresult rv = NS_OK;
06449 
06450     if (!nsCRT::strcmp(aTopic, "profile-before-change"))
06451     {
06452         // The profile is about to change.
06453         categoryDataSource = nsnull;
06454 
06455         if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get()))
06456         {
06457             // Delete search.rdf
06458             nsCOMPtr<nsIFile> searchFile;
06459             rv = NS_GetSpecialDirectory(NS_APP_SEARCH_50_FILE, getter_AddRefs(searchFile));
06460             if (NS_SUCCEEDED(rv))
06461                 rv = searchFile->Remove(PR_FALSE);
06462         }
06463     }
06464     else if (!nsCRT::strcmp(aTopic, "profile-do-change"))
06465     {
06466         // The profile has aleady changed.
06467         if (!categoryDataSource)
06468           GetCategoryList();
06469     }
06470 
06471     return rv;
06472 }
06473 
06474 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(LocalSearchDataSource, Init)
06475 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(InternetSearchDataSource, Init)
06476 
06477 static const nsModuleComponentInfo components[] = {
06478     { "Local Search", NS_RDFFINDDATASOURCE_CID,
06479       NS_LOCALSEARCH_SERVICE_CONTRACTID, LocalSearchDataSourceConstructor },
06480     { "Local Search", NS_RDFFINDDATASOURCE_CID,
06481       NS_LOCALSEARCH_DATASOURCE_CONTRACTID, LocalSearchDataSourceConstructor },
06482     { "Internet Search", NS_RDFSEARCHDATASOURCE_CID,
06483       NS_INTERNETSEARCH_SERVICE_CONTRACTID, InternetSearchDataSourceConstructor },
06484     { "Internet Search", NS_RDFSEARCHDATASOURCE_CID,
06485       NS_INTERNETSEARCH_DATASOURCE_CONTRACTID, InternetSearchDataSourceConstructor },
06486 };
06487 
06488 NS_IMPL_NSGETMODULE(SearchServiceModule, components)