/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Robert John Churchill * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* Implementation for an internet search RDF data store. */ #include "nsInternetSearchService.h" #include "nsLocalSearchService.h" #include "nscore.h" #include "nsIEnumerator.h" #include "nsIRDFObserver.h" #include "nsIRDFContainer.h" #include "nsIRDFContainerUtils.h" #include "nsIServiceManager.h" #include "nsVoidArray.h" // XXX introduces dependency on raptorbase #include "nsXPIDLString.h" #include "nsRDFCID.h" #include "plhash.h" #include "plstr.h" #include "prmem.h" #include "prprf.h" #include "prio.h" #include "prlog.h" #include "rdf.h" #include "nsIDirectoryService.h" #include "nsDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h" #include "nsCOMArray.h" #include "nsCRT.h" #include "nsEnumeratorUtils.h" #include "nsIRDFRemoteDataSource.h" #include "nsICharsetConverterManager.h" #include "nsICharsetAlias.h" #include "nsITextToSubURI.h" #include "nsEscape.h" #include "nsNetUtil.h" #include "nsIChannel.h" #include "nsIFileChannel.h" #include "nsIHttpChannel.h" #include "nsIUploadChannel.h" #include "nsIInputStream.h" #ifndef MOZ_PLACES #include "nsIBookmarksService.h" #endif #include "nsIStringBundle.h" #include "nsIObserverService.h" #include "nsIURL.h" #include "nsILocalFile.h" #include "nsUnicharUtils.h" #include "nsReadableUtils.h" #include "nsIPrefLocalizedString.h" #include "nsIGenericFactory.h" #ifdef XP_WIN #include "windef.h" #include "winbase.h" #endif #ifdef DEBUG // #define DEBUG_SEARCH_OUTPUT 1 // #define DEBUG_SEARCH_UPDATES 1 #endif #define MAX_SEARCH_RESULTS_ALLOWED 100 #define POSTHEADER_PREFIX "Content-type: application/x-www-form-urlencoded\r\nContent-Length: " #define POSTHEADER_SUFFIX "\r\n\r\n" #define SEARCH_PROPERTIES "chrome://communicator/locale/search/search-panel.properties" #ifdef MOZ_XUL_APP #define SEARCHCONFIG_PROPERTIES "chrome://branding/content/searchconfig.properties" #define INTL_PROPERTIES "chrome://global/locale/intl.properties" #else #define SEARCHCONFIG_PROPERTIES "chrome://navigator/content/searchconfig.properties" #define INTL_PROPERTIES "chrome://navigator/locale/navigator.properties" #endif static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); static NS_DEFINE_CID(kRDFContainerCID, NS_RDFCONTAINER_CID); static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID); static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID); static NS_DEFINE_CID(kTextToSubURICID, NS_TEXTTOSUBURI_CID); static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); static const char kURINC_SearchEngineRoot[] = "NC:SearchEngineRoot"; static const char kURINC_SearchResultsSitesRoot[] = "NC:SearchResultsSitesRoot"; static const char kURINC_LastSearchRoot[] = "NC:LastSearchRoot"; static const char kURINC_SearchCategoryRoot[] = "NC:SearchCategoryRoot"; static const char kURINC_SearchCategoryPrefix[] = "NC:SearchCategory?category="; static const char kURINC_SearchCategoryEnginePrefix[] = "NC:SearchCategory?engine="; static const char kURINC_SearchCategoryEngineBasenamePrefix[] = "NC:SearchCategory?engine=urn:search:engine:"; static const char kURINC_FilterSearchURLsRoot[] = "NC:FilterSearchURLsRoot"; static const char kURINC_FilterSearchSitesRoot[] = "NC:FilterSearchSitesRoot"; static const char kSearchCommand[] = "http://home.netscape.com/NC-rdf#command?"; int PR_CALLBACK searchModePrefCallback(const char *pref, void *aClosure); // helper routine because we need to rewrite this to use string // iterators.. this replaces the old nsString::Find static PRInt32 nsString_Find(const nsAString& aPattern, const nsAString& aSource, PRBool aIgnoreCase = PR_FALSE, PRInt32 aOffset = 0, PRInt32 aCount = -1) { nsAString::const_iterator start, end; aSource.BeginReading(start); aSource.EndReading(end); // now adjust for the parameters start.advance(aOffset); if (aCount>0) { end = start; // note that start may have been advanced! end.advance(aCount); } PRBool found; if (aIgnoreCase) found = FindInReadable(aPattern, start, end, nsCaseInsensitiveStringComparator()); else found = FindInReadable(aPattern, start, end); if (!found) return kNotFound; nsAString::const_iterator originalStart; aSource.BeginReading(originalStart); return Distance(originalStart, start); } class InternetSearchContext : public nsIInternetSearchContext { public: InternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine, nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint); virtual ~InternetSearchContext(void); NS_METHOD Init(); NS_DECL_ISUPPORTS NS_DECL_NSIINTERNETSEARCHCONTEXT private: PRUint32 mContextType; nsCOMPtr mParent; nsCOMPtr mEngine; nsCOMPtr mUnicodeDecoder; nsString mBuffer; nsString mHint; }; InternetSearchContext::~InternetSearchContext(void) { } InternetSearchContext::InternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine, nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint) : mContextType(contextType), mParent(aParent), mEngine(aEngine), mUnicodeDecoder(aUnicodeDecoder), mHint(hint) { } NS_IMETHODIMP InternetSearchContext::Init() { return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetContextType(PRUint32 *aContextType) { *aContextType = mContextType; return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetUnicodeDecoder(nsIUnicodeDecoder **decoder) { *decoder = mUnicodeDecoder; NS_IF_ADDREF(*decoder); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetEngine(nsIRDFResource **node) { *node = mEngine; NS_IF_ADDREF(*node); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetHintConst(const PRUnichar **hint) { *hint = mHint.get(); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetParent(nsIRDFResource **node) { *node = mParent; NS_IF_ADDREF(*node); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::AppendBytes(const char *buffer, PRInt32 numBytes) { mBuffer.AppendWithConversion(buffer, numBytes); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::AppendUnicodeBytes(const PRUnichar *buffer, PRInt32 numUniBytes) { mBuffer.Append(buffer, numUniBytes); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetBufferConst(const PRUnichar **buffer) { *buffer = mBuffer.get(); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::GetBufferLength(PRInt32 *bufferLen) { *bufferLen = mBuffer.Length(); return(NS_OK); } NS_IMETHODIMP InternetSearchContext::Truncate() { mBuffer.Truncate(); return(NS_OK); } NS_IMPL_THREADSAFE_ISUPPORTS1(InternetSearchContext, nsIInternetSearchContext) nsresult NS_NewInternetSearchContext(PRUint32 contextType, nsIRDFResource *aParent, nsIRDFResource *aEngine, nsIUnicodeDecoder *aUnicodeDecoder, const PRUnichar *hint, nsIInternetSearchContext **aResult) { InternetSearchContext *result = new InternetSearchContext(contextType, aParent, aEngine, aUnicodeDecoder, hint); if (! result) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = result->Init(); if (NS_FAILED(rv)) { delete result; return rv; } NS_ADDREF(result); *aResult = result; return NS_OK; } static const char kEngineProtocol[] = "engine://"; static const char kSearchProtocol[] = "internetsearch:"; #ifdef DEBUG_SEARCH_UPDATES #define SEARCH_UPDATE_TIMEOUT 10000 // fire every 10 seconds #else #define SEARCH_UPDATE_TIMEOUT 60000 // fire every 60 seconds #endif int PR_CALLBACK searchModePrefCallback(const char *pref, void *aClosure) { InternetSearchDataSource *searchDS = NS_STATIC_CAST(InternetSearchDataSource *, aClosure); if (!searchDS) return(NS_OK); if (searchDS->prefs) { searchDS->prefs->GetIntPref(pref, &searchDS->gBrowserSearchMode); #ifdef DEBUG printf("searchModePrefCallback: '%s' = %d\n", pref, searchDS->gBrowserSearchMode); #endif searchDS->Assert(searchDS->kNC_LastSearchRoot, searchDS->kNC_LastSearchMode, searchDS->kTrueLiteral, PR_TRUE); } return(NS_OK); } static nsIRDFService *gRDFService = nsnull; static nsIRDFContainerUtils *gRDFC = nsnull; PRInt32 InternetSearchDataSource::gRefCnt = 0; PRInt32 InternetSearchDataSource::gBrowserSearchMode = 0; nsIRDFDataSource *InternetSearchDataSource::mInner = nsnull; nsCOMPtr InternetSearchDataSource::mUpdateArray; nsCOMPtr InternetSearchDataSource::mLocalstore; nsCOMPtr InternetSearchDataSource::categoryDataSource; PRBool InternetSearchDataSource::gEngineListBuilt = PR_FALSE; #ifdef MOZ_PHOENIX PRBool InternetSearchDataSource::gReorderedEngineList = PR_FALSE; #endif nsCOMPtr InternetSearchDataSource::mBackgroundLoadGroup; nsCOMPtr InternetSearchDataSource::mLoadGroup; nsCOMPtr InternetSearchDataSource::prefs; nsIRDFResource *InternetSearchDataSource::kNC_SearchResult; nsIRDFResource *InternetSearchDataSource::kNC_SearchEngineRoot; nsIRDFResource *InternetSearchDataSource::kNC_LastSearchRoot; nsIRDFResource *InternetSearchDataSource::kNC_LastSearchMode; nsIRDFResource *InternetSearchDataSource::kNC_SearchCategoryRoot; nsIRDFResource *InternetSearchDataSource::kNC_SearchResultsSitesRoot; nsIRDFResource *InternetSearchDataSource::kNC_FilterSearchURLsRoot; nsIRDFResource *InternetSearchDataSource::kNC_FilterSearchSitesRoot; nsIRDFResource *InternetSearchDataSource::kNC_SearchType; nsIRDFResource *InternetSearchDataSource::kNC_Ref; nsIRDFResource *InternetSearchDataSource::kNC_Child; nsIRDFResource *InternetSearchDataSource::kNC_Title; nsIRDFResource *InternetSearchDataSource::kNC_Data; nsIRDFResource *InternetSearchDataSource::kNC_Name; nsIRDFResource *InternetSearchDataSource::kNC_Description; nsIRDFResource *InternetSearchDataSource::kNC_Version; nsIRDFResource *InternetSearchDataSource::kNC_actionButton; nsIRDFResource *InternetSearchDataSource::kNC_actionBar; nsIRDFResource *InternetSearchDataSource::kNC_searchForm; nsIRDFResource *InternetSearchDataSource::kNC_LastText; nsIRDFResource *InternetSearchDataSource::kNC_URL; nsIRDFResource *InternetSearchDataSource::kRDF_InstanceOf; nsIRDFResource *InternetSearchDataSource::kRDF_type; nsIRDFResource *InternetSearchDataSource::kNC_loading; nsIRDFResource *InternetSearchDataSource::kNC_HTML; nsIRDFResource *InternetSearchDataSource::kNC_Icon; nsIRDFResource *InternetSearchDataSource::kNC_StatusIcon; nsIRDFResource *InternetSearchDataSource::kNC_Banner; nsIRDFResource *InternetSearchDataSource::kNC_Site; nsIRDFResource *InternetSearchDataSource::kNC_Relevance; nsIRDFResource *InternetSearchDataSource::kNC_RelevanceSort; nsIRDFResource *InternetSearchDataSource::kNC_Date; nsIRDFResource *InternetSearchDataSource::kNC_PageRank; nsIRDFResource *InternetSearchDataSource::kNC_Engine; nsIRDFResource *InternetSearchDataSource::kNC_Price; nsIRDFResource *InternetSearchDataSource::kNC_PriceSort; nsIRDFResource *InternetSearchDataSource::kNC_Availability; nsIRDFResource *InternetSearchDataSource::kNC_BookmarkSeparator; nsIRDFResource *InternetSearchDataSource::kNC_Update; nsIRDFResource *InternetSearchDataSource::kNC_UpdateIcon; nsIRDFResource *InternetSearchDataSource::kNC_UpdateCheckDays; nsIRDFResource *InternetSearchDataSource::kWEB_LastPingDate; nsIRDFResource *InternetSearchDataSource::kWEB_LastPingModDate; nsIRDFResource *InternetSearchDataSource::kWEB_LastPingContentLen; nsIRDFResource *InternetSearchDataSource::kNC_SearchCommand_AddToBookmarks; nsIRDFResource *InternetSearchDataSource::kNC_SearchCommand_AddQueryToBookmarks; nsIRDFResource *InternetSearchDataSource::kNC_SearchCommand_FilterResult; nsIRDFResource *InternetSearchDataSource::kNC_SearchCommand_FilterSite; nsIRDFResource *InternetSearchDataSource::kNC_SearchCommand_ClearFilters; nsIRDFLiteral *InternetSearchDataSource::kTrueLiteral; InternetSearchDataSource::InternetSearchDataSource(void) { if (gRefCnt++ == 0) { nsresult rv = CallGetService(kRDFServiceCID, &gRDFService); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service"); rv = CallGetService(kRDFContainerUtilsCID, &gRDFC); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF container utils"); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchEngineRoot), &kNC_SearchEngineRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_LastSearchRoot), &kNC_LastSearchRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchResultsSitesRoot), &kNC_SearchResultsSitesRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_FilterSearchURLsRoot), &kNC_FilterSearchURLsRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_FilterSearchSitesRoot), &kNC_FilterSearchSitesRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_SearchCategoryRoot), &kNC_SearchCategoryRoot); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "SearchMode"), &kNC_LastSearchMode); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "searchtype"), &kNC_SearchType); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "SearchResult"), &kNC_SearchResult); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "ref"), &kNC_Ref); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), &kNC_Child); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "title"), &kNC_Title); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "data"), &kNC_Data); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"), &kNC_Name); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Description"), &kNC_Description); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Version"), &kNC_Version); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "actionButton"), &kNC_actionButton); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "actionBar"), &kNC_actionBar); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "searchForm"), &kNC_searchForm); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "LastText"), &kNC_LastText); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"), &kNC_URL); gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"), &kRDF_InstanceOf); gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"), &kRDF_type); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"), &kNC_loading); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "HTML"), &kNC_HTML); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Icon"), &kNC_Icon); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "StatusIcon"), &kNC_StatusIcon); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Banner"), &kNC_Banner); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Site"), &kNC_Site); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Relevance"), &kNC_Relevance); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Relevance?sort=true"), &kNC_RelevanceSort); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Date"), &kNC_Date); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "PageRank"), &kNC_PageRank); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Engine"), &kNC_Engine); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Price"), &kNC_Price); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Price?sort=true"), &kNC_PriceSort); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Availability"), &kNC_Availability); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"), &kNC_BookmarkSeparator); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Update"), &kNC_Update); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "UpdateIcon"), &kNC_UpdateIcon); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "UpdateCheckDays"), &kNC_UpdateCheckDays); gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingDate"), &kWEB_LastPingDate); gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingModDate"), &kWEB_LastPingModDate); gRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastPingContentLen"), &kWEB_LastPingContentLen); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=addtobookmarks"), &kNC_SearchCommand_AddToBookmarks); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=addquerytobookmarks"), &kNC_SearchCommand_AddQueryToBookmarks); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=filterresult"), &kNC_SearchCommand_FilterResult); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=filtersite"), &kNC_SearchCommand_FilterSite); gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=clearfilters"), &kNC_SearchCommand_ClearFilters); gRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), &kTrueLiteral); prefs = do_GetService(kPrefCID); if (prefs) { prefs->RegisterCallback("browser.search.mode", searchModePrefCallback, this); prefs->GetIntPref("browser.search.mode", &gBrowserSearchMode); } } } InternetSearchDataSource::~InternetSearchDataSource (void) { if (--gRefCnt == 0) { NS_IF_RELEASE(kNC_SearchResult); NS_IF_RELEASE(kNC_SearchEngineRoot); NS_IF_RELEASE(kNC_LastSearchRoot); NS_IF_RELEASE(kNC_LastSearchMode); NS_IF_RELEASE(kNC_SearchCategoryRoot); NS_IF_RELEASE(kNC_SearchResultsSitesRoot); NS_IF_RELEASE(kNC_FilterSearchURLsRoot); NS_IF_RELEASE(kNC_FilterSearchSitesRoot); NS_IF_RELEASE(kNC_SearchType); NS_IF_RELEASE(kNC_Ref); NS_IF_RELEASE(kNC_Child); NS_IF_RELEASE(kNC_Title); NS_IF_RELEASE(kNC_Data); NS_IF_RELEASE(kNC_Name); NS_IF_RELEASE(kNC_Description); NS_IF_RELEASE(kNC_Version); NS_IF_RELEASE(kNC_actionButton); NS_IF_RELEASE(kNC_actionBar); NS_IF_RELEASE(kNC_searchForm); NS_IF_RELEASE(kNC_LastText); NS_IF_RELEASE(kNC_URL); NS_IF_RELEASE(kRDF_InstanceOf); NS_IF_RELEASE(kRDF_type); NS_IF_RELEASE(kNC_loading); NS_IF_RELEASE(kNC_HTML); NS_IF_RELEASE(kNC_Icon); NS_IF_RELEASE(kNC_StatusIcon); NS_IF_RELEASE(kNC_Banner); NS_IF_RELEASE(kNC_Site); NS_IF_RELEASE(kNC_Relevance); NS_IF_RELEASE(kNC_RelevanceSort); NS_IF_RELEASE(kNC_Date); NS_IF_RELEASE(kNC_PageRank); NS_IF_RELEASE(kNC_Engine); NS_IF_RELEASE(kNC_Price); NS_IF_RELEASE(kNC_PriceSort); NS_IF_RELEASE(kNC_Availability); NS_IF_RELEASE(kNC_BookmarkSeparator); NS_IF_RELEASE(kNC_Update); NS_IF_RELEASE(kNC_UpdateIcon); NS_IF_RELEASE(kNC_UpdateCheckDays); NS_IF_RELEASE(kWEB_LastPingDate); NS_IF_RELEASE(kWEB_LastPingModDate); NS_IF_RELEASE(kWEB_LastPingContentLen); NS_IF_RELEASE(kNC_SearchCommand_AddToBookmarks); NS_IF_RELEASE(kNC_SearchCommand_AddQueryToBookmarks); NS_IF_RELEASE(kNC_SearchCommand_FilterResult); NS_IF_RELEASE(kNC_SearchCommand_FilterSite); NS_IF_RELEASE(kNC_SearchCommand_ClearFilters); NS_IF_RELEASE(kTrueLiteral); NS_IF_RELEASE(mInner); mUpdateArray = nsnull; mLocalstore = nsnull; mBackgroundLoadGroup = nsnull; mLoadGroup = nsnull; categoryDataSource = nsnull; if (mTimer) { // be sure to cancel the timer, as it holds a // weak reference back to InternetSearchDataSource mTimer->Cancel(); mTimer = nsnull; } if (prefs) { prefs->UnregisterCallback("browser.search.mode", searchModePrefCallback, this); prefs = nsnull; } NS_IF_RELEASE(gRDFC); if (gRDFService) { gRDFService->UnregisterDataSource(this); NS_RELEASE(gRDFService); } } } nsresult InternetSearchDataSource::GetSearchEngineToPing(nsIRDFResource **theEngine, nsCString &updateURL) { nsresult rv = NS_OK; *theEngine = nsnull; updateURL.Truncate(); if (!mUpdateArray) return(NS_OK); PRUint32 numEngines = 0; if (NS_FAILED(rv = mUpdateArray->Count(&numEngines))) return(rv); if (numEngines < 1) return(NS_OK); nsCOMPtr aRes (do_QueryElementAt(mUpdateArray, 0)); // note: important to remove element from array mUpdateArray->RemoveElementAt(0); if (aRes) { if (isSearchCategoryEngineURI(aRes)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(aRes, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) return(NS_RDF_NO_VALUE); aRes = trueEngine; } if (!aRes) return(NS_OK); *theEngine = aRes.get(); NS_ADDREF(*theEngine); // get update URL nsCOMPtr aNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(aRes, kNC_Update, PR_TRUE, getter_AddRefs(aNode))) && (rv != NS_RDF_NO_VALUE)) { nsCOMPtr aLiteral (do_QueryInterface(aNode)); if (aLiteral) { const PRUnichar *updateUni = nsnull; aLiteral->GetValueConst(&updateUni); if (updateUni) { updateURL.AssignWithConversion(updateUni); } } } } return(rv); } void InternetSearchDataSource::FireTimer(nsITimer* aTimer, void* aClosure) { InternetSearchDataSource *search = NS_STATIC_CAST(InternetSearchDataSource *, aClosure); if (!search) return; if (!search->busySchedule) { nsresult rv; nsCOMPtr searchURI; nsCAutoString updateURL; if (NS_FAILED(rv = search->GetSearchEngineToPing(getter_AddRefs(searchURI), updateURL))) return; if (!searchURI) return; if (updateURL.IsEmpty()) return; search->busyResource = searchURI; nsCOMPtr engineContext; if (NS_FAILED(rv = NS_NewInternetSearchContext(nsIInternetSearchContext::ENGINE_UPDATE_HEAD_CONTEXT, nsnull, searchURI, nsnull, nsnull, getter_AddRefs(engineContext)))) return; if (!engineContext) return; nsCOMPtr uri; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(uri), updateURL.get()))) return; nsCOMPtr channel; if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull))) return; channel->SetLoadFlags(nsIRequest::VALIDATE_ALWAYS); nsCOMPtr httpChannel (do_QueryInterface(channel)); if (!httpChannel) return; // rjc says: just check "HEAD" info for whether a search file has changed httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD")); if (NS_SUCCEEDED(rv = channel->AsyncOpen(search, engineContext))) { search->busySchedule = PR_TRUE; #ifdef DEBUG_SEARCH_UPDATES printf(" InternetSearchDataSource::FireTimer - Pinging '%s'\n", (char *)updateURL.get()); #endif } } #ifdef DEBUG_SEARCH_UPDATES else { printf(" InternetSearchDataSource::FireTimer - busy pinging.\n"); } #endif } PRBool InternetSearchDataSource::isEngineURI(nsIRDFResource *r) { PRBool isEngineURIFlag = PR_FALSE; const char *uri = nsnull; r->GetValueConst(&uri); if ((uri) && (!strncmp(uri, kEngineProtocol, sizeof(kEngineProtocol) - 1))) { isEngineURIFlag = PR_TRUE; } return(isEngineURIFlag); } PRBool InternetSearchDataSource::isSearchURI(nsIRDFResource *r) { PRBool isSearchURIFlag = PR_FALSE; const char *uri = nsnull; r->GetValueConst(&uri); if ((uri) && (!strncmp(uri, kSearchProtocol, sizeof(kSearchProtocol) - 1))) { isSearchURIFlag = PR_TRUE; } return(isSearchURIFlag); } PRBool InternetSearchDataSource::isSearchCategoryURI(nsIRDFResource *r) { PRBool isSearchCategoryURIFlag = PR_FALSE; const char *uri = nsnull; r->GetValueConst(&uri); if ((uri) && (!strncmp(uri, kURINC_SearchCategoryPrefix, sizeof(kURINC_SearchCategoryPrefix) - 1))) { isSearchCategoryURIFlag = PR_TRUE; } return(isSearchCategoryURIFlag); } PRBool InternetSearchDataSource::isSearchCategoryEngineURI(nsIRDFResource *r) { PRBool isSearchCategoryEngineURIFlag = PR_FALSE; const char *uri = nsnull; r->GetValueConst(&uri); if ((uri) && (!strncmp(uri, kURINC_SearchCategoryEnginePrefix, sizeof(kURINC_SearchCategoryEnginePrefix) - 1))) { isSearchCategoryEngineURIFlag = PR_TRUE; } return(isSearchCategoryEngineURIFlag); } PRBool InternetSearchDataSource::isSearchCategoryEngineBasenameURI(nsIRDFNode *r) { PRBool isSearchCategoryEngineBasenameURIFlag = PR_FALSE; nsCOMPtr aRes (do_QueryInterface(r)); if (aRes) { const char *uri = nsnull; aRes->GetValueConst(&uri); if ((uri) && (!nsCRT::strncmp(uri, kURINC_SearchCategoryEngineBasenamePrefix, (int)sizeof(kURINC_SearchCategoryEngineBasenamePrefix) - 1))) { isSearchCategoryEngineBasenameURIFlag = PR_TRUE; } } else { nsCOMPtr aLit (do_QueryInterface(r)); if (aLit) { const PRUnichar *uriUni = nsnull; aLit->GetValueConst(&uriUni); if ((uriUni) && (!nsCRT::strncmp(uriUni, NS_ConvertASCIItoUCS2(kURINC_SearchCategoryEngineBasenamePrefix).get(), (int)sizeof(kURINC_SearchCategoryEngineBasenamePrefix) - 1))) { isSearchCategoryEngineBasenameURIFlag = PR_TRUE; } } } return(isSearchCategoryEngineBasenameURIFlag); } PRBool InternetSearchDataSource::isSearchCommand(nsIRDFResource *r) { PRBool isSearchCommandFlag = PR_FALSE; const char *uri = nsnull; if (NS_SUCCEEDED(r->GetValueConst( &uri )) && (uri)) { if (!strncmp(uri, kSearchCommand, sizeof(kSearchCommand) - 1)) { isSearchCommandFlag = PR_TRUE; } } return(isSearchCommandFlag); } nsresult InternetSearchDataSource::resolveSearchCategoryEngineURI(nsIRDFResource *engine, nsIRDFResource **trueEngine) { *trueEngine = nsnull; if ((!categoryDataSource) || (!mInner)) return(NS_ERROR_UNEXPECTED); nsresult rv; const char *uriUni = nsnull; if (NS_FAILED(rv = engine->GetValueConst(&uriUni))) return(rv); if (!uriUni) return(NS_ERROR_NULL_POINTER); nsAutoString uri; uri.AssignWithConversion(uriUni); if (uri.Find(kURINC_SearchCategoryEngineBasenamePrefix) !=0) return(NS_ERROR_UNEXPECTED); nsCOMPtr basenameLiteral; if (NS_FAILED(rv = gRDFService->GetLiteral(uri.get(), getter_AddRefs(basenameLiteral)))) return(rv); nsCOMPtr catSrc; rv = mInner->GetSource(kNC_URL, basenameLiteral, PR_TRUE, getter_AddRefs(catSrc)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!catSrc) return(NS_ERROR_UNEXPECTED); *trueEngine = catSrc; NS_IF_ADDREF(*trueEngine); return(NS_OK); } //////////////////////////////////////////////////////////////////////// NS_IMPL_ADDREF(InternetSearchDataSource) NS_IMPL_RELEASE(InternetSearchDataSource) NS_INTERFACE_MAP_BEGIN(InternetSearchDataSource) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInternetSearchService) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIInternetSearchService) NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END NS_METHOD InternetSearchDataSource::Init() { nsresult rv = NS_ERROR_OUT_OF_MEMORY; if (NS_FAILED(rv = CallCreateInstance(kRDFInMemoryDataSourceCID, &mInner))) return(rv); // get localstore, as we'll be using it if (NS_FAILED(rv = gRDFService->GetDataSource("rdf:local-store", getter_AddRefs(mLocalstore)))) return(rv); if (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(mUpdateArray)))) return(rv); // register this as a named data source with the service manager if (NS_FAILED(rv = gRDFService->RegisterDataSource(this, PR_FALSE))) return(rv); rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create load group"); if (!mTimer) { busySchedule = PR_FALSE; mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); if (mTimer) { mTimer->InitWithFuncCallback(InternetSearchDataSource::FireTimer, this, SEARCH_UPDATE_TIMEOUT, nsITimer::TYPE_REPEATING_SLACK); // Note: don't addref "this" as we'll cancel the timer in the // InternetSearchDataSource destructor } } gEngineListBuilt = PR_FALSE; // Register as a profile change obsevrer nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); if (observerService) { observerService->AddObserver(this, "profile-before-change", PR_TRUE); observerService->AddObserver(this, "profile-do-change", PR_TRUE); } return(rv); } void InternetSearchDataSource::DeferredInit() { if (gEngineListBuilt) return; nsresult rv; nsCOMPtr dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); if (!dirSvc) return; gEngineListBuilt = PR_TRUE; // get available search engines nsCOMPtr dirlist; rv = dirSvc->Get(NS_APP_SEARCH_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirlist)); if (NS_SUCCEEDED(rv)) { PRBool more; while (NS_SUCCEEDED(dirlist->HasMoreElements(&more)) && more) { nsCOMPtr suppfile; nsCOMPtr dir; dirlist->GetNext(getter_AddRefs(suppfile)); dir = do_QueryInterface(suppfile); if (dir) { GetSearchEngineList(dir, PR_FALSE); } } } // read in category list GetCategoryList(); } NS_IMETHODIMP InternetSearchDataSource::GetURI(char **uri) { NS_PRECONDITION(uri != nsnull, "null ptr"); if (! uri) return NS_ERROR_NULL_POINTER; if ((*uri = nsCRT::strdup("rdf:internetsearch")) == nsnull) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } NS_IMETHODIMP InternetSearchDataSource::GetSource(nsIRDFResource* property, nsIRDFNode* target, PRBool tv, nsIRDFResource** source /* out */) { NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; *source = nsnull; return NS_RDF_NO_VALUE; } NS_IMETHODIMP InternetSearchDataSource::GetSources(nsIRDFResource *property, nsIRDFNode *target, PRBool tv, nsISimpleEnumerator **sources /* out */) { nsresult rv = NS_RDF_NO_VALUE; if (mInner) { rv = mInner->GetSources(property, target, tv, sources); } else { rv = NS_NewEmptyEnumerator(sources); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::GetTarget(nsIRDFResource *source, nsIRDFResource *property, PRBool tv, nsIRDFNode **target /* out */) { NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; *target = nsnull; nsresult rv = NS_RDF_NO_VALUE; // we only have positive assertions in the internet search data source. if (! tv) return(rv); if ((isSearchCategoryURI(source)) && (categoryDataSource)) { const char *uri = nsnull; source->GetValueConst(&uri); if (!uri) return(NS_ERROR_UNEXPECTED); nsAutoString catURI; catURI.AssignWithConversion(uri); nsCOMPtr category; nsCAutoString caturiC; caturiC.AssignWithConversion(catURI); if (NS_FAILED(rv = gRDFService->GetResource(caturiC, getter_AddRefs(category)))) return(rv); rv = categoryDataSource->GetTarget(category, property, tv, target); return(rv); } if (isSearchCategoryEngineURI(source)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) return(NS_RDF_NO_VALUE); source = trueEngine; } if (isSearchURI(source) && (property == kNC_Child)) { // fake out the generic builder (i.e. return anything in this case) // so that search containers never appear to be empty *target = source; NS_ADDREF(source); return(NS_OK); } if (isSearchCommand(source) && (property == kNC_Name)) { nsresult rv; nsCOMPtr stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv) && stringService) { nsCOMPtr bundle; rv = stringService->CreateBundle(SEARCH_PROPERTIES, getter_AddRefs(bundle)); if (NS_SUCCEEDED(rv) && bundle) { nsXPIDLString valUni; nsAutoString name; if (source == kNC_SearchCommand_AddToBookmarks) name.AssignLiteral("addtobookmarks"); else if (source == kNC_SearchCommand_AddQueryToBookmarks) name.AssignLiteral("addquerytobookmarks"); else if (source == kNC_SearchCommand_FilterResult) name.AssignLiteral("excludeurl"); else if (source == kNC_SearchCommand_FilterSite) name.AssignLiteral("excludedomain"); else if (source == kNC_SearchCommand_ClearFilters) name.AssignLiteral("clearfilters"); rv = bundle->GetStringFromName(name.get(), getter_Copies(valUni)); if (NS_SUCCEEDED(rv) && valUni && *valUni) { *target = nsnull; nsCOMPtr literal; if (NS_FAILED(rv = gRDFService->GetLiteral(valUni, getter_AddRefs(literal)))) return rv; *target = literal; NS_IF_ADDREF(*target); return rv; } } } } if (isEngineURI(source)) { // if we're asking for info on a search engine, (deferred) load it if needed nsCOMPtr dataLit; FindData(source, getter_AddRefs(dataLit)); } if (mInner) { rv = mInner->GetTarget(source, property, tv, target); } return(rv); } #ifdef MOZ_PHOENIX void InternetSearchDataSource::ReorderEngineList() { // XXXben - a temporary, inelegant solution to search list ordering until // after 1.0 when we replace all of this with something better // suited to our needs. nsresult rv; nsCOMArray engineList; // Load all data for sherlock files... nsCOMPtr engines; rv = GetTargets(kNC_SearchEngineRoot, kNC_Child, PR_TRUE, getter_AddRefs(engines)); if (NS_FAILED(rv)) return; // Not Fatal. do { PRBool hasMore; engines->HasMoreElements(&hasMore); if (!hasMore) break; nsCOMPtr supp; engines->GetNext(getter_AddRefs(supp)); nsCOMPtr engineResource(do_QueryInterface(supp)); nsCOMPtr data; FindData(engineResource, getter_AddRefs(data)); } while (PR_TRUE); // Build the ordered items first... nsCOMPtr pserv(do_QueryInterface(prefs)); char prefNameBuf[1096]; PRInt32 i = 0; do { ++i; sprintf(prefNameBuf, "browser.search.order.%d", i); nsCOMPtr engineName; rv = pserv->GetComplexValue(prefNameBuf, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(engineName)); if (NS_FAILED(rv)) break; nsXPIDLString data; engineName->GetData(getter_Copies(data)); nsCOMPtr engineNameLiteral; gRDFService->GetLiteral(data, getter_AddRefs(engineNameLiteral)); nsCOMPtr engineResource; rv = mInner->GetSource(kNC_Name, engineNameLiteral, PR_TRUE, getter_AddRefs(engineResource)); if (NS_FAILED(rv)) continue; engineList.AppendObject(engineResource); } while (PR_TRUE); // Now add the rest... rv = GetTargets(kNC_SearchEngineRoot, kNC_Child, PR_TRUE, getter_AddRefs(engines)); if (NS_FAILED(rv)) return; // Not Fatal. do { PRBool hasMore; engines->HasMoreElements(&hasMore); if (!hasMore) break; nsCOMPtr supp; engines->GetNext(getter_AddRefs(supp)); nsCOMPtr engineResource(do_QueryInterface(supp)); if (engineList.IndexOfObject(engineResource) == -1) engineList.AppendObject(engineResource); // Unhook the item from the list, so we can rebuild it in the right // order. Failures are benign. Unassert(kNC_SearchEngineRoot, kNC_Child, engineResource); } while (PR_TRUE); PRInt32 engineCount = engineList.Count(); for (i = 0; i < engineCount; ++i) Assert(kNC_SearchEngineRoot, kNC_Child, engineList[i], PR_TRUE); gReorderedEngineList = PR_TRUE; } #endif NS_IMETHODIMP InternetSearchDataSource::GetTargets(nsIRDFResource *source, nsIRDFResource *property, PRBool tv, nsISimpleEnumerator **targets /* out */) { NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(targets != nsnull, "null ptr"); if (! targets) return NS_ERROR_NULL_POINTER; nsresult rv = NS_RDF_NO_VALUE; // we only have positive assertions in the internet search data source. if (! tv) return(rv); if ((isSearchCategoryURI(source)) && (categoryDataSource)) { const char *uri = nsnull; source->GetValueConst(&uri); if (!uri) return(NS_ERROR_UNEXPECTED); nsAutoString catURI; catURI.AssignWithConversion(uri); nsCOMPtr category; nsCAutoString caturiC; caturiC.AssignWithConversion(catURI); if (NS_FAILED(rv = gRDFService->GetResource(caturiC, getter_AddRefs(category)))) return(rv); rv = categoryDataSource->GetTargets(category, property, tv, targets); return(rv); } if (isSearchCategoryEngineURI(source)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) return(NS_RDF_NO_VALUE); source = trueEngine; } if (mInner) { // defer search engine discovery until needed; small startup time improvement if ((source == kNC_SearchEngineRoot || isSearchURI(source)) && property == kNC_Child && !gEngineListBuilt) { DeferredInit(); } rv = mInner->GetTargets(source, property, tv, targets); } if (isSearchURI(source)) { if (property == kNC_Child) { PRBool doNetworkRequest = PR_TRUE; if (NS_SUCCEEDED(rv) && (targets)) { // check and see if we already have data for the search in question; // if we do, BeginSearchRequest() won't bother doing the search again, // otherwise it will kickstart it PRBool hasResults = PR_FALSE; if (NS_SUCCEEDED((*targets)->HasMoreElements(&hasResults)) && hasResults) { doNetworkRequest = PR_FALSE; } } BeginSearchRequest(source, doNetworkRequest); } } return(rv); } nsresult InternetSearchDataSource::GetCategoryList() { nsIRDFDataSource *ds; nsresult rv = CallCreateInstance(kRDFXMLDataSourceCID, &ds); if (NS_FAILED(rv)) return(rv); if (!ds) return(NS_ERROR_UNEXPECTED); categoryDataSource = do_QueryInterface(ds); NS_RELEASE(ds); ds = nsnull; if (!categoryDataSource) return(NS_ERROR_UNEXPECTED); nsCOMPtr remoteCategoryDataSource (do_QueryInterface(categoryDataSource)); if (!remoteCategoryDataSource) return(NS_ERROR_UNEXPECTED); // get search.rdf nsCOMPtr searchFile; nsCAutoString searchFileURLSpec; rv = NS_GetSpecialDirectory(NS_APP_SEARCH_50_FILE, getter_AddRefs(searchFile)); if (NS_FAILED(rv)) return rv; NS_GetURLSpecFromFile(searchFile, searchFileURLSpec); if (NS_FAILED(rv)) return rv; rv = remoteCategoryDataSource->Init(searchFileURLSpec.get()); if (NS_FAILED(rv)) return rv; // synchronous read rv = remoteCategoryDataSource->Refresh(PR_TRUE); if (NS_FAILED(rv)) return(rv); // ensure that all search engine references actually exist; if not, forget about them PRBool isDirtyFlag = PR_FALSE; nsCOMPtr categoryRoot; rv = gRDFC->MakeSeq(categoryDataSource, kNC_SearchCategoryRoot, getter_AddRefs(categoryRoot)); if (NS_FAILED(rv)) return(rv); if (!categoryRoot) return(NS_ERROR_UNEXPECTED); rv = categoryRoot->Init(categoryDataSource, kNC_SearchCategoryRoot); if (NS_FAILED(rv)) return(rv); PRInt32 numCategories = 0; rv = categoryRoot->GetCount(&numCategories); if (NS_FAILED(rv)) return(rv); // Note: one-based for (PRInt32 catLoop=1; catLoop <= numCategories; catLoop++) { nsCOMPtr aCategoryOrdinal; rv = gRDFC->IndexToOrdinalResource(catLoop, getter_AddRefs(aCategoryOrdinal)); if (NS_FAILED(rv)) break; if (!aCategoryOrdinal) break; nsCOMPtr aCategoryNode; rv = categoryDataSource->GetTarget(kNC_SearchCategoryRoot, aCategoryOrdinal, PR_TRUE, getter_AddRefs(aCategoryNode)); if (NS_FAILED(rv)) break; nsCOMPtr aCategoryRes (do_QueryInterface(aCategoryNode)); if (!aCategoryRes) break; const char *catResURI = nsnull; aCategoryRes->GetValueConst(&catResURI); if (!catResURI) break; nsAutoString categoryStr; categoryStr.AssignWithConversion(kURINC_SearchCategoryPrefix); categoryStr.AppendWithConversion(catResURI); nsCOMPtr searchCategoryRes; if (NS_FAILED(rv = gRDFService->GetUnicodeResource(categoryStr, getter_AddRefs(searchCategoryRes)))) break; nsCOMPtr categoryContainer; rv = gRDFC->MakeSeq(categoryDataSource, searchCategoryRes, getter_AddRefs(categoryContainer)); if (NS_FAILED(rv)) continue; rv = categoryContainer->Init(categoryDataSource, searchCategoryRes); if (NS_FAILED(rv)) return(rv); PRInt32 numEngines = 0; rv = categoryContainer->GetCount(&numEngines); if (NS_FAILED(rv)) break; // Note: one-based, and loop backwards as we might be removing entries for (PRInt32 engineLoop=numEngines; engineLoop >= 1; engineLoop--) { nsCOMPtr aEngineOrdinal; rv = gRDFC->IndexToOrdinalResource(engineLoop, getter_AddRefs(aEngineOrdinal)); if (NS_FAILED(rv)) break; if (!aEngineOrdinal) break; nsCOMPtr aEngineNode; rv = categoryDataSource->GetTarget(searchCategoryRes, aEngineOrdinal, PR_TRUE, getter_AddRefs(aEngineNode)); if (NS_FAILED(rv)) break; nsCOMPtr aEngineRes (do_QueryInterface(aEngineNode)); if (!aEngineRes) break; if (isSearchCategoryEngineURI(aEngineRes)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(aEngineRes, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (!trueEngine)) { // unable to resolve, so forget about this engine reference #ifdef DEBUG const char *catEngineURI = nsnull; aEngineRes->GetValueConst(&catEngineURI); if (catEngineURI) { printf("**** Stale search engine reference to '%s'\n", catEngineURI); } #endif nsCOMPtr staleCatEngine; rv = categoryContainer->RemoveElementAt(engineLoop, PR_TRUE, getter_AddRefs(staleCatEngine)); isDirtyFlag = PR_TRUE; } } } } if (isDirtyFlag) { if (remoteCategoryDataSource) { remoteCategoryDataSource->Flush(); } } return(rv); } NS_IMETHODIMP InternetSearchDataSource::Assert(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target, PRBool tv) { nsresult rv = NS_RDF_ASSERTION_REJECTED; // we only have positive assertions in the internet search data source. if (! tv) return(rv); if (mInner) { rv = mInner->Assert(source, property, target, tv); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::Unassert(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target) { nsresult rv = NS_RDF_ASSERTION_REJECTED; if (mInner) { rv = mInner->Unassert(source, property, target); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::Change(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *oldTarget, nsIRDFNode *newTarget) { nsresult rv = NS_RDF_ASSERTION_REJECTED; if (mInner) { rv = mInner->Change(source, property, oldTarget, newTarget); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::Move(nsIRDFResource *oldSource, nsIRDFResource *newSource, nsIRDFResource *property, nsIRDFNode *target) { nsresult rv = NS_RDF_ASSERTION_REJECTED; if (mInner) { rv = mInner->Move(oldSource, newSource, property, target); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::HasAssertion(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target, PRBool tv, PRBool *hasAssertion /* out */) { NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(hasAssertion != nsnull, "null ptr"); if (! hasAssertion) return NS_ERROR_NULL_POINTER; *hasAssertion = PR_FALSE; // we only have positive assertions in the internet search data source. if (! tv) { return NS_OK; } nsresult rv = NS_RDF_NO_VALUE; if (mInner) { rv = mInner->HasAssertion(source, property, target, tv, hasAssertion); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result) { if (mInner) { return mInner->HasArcIn(aNode, aArc, result); } else { *result = PR_FALSE; } return NS_OK; } NS_IMETHODIMP InternetSearchDataSource::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, PRBool *result) { NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; nsresult rv; if ((source == kNC_SearchEngineRoot) || (source == kNC_LastSearchRoot) || isSearchURI(source)) { *result = (aArc == kNC_Child); return NS_OK; } if ((isSearchCategoryURI(source)) && (categoryDataSource)) { const char *uri = nsnull; source->GetValueConst(&uri); if (!uri) return(NS_ERROR_UNEXPECTED); nsCOMPtr category; if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(uri), getter_AddRefs(category)))) return(rv); return categoryDataSource->HasArcOut(source, aArc, result); } if (isSearchCategoryEngineURI(source)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) { *result = PR_FALSE; return NS_OK; } source = trueEngine; } if (isEngineURI(source)) { // if we're asking for info on a search engine, (deferred) load it if needed nsCOMPtr dataLit; FindData(source, getter_AddRefs(dataLit)); } if (mInner) { return mInner->HasArcOut(source, aArc, result); } *result = PR_FALSE; return NS_OK; } NS_IMETHODIMP InternetSearchDataSource::ArcLabelsIn(nsIRDFNode *node, nsISimpleEnumerator ** labels /* out */) { nsresult rv; if (mInner) { rv = mInner->ArcLabelsIn(node, labels); return(rv); } else { rv = NS_NewEmptyEnumerator(labels); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::ArcLabelsOut(nsIRDFResource *source, nsISimpleEnumerator **labels /* out */) { NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(labels != nsnull, "null ptr"); if (! labels) return NS_ERROR_NULL_POINTER; nsresult rv; if ((source == kNC_SearchEngineRoot) || (source == kNC_LastSearchRoot) || isSearchURI(source)) { nsCOMPtr array; rv = NS_NewISupportsArray(getter_AddRefs(array)); if (NS_FAILED(rv)) return rv; array->AppendElement(kNC_Child); nsISimpleEnumerator* result = new nsArrayEnumerator(array); if (! result) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(result); *labels = result; return(NS_OK); } if ((isSearchCategoryURI(source)) && (categoryDataSource)) { const char *uri = nsnull; source->GetValueConst(&uri); if (!uri) return(NS_ERROR_UNEXPECTED); nsCOMPtr category; if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(uri), getter_AddRefs(category)))) return(rv); rv = categoryDataSource->ArcLabelsOut(category, labels); return(rv); } if (isSearchCategoryEngineURI(source)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(source, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) return(NS_RDF_NO_VALUE); source = trueEngine; } if (isEngineURI(source)) { // if we're asking for info on a search engine, (deferred) load it if needed nsCOMPtr dataLit; FindData(source, getter_AddRefs(dataLit)); } if (mInner) { rv = mInner->ArcLabelsOut(source, labels); return(rv); } return NS_NewEmptyEnumerator(labels); } NS_IMETHODIMP InternetSearchDataSource::GetAllResources(nsISimpleEnumerator** aCursor) { nsresult rv = NS_RDF_NO_VALUE; if (mInner) { rv = mInner->GetAllResources(aCursor); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::AddObserver(nsIRDFObserver *aObserver) { nsresult rv = NS_OK; if (mInner) { rv = mInner->AddObserver(aObserver); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::RemoveObserver(nsIRDFObserver *aObserver) { nsresult rv = NS_OK; if (mInner) { rv = mInner->RemoveObserver(aObserver); } return(rv); } NS_IMETHODIMP InternetSearchDataSource::GetAllCmds(nsIRDFResource* source, nsISimpleEnumerator/**/** commands) { nsCOMPtr cmdArray; nsresult rv; rv = NS_NewISupportsArray(getter_AddRefs(cmdArray)); if (NS_FAILED(rv)) return(rv); // check if we have any filters, enable command to clear them PRBool haveFilters = PR_FALSE; if (mLocalstore) { nsCOMPtr cursor; PRBool hasMore = PR_FALSE; // check kNC_FilterSearchURLsRoot if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchURLsRoot, kNC_Child, PR_TRUE, getter_AddRefs(cursor)))) { if (NS_SUCCEEDED(cursor->HasMoreElements(&hasMore)) && hasMore) { haveFilters = PR_TRUE; } } if (!haveFilters) { // check kNC_FilterSearchSitesRoot if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchSitesRoot, kNC_Child, PR_TRUE, getter_AddRefs(cursor)))) { if (NS_SUCCEEDED(cursor->HasMoreElements(&hasMore)) && hasMore) { haveFilters = PR_TRUE; } } } } PRBool isSearchResult = PR_FALSE; rv = mInner->HasAssertion(source, kRDF_type, kNC_SearchResult, PR_TRUE, &isSearchResult); if (NS_SUCCEEDED(rv) && isSearchResult) { #ifndef MOZ_PLACES nsCOMPtr datasource; if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource)))) { nsCOMPtr bookmarks (do_QueryInterface(datasource)); if (bookmarks) { char *uri = getSearchURI(source); if (uri) { PRBool isBookmarkedFlag = PR_FALSE; rv = bookmarks->IsBookmarked(uri, &isBookmarkedFlag); if (NS_SUCCEEDED(rv) && !isBookmarkedFlag) { cmdArray->AppendElement(kNC_SearchCommand_AddToBookmarks); } Recycle(uri); } } } #endif cmdArray->AppendElement(kNC_SearchCommand_AddQueryToBookmarks); cmdArray->AppendElement(kNC_BookmarkSeparator); // if this is a search result, and it isn't filtered, enable command to be able to filter it PRBool isURLFiltered = PR_FALSE; rv = mInner->HasAssertion(kNC_FilterSearchURLsRoot, kNC_Child, source, PR_TRUE, &isURLFiltered); if (NS_SUCCEEDED(rv) && !isURLFiltered) { cmdArray->AppendElement(kNC_SearchCommand_FilterResult); } // XXX (should check site) if this is a search result site, and the site isn't filtered, // enable command to filter it cmdArray->AppendElement(kNC_SearchCommand_FilterSite); if (haveFilters) { cmdArray->AppendElement(kNC_BookmarkSeparator); cmdArray->AppendElement(kNC_SearchCommand_ClearFilters); } } else if (isSearchURI(source) || (source == kNC_LastSearchRoot)) { if (haveFilters) { cmdArray->AppendElement(kNC_SearchCommand_ClearFilters); } } // always append a separator last (due to aggregation of commands from multiple datasources) cmdArray->AppendElement(kNC_BookmarkSeparator); nsISimpleEnumerator *result = new nsArrayEnumerator(cmdArray); if (!result) return(NS_ERROR_OUT_OF_MEMORY); NS_ADDREF(result); *commands = result; return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::IsCommandEnabled(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* aArguments, PRBool* aResult) { return(NS_ERROR_NOT_IMPLEMENTED); } char * InternetSearchDataSource::getSearchURI(nsIRDFResource *src) { char *uri = nsnull; if (src) { nsresult rv; nsCOMPtr srcNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(src, kNC_URL, PR_TRUE, getter_AddRefs(srcNode)))) { nsCOMPtr urlLiteral (do_QueryInterface(srcNode)); if (urlLiteral) { const PRUnichar *uriUni = nsnull; urlLiteral->GetValueConst(&uriUni); if (uriUni) { nsAutoString uriString(uriUni); uri = ToNewUTF8String(uriString); } } } } return(uri); } nsresult InternetSearchDataSource::addToBookmarks(nsIRDFResource *src) { if (!src) return(NS_ERROR_UNEXPECTED); if (!mInner) return(NS_ERROR_UNEXPECTED); nsresult rv; nsCOMPtr nameNode; // Note: nameLiteral needs to stay in scope for the life of "name" nsCOMPtr nameLiteral; const PRUnichar *name = nsnull; if (NS_SUCCEEDED(rv = mInner->GetTarget(src, kNC_Name, PR_TRUE, getter_AddRefs(nameNode)))) { nameLiteral = do_QueryInterface(nameNode); if (nameLiteral) { nameLiteral->GetValueConst(&name); } } #ifndef MOZ_PLACES nsCOMPtr datasource; if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource)))) { nsCOMPtr bookmarks (do_QueryInterface(datasource)); if (bookmarks) { char *uri = getSearchURI(src); if (uri) { rv = bookmarks->AddBookmarkImmediately(NS_ConvertUTF8toUTF16(uri).get(), name, nsIBookmarksService::BOOKMARK_SEARCH_TYPE, nsnull); Recycle(uri); } } } #endif return(NS_OK); } nsresult InternetSearchDataSource::addQueryToBookmarks(nsIRDFResource *src) { if (!src) return(NS_ERROR_UNEXPECTED); if (!mInner) return(NS_ERROR_UNEXPECTED); nsresult rv; nsCOMPtr refNode; if (NS_FAILED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref, PR_TRUE, getter_AddRefs(refNode)))) return(rv); nsCOMPtr urlLiteral (do_QueryInterface(refNode)); if (!urlLiteral) return(NS_ERROR_UNEXPECTED); const PRUnichar *uriUni = nsnull; urlLiteral->GetValueConst(&uriUni); nsCOMPtr textNode; if (NS_FAILED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_LastText, PR_TRUE, getter_AddRefs(textNode)))) return(rv); nsCOMPtr textLiteral = do_QueryInterface(textNode); nsXPIDLString value; if (textLiteral) { const PRUnichar *textUni = nsnull; textLiteral->GetValueConst(&textUni); nsAutoString name; name.Assign(textUni); // replace pluses with spaces name.ReplaceChar(PRUnichar('+'), PRUnichar(' ')); nsCOMPtr stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv) && stringService) { nsCOMPtr bundle; rv = stringService->CreateBundle(SEARCH_PROPERTIES, getter_AddRefs(bundle)); if (bundle) { const PRUnichar *strings[] = { name.get() }; rv = bundle->FormatStringFromName(NS_LITERAL_STRING("searchTitle").get(), strings, 1, getter_Copies(value)); } } } #ifndef MOZ_PLACES nsCOMPtr datasource; if (NS_SUCCEEDED(rv = gRDFService->GetDataSource("rdf:bookmarks", getter_AddRefs(datasource)))) { nsCOMPtr bookmarks (do_QueryInterface(datasource)); if (bookmarks) rv = bookmarks->AddBookmarkImmediately(uriUni, value.get(), nsIBookmarksService::BOOKMARK_SEARCH_TYPE, nsnull); } #endif return(NS_OK); } nsresult InternetSearchDataSource::filterResult(nsIRDFResource *aResource) { if (!aResource) return(NS_ERROR_UNEXPECTED); if (!mInner) return(NS_ERROR_UNEXPECTED); // remove all anonymous resources which have this as a #URL char *uri = getSearchURI(aResource); if (!uri) return(NS_ERROR_UNEXPECTED); nsAutoString url; url.AssignWithConversion(uri); Recycle(uri); nsresult rv; nsCOMPtr urlLiteral; if (NS_FAILED(rv = gRDFService->GetLiteral(url.get(), getter_AddRefs(urlLiteral))) || (urlLiteral == nsnull)) return(NS_ERROR_UNEXPECTED); // add aResource into a list of nodes to filter out PRBool alreadyFiltered = PR_FALSE; rv = mLocalstore->HasAssertion(kNC_FilterSearchURLsRoot, kNC_Child, urlLiteral, PR_TRUE, &alreadyFiltered); if (NS_SUCCEEDED(rv) && alreadyFiltered) { // already filtered, nothing to do return(rv); } // filter this URL out mLocalstore->Assert(kNC_FilterSearchURLsRoot, kNC_Child, urlLiteral, PR_TRUE); // flush localstore nsCOMPtr remoteLocalStore (do_QueryInterface(mLocalstore)); if (remoteLocalStore) { remoteLocalStore->Flush(); } nsCOMPtr anonArcs; if (NS_SUCCEEDED(rv = mInner->GetSources(kNC_URL, urlLiteral, PR_TRUE, getter_AddRefs(anonArcs)))) { PRBool hasMoreAnonArcs = PR_TRUE; while (hasMoreAnonArcs) { if (NS_FAILED(anonArcs->HasMoreElements(&hasMoreAnonArcs)) || !hasMoreAnonArcs) break; nsCOMPtr anonArc; if (NS_FAILED(anonArcs->GetNext(getter_AddRefs(anonArc)))) break; nsCOMPtr anonChild (do_QueryInterface(anonArc)); if (!anonChild) continue; PRBool isSearchResult = PR_FALSE; rv = mInner->HasAssertion(anonChild, kRDF_type, kNC_SearchResult, PR_TRUE, &isSearchResult); if (NS_FAILED(rv) || !isSearchResult) continue; nsCOMPtr anonParent; if (NS_FAILED(rv = mInner->GetSource(kNC_Child, anonChild, PR_TRUE, getter_AddRefs(anonParent)))) continue; if (!anonParent) continue; mInner->Unassert(anonParent, kNC_Child, anonChild); } } return(NS_OK); } nsresult InternetSearchDataSource::filterSite(nsIRDFResource *aResource) { if (!aResource) return(NS_ERROR_UNEXPECTED); if (!mInner) return(NS_ERROR_UNEXPECTED); char *uri = getSearchURI(aResource); if (!uri) return(NS_ERROR_UNEXPECTED); nsAutoString host; host.AssignWithConversion(uri); Recycle(uri); // determine site (host name) PRInt32 slashOffset1 = host.Find("://"); if (slashOffset1 < 1) return(NS_ERROR_UNEXPECTED); PRInt32 slashOffset2 = host.FindChar(PRUnichar('/'), slashOffset1 + 3); if (slashOffset2 <= slashOffset1) return(NS_ERROR_UNEXPECTED); host.Truncate(slashOffset2 + 1); nsresult rv; nsCOMPtr urlLiteral; if (NS_FAILED(rv = gRDFService->GetLiteral(host.get(), getter_AddRefs(urlLiteral))) || (urlLiteral == nsnull)) return(NS_ERROR_UNEXPECTED); // add aResource into a list of nodes to filter out PRBool alreadyFiltered = PR_FALSE; rv = mLocalstore->HasAssertion(kNC_FilterSearchSitesRoot, kNC_Child, urlLiteral, PR_TRUE, &alreadyFiltered); if (NS_SUCCEEDED(rv) && alreadyFiltered) { // already filtered, nothing to do return(rv); } // filter this site out mLocalstore->Assert(kNC_FilterSearchSitesRoot, kNC_Child, urlLiteral, PR_TRUE); // flush localstore nsCOMPtr remoteLocalStore (do_QueryInterface(mLocalstore)); if (remoteLocalStore) { remoteLocalStore->Flush(); } // remove all anonymous resources which have this as a site nsCOMPtr array; nsCOMPtr aRes; nsCOMPtr cursor; PRBool hasMore; rv = NS_NewISupportsArray(getter_AddRefs(array)); if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv = GetAllResources(getter_AddRefs(cursor)))) return(rv); if (!cursor) return(NS_ERROR_UNEXPECTED); hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(rv = cursor->HasMoreElements(&hasMore))) return(rv); if (!hasMore) break; nsCOMPtr isupports; if (NS_FAILED(rv = cursor->GetNext(getter_AddRefs(isupports)))) return(rv); if (!isupports) return(NS_ERROR_UNEXPECTED); aRes = do_QueryInterface(isupports); if (!aRes) return(NS_ERROR_UNEXPECTED); if ((aRes.get() == kNC_LastSearchRoot) || (isSearchURI(aRes))) { array->AppendElement(aRes); } } PRUint32 count; if (NS_FAILED(rv = array->Count(&count))) return(rv); for (PRUint32 loop=0; loop aSearchRoot (do_QueryElementAt(array, loop)); if (!aSearchRoot) break; if (NS_SUCCEEDED(rv = mInner->GetTargets(aSearchRoot, kNC_Child, PR_TRUE, getter_AddRefs(cursor)))) { hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(cursor->HasMoreElements(&hasMore)) || !hasMore) break; nsCOMPtr arc; if (NS_FAILED(cursor->GetNext(getter_AddRefs(arc)))) break; aRes = do_QueryInterface(arc); if (!aRes) break; uri = getSearchURI(aRes); if (!uri) return(NS_ERROR_UNEXPECTED); nsAutoString site; site.AssignWithConversion(uri); Recycle(uri); // determine site (host name) slashOffset1 = site.Find("://"); if (slashOffset1 < 1) return(NS_ERROR_UNEXPECTED); slashOffset2 = site.FindChar(PRUnichar('/'), slashOffset1 + 3); if (slashOffset2 <= slashOffset1) return(NS_ERROR_UNEXPECTED); site.Truncate(slashOffset2 + 1); if (site.Equals(host, nsCaseInsensitiveStringComparator())) { mInner->Unassert(aSearchRoot, kNC_Child, aRes); } } } } return(NS_OK); } nsresult InternetSearchDataSource::clearFilters(void) { if (!mInner) return(NS_ERROR_UNEXPECTED); nsresult rv; nsCOMPtr arcs; PRBool hasMore = PR_TRUE; nsCOMPtr arc; // remove all filtered URLs if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchURLsRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs)))) { hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; nsCOMPtr filterURL (do_QueryInterface(arc)); if (!filterURL) continue; mLocalstore->Unassert(kNC_FilterSearchURLsRoot, kNC_Child, filterURL); } } // remove all filtered sites if (NS_SUCCEEDED(rv = mLocalstore->GetTargets(kNC_FilterSearchSitesRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs)))) { hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; nsCOMPtr filterSiteLiteral (do_QueryInterface(arc)); if (!filterSiteLiteral) continue; mLocalstore->Unassert(kNC_FilterSearchSitesRoot, kNC_Child, filterSiteLiteral); } } // flush localstore nsCOMPtr remoteLocalStore (do_QueryInterface(mLocalstore)); if (remoteLocalStore) { remoteLocalStore->Flush(); } return(NS_OK); } PRBool InternetSearchDataSource::isSearchResultFiltered(const nsString &hrefStr) { PRBool filterStatus = PR_FALSE; nsresult rv; const PRUnichar *hrefUni = hrefStr.get(); if (!hrefUni) return(filterStatus); // check if this specific URL is to be filtered out nsCOMPtr hrefLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(hrefUni, getter_AddRefs(hrefLiteral)))) { if (NS_SUCCEEDED(rv = mLocalstore->HasAssertion(kNC_FilterSearchURLsRoot, kNC_Child, hrefLiteral, PR_TRUE, &filterStatus))) { if (filterStatus) { return(filterStatus); } } } // check if this specific Site is to be filtered out // determine site (host name) nsAutoString host(hrefStr); PRInt32 slashOffset1 = host.Find("://"); if (slashOffset1 < 1) return(NS_ERROR_UNEXPECTED); PRInt32 slashOffset2 = host.FindChar(PRUnichar('/'), slashOffset1 + 3); if (slashOffset2 <= slashOffset1) return(NS_ERROR_UNEXPECTED); host.Truncate(slashOffset2 + 1); nsCOMPtr urlLiteral; if (NS_FAILED(rv = gRDFService->GetLiteral(host.get(), getter_AddRefs(urlLiteral))) || (urlLiteral == nsnull)) return(NS_ERROR_UNEXPECTED); rv = mLocalstore->HasAssertion(kNC_FilterSearchSitesRoot, kNC_Child, urlLiteral, PR_TRUE, &filterStatus); return(filterStatus); } NS_IMETHODIMP InternetSearchDataSource::DoCommand(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* aArguments) { nsresult rv = NS_OK; PRInt32 loop; PRUint32 numSources; if (NS_FAILED(rv = aSources->Count(&numSources))) return(rv); if (numSources < 1) { return(NS_ERROR_ILLEGAL_VALUE); } for (loop=((PRInt32)numSources)-1; loop>=0; loop--) { nsCOMPtr src (do_QueryElementAt(aSources, loop)); if (!src) return(NS_ERROR_NO_INTERFACE); if (aCommand == kNC_SearchCommand_AddToBookmarks) { if (NS_FAILED(rv = addToBookmarks(src))) return(rv); } else if (aCommand == kNC_SearchCommand_AddQueryToBookmarks) { if (NS_FAILED(rv = addQueryToBookmarks(src))) return(rv); } else if (aCommand == kNC_SearchCommand_FilterResult) { if (NS_FAILED(rv = filterResult(src))) return(rv); } else if (aCommand == kNC_SearchCommand_FilterSite) { if (NS_FAILED(rv = filterSite(src))) return(rv); } else if (aCommand == kNC_SearchCommand_ClearFilters) { if (NS_FAILED(rv = clearFilters())) return(rv); } } return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::BeginUpdateBatch() { return mInner->BeginUpdateBatch(); } NS_IMETHODIMP InternetSearchDataSource::EndUpdateBatch() { return mInner->EndUpdateBatch(); } NS_IMETHODIMP InternetSearchDataSource::AddSearchEngine(const char *engineURL, const char *iconURL, const PRUnichar *suggestedTitle, const PRUnichar *suggestedCategory) { return AddSearchEngineInternal(engineURL, iconURL, suggestedTitle, suggestedCategory, nsnull); } nsresult InternetSearchDataSource::AddSearchEngineInternal(const char *engineURL, const char *iconURL, const PRUnichar *suggestedTitle, const PRUnichar *suggestedCategory, nsIRDFResource *aOldEngineResource) { NS_PRECONDITION(engineURL != nsnull, "null ptr"); if (!engineURL) return(NS_ERROR_NULL_POINTER); // Note: iconURL, suggestedTitle & suggestedCategory // can be null or empty strings, which is OK #ifdef DEBUG_SEARCH_OUTPUT printf("AddSearchEngine: engine='%s'\n", engineURL); #endif nsresult rv = NS_OK; // mBackgroundLoadGroup is a dynamically created singleton if (!mBackgroundLoadGroup) { if (NS_FAILED(rv = NS_NewLoadGroup(getter_AddRefs(mBackgroundLoadGroup), nsnull))) return(rv); if (!mBackgroundLoadGroup) return(NS_ERROR_UNEXPECTED); } // download engine nsCOMPtr engineContext; rv = NS_NewInternetSearchContext (aOldEngineResource? nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT: nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT, nsnull, aOldEngineResource, nsnull, suggestedCategory, getter_AddRefs(engineContext)); NS_ENSURE_SUCCESS(rv, rv); if (!engineContext) return(NS_ERROR_UNEXPECTED); nsCOMPtr engineURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(engineURI), engineURL))) return(rv); nsCOMPtr engineChannel; if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(engineChannel), engineURI, nsnull, mBackgroundLoadGroup))) return(rv); if (NS_FAILED(rv = engineChannel->AsyncOpen(this, engineContext))) return(rv); // download icon nsCOMPtr iconContext; rv = NS_NewInternetSearchContext (aOldEngineResource? nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT: nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT, nsnull, aOldEngineResource, nsnull, suggestedCategory, getter_AddRefs(iconContext)); NS_ENSURE_SUCCESS(rv, rv); if (!iconContext) return(NS_ERROR_UNEXPECTED); if (iconURL && (*iconURL)) { nsCOMPtr iconURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(iconURI), iconURL))) return(rv); nsCOMPtr iconChannel; if (NS_FAILED(rv = NS_NewChannel(getter_AddRefs(iconChannel), iconURI, nsnull, mBackgroundLoadGroup))) return(rv); if (NS_FAILED(rv = iconChannel->AsyncOpen(this, iconContext))) return(rv); } return(NS_OK); } nsresult InternetSearchDataSource::saveContents(nsIChannel* channel, nsIInternetSearchContext *context, PRUint32 contextType) { NS_ASSERTION(contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT, "unexpected context"); nsresult rv = NS_OK; if (!channel) return(NS_ERROR_UNEXPECTED); if (!context) return(NS_ERROR_UNEXPECTED); // get real URI nsCOMPtr channelURI; if (NS_FAILED(rv = channel->GetURI(getter_AddRefs(channelURI)))) return(rv); if (!channelURI) return(NS_ERROR_NULL_POINTER); nsCAutoString baseName; if (NS_FAILED(rv = channelURI->GetSpec(baseName))) return(rv); PRInt32 slashOffset = baseName.RFindChar(PRUnichar('/')); if (slashOffset < 0) return(NS_ERROR_UNEXPECTED); baseName.Cut(0, slashOffset+1); if (baseName.IsEmpty()) return(NS_ERROR_UNEXPECTED); // make sure that search engines are .src files PRInt32 extensionOffset; if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT) { extensionOffset = baseName.RFind(".src", PR_TRUE); if ((extensionOffset < 0) || (extensionOffset != (PRInt32)(baseName.Length()-4))) { return(NS_ERROR_UNEXPECTED); } } nsCOMPtr outFile; // If the mode is "UPDATE", the output dir is same as the original file // location. Otherwise ("NEW" mode), located in NS_APP_USER_SEARCH_DIR. nsCOMPtr oldResource; rv = context->GetEngine(getter_AddRefs(oldResource)); if (oldResource) { nsCOMPtr oldEngineFile; rv = EngineFileFromResource(oldResource, getter_AddRefs(oldEngineFile)); NS_ENSURE_SUCCESS(rv, rv); rv = oldEngineFile->GetParent(getter_AddRefs(outFile)); NS_ENSURE_SUCCESS(rv, rv); } else { rv = NS_GetSpecialDirectory(NS_APP_USER_SEARCH_DIR, getter_AddRefs(outFile)); if (NS_FAILED(rv)) return rv; } PRBool exists; rv = outFile->Exists(&exists); if (NS_FAILED(rv)) return(rv); if (!exists) { rv = outFile->Create(nsIFile::DIRECTORY_TYPE, 0755); if (NS_FAILED(rv)) return(rv); } const PRUnichar *dataBuf = nsnull; if (NS_FAILED(rv = context->GetBufferConst(&dataBuf))) return(rv); // if no data, then nothing to do // Note: do this before opening file, as it would be truncated PRInt32 bufferLength = 0; if (NS_FAILED(context->GetBufferLength(&bufferLength))) return(rv); if (bufferLength < 1) return(NS_OK); rv = outFile->Append(NS_ConvertUTF8toUCS2(baseName)); if (NS_FAILED(rv)) return rv; // save data to file // Note: write out one character at a time, as we might be dealing // with binary data (such as 0x00) [especially for images] // // XXX - It appears that this is done in order to discard the upper // byte of each PRUnichar. I hope that's OK!! // if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT) { // This is an update operation that we triggered. Remove the old one. outFile->Remove(PR_FALSE); } else { PRBool exists; rv = outFile->Exists(&exists); if (NS_FAILED(rv) || exists) { // We already have a search plugin with this filename; don't // replace it (bug 290038). return NS_ERROR_UNEXPECTED; } } nsCOMPtr outputStream, fileOutputStream; rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutputStream), outFile); if (NS_FAILED(rv)) return rv; rv = NS_NewBufferedOutputStream(getter_AddRefs(outputStream), fileOutputStream, 4096); if (NS_FAILED(rv)) return rv; PRUint32 bytesWritten; for (PRInt32 loop=0; loop < bufferLength; loop++) { const char b = (const char) dataBuf[loop]; outputStream->Write(&b, 1, &bytesWritten); } outputStream->Flush(); outputStream->Close(); if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT) { // check suggested category hint const PRUnichar *hintUni = nsnull; rv = context->GetHintConst(&hintUni); // update graph with various required info SaveEngineInfoIntoGraph(outFile, nsnull, hintUni, dataBuf, PR_FALSE); } else if (contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT) { // update graph with icon info SaveEngineInfoIntoGraph(nsnull, outFile, nsnull, nsnull, PR_FALSE); } // after we're all done with the data buffer, get rid of it context->Truncate(); return(rv); } NS_IMETHODIMP InternetSearchDataSource::GetInternetSearchURL(const char *searchEngineURI, const PRUnichar *searchStr, PRInt16 direction, PRUint16 pageNumber, PRUint16 *whichButtons, char **resultURL) { if (!resultURL) return(NS_ERROR_NULL_POINTER); *resultURL = nsnull; // if we haven't already, load in the engines if (!gEngineListBuilt) DeferredInit(); nsresult rv; nsCOMPtr engine; if (NS_FAILED(rv = gRDFService->GetResource(nsDependentCString(searchEngineURI), getter_AddRefs(engine)))) return(rv); if (!engine) return(NS_ERROR_UNEXPECTED); validateEngine(engine); // if its a engine from a search category, then get its "#Name", // and try to map from that back to the real engine reference if (isSearchCategoryEngineURI(engine)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(engine, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) return(NS_RDF_NO_VALUE); engine = trueEngine; } nsCOMPtr dataLit; rv = FindData(engine, getter_AddRefs(dataLit)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!dataLit) return(NS_ERROR_UNEXPECTED); const PRUnichar *dataUni = nsnull; dataLit->GetValueConst(&dataUni); if (!dataUni) return(NS_RDF_NO_VALUE); nsAutoString text(searchStr), encodingStr, queryEncodingStr; // first look for "search/queryCharset"... if that isn't specified, // then fall back to looking for "search/queryEncoding" (a decimal) GetData(dataUni, "search", 0, "queryCharset", queryEncodingStr); if (queryEncodingStr.IsEmpty()) { GetData(dataUni, "search", 0, "queryEncoding", encodingStr); // decimal string values MapEncoding(encodingStr, queryEncodingStr); } if (!queryEncodingStr.IsEmpty()) { // remember query charset string mQueryEncodingStr = queryEncodingStr; // convert from escaped-UTF_8, to unicode, and then to // the charset indicated by the dataset in question char *utf8data = ToNewUTF8String(text); if (utf8data) { nsCOMPtr textToSubURI = do_GetService(kTextToSubURICID, &rv); if (NS_SUCCEEDED(rv) && (textToSubURI)) { PRUnichar *uni = nsnull; if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert("UTF-8", utf8data, &uni)) && (uni)) { char *charsetData = nsnull; nsCAutoString queryencodingstrC; queryencodingstrC.AssignWithConversion(queryEncodingStr); if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape(queryencodingstrC.get(), uni, &charsetData)) && (charsetData)) { text.AssignWithConversion(charsetData); Recycle(charsetData); } Recycle(uni); } } Recycle(utf8data); } } nsAutoString action, input, method, userVar, name; if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action))) return(rv); // Search only supports the http protocol if (!StringBeginsWith(action, NS_LITERAL_STRING("http:")) && !StringBeginsWith(action, NS_LITERAL_STRING("https:"))) return NS_ERROR_UNEXPECTED; if (NS_FAILED(rv = GetData(dataUni, "search", 0, "method", method))) return(rv); if (NS_FAILED(rv = GetData(dataUni, "search", 0, "name", name))) return(rv); if (NS_FAILED(rv = GetInputs(dataUni, name, userVar, text, input, direction, pageNumber, whichButtons))) return(rv); if (input.IsEmpty()) return(NS_ERROR_UNEXPECTED); // we can only handle HTTP GET if (!method.LowerCaseEqualsLiteral("get")) return(NS_ERROR_UNEXPECTED); // HTTP Get method support action += input; // return a copy of the resulting search URL *resultURL = ToNewCString(action); return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::RememberLastSearchText(const PRUnichar *escapedSearchStr) { nsresult rv; nsCOMPtr textNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_LastText, PR_TRUE, getter_AddRefs(textNode)))) { if (escapedSearchStr != nsnull) { nsresult temprv; nsCOMPtr textLiteral; if (NS_SUCCEEDED(temprv = gRDFService->GetLiteral(escapedSearchStr, getter_AddRefs(textLiteral)))) { if (rv != NS_RDF_NO_VALUE) { mInner->Change(kNC_LastSearchRoot, kNC_LastText, textNode, textLiteral); } else { mInner->Assert(kNC_LastSearchRoot, kNC_LastText, textLiteral, PR_TRUE); } } } else if (rv != NS_RDF_NO_VALUE) { rv = mInner->Unassert(kNC_LastSearchRoot, kNC_LastText, textNode); } } return(rv); } NS_IMETHODIMP InternetSearchDataSource::FindInternetSearchResults(const char *url, PRBool *searchInProgress) { *searchInProgress = PR_FALSE; if (!mInner) return(NS_OK); // if the url doesn't look like a HTTP GET query, just return, // otherwise strip off the query data nsAutoString shortURL; shortURL.AssignWithConversion(url); PRInt32 optionsOffset; if ((optionsOffset = shortURL.FindChar(PRUnichar('?'))) < 0) return(NS_OK); shortURL.Truncate(optionsOffset); // if we haven't already, load in the engines if (!gEngineListBuilt) DeferredInit(); // look in available engines to see if any of them appear // to match this url (minus the GET options) PRBool foundEngine = PR_FALSE; nsresult rv; nsCOMPtr engine; nsCOMPtr arcs; nsAutoString engineURI; nsCOMPtr dataLit; const PRUnichar *dataUni = nsnull; if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_SearchEngineRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs)))) { PRBool hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; nsCOMPtr arc; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; engine = do_QueryInterface(arc); if (!engine) continue; const char *uri = nsnull; engine->GetValueConst(&uri); if (uri) { engineURI.AssignWithConversion(uri); } if (NS_FAILED(rv = FindData(engine, getter_AddRefs(dataLit))) || (rv == NS_RDF_NO_VALUE)) continue; if (!dataLit) continue; dataLit->GetValueConst(&dataUni); if (!dataUni) continue; nsAutoString action; if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action))) continue; if (shortURL.Equals(action, nsCaseInsensitiveStringComparator())) { foundEngine = PR_TRUE; break; } // extension for engines which can have multiple "actions" if (NS_FAILED(rv = GetData(dataUni, "browser", 0, "alsomatch", action))) continue; if (nsString_Find(shortURL, action, PR_TRUE) >= 0) { foundEngine = PR_TRUE; break; } } } if (foundEngine) { nsAutoString searchURL; searchURL.AssignWithConversion(url); // look for query option which is the string the user is searching for nsAutoString userVar, inputUnused, engineNameStr; GetData(dataUni, "search", 0, "name", engineNameStr); if (NS_FAILED(rv = GetInputs(dataUni, engineNameStr, userVar, EmptyString(), inputUnused, 0, 0, 0))) return(rv); if (userVar.IsEmpty()) return(NS_RDF_NO_VALUE); nsAutoString queryStr; queryStr = NS_LITERAL_STRING("?") + userVar + NS_LITERAL_STRING("="); PRInt32 queryOffset; if ((queryOffset = nsString_Find(queryStr, searchURL, PR_TRUE )) < 0) { queryStr = NS_LITERAL_STRING("&") + userVar + NS_LITERAL_STRING("="); queryOffset = nsString_Find(queryStr, searchURL, PR_TRUE); } nsAutoString searchText; if (queryOffset >= 0) { PRInt32 andOffset; searchURL.Right(searchText, searchURL.Length() - queryOffset - queryStr.Length()); if ((andOffset = searchText.FindChar(PRUnichar('&'))) >= 0) { searchText.Truncate(andOffset); } } if (!searchText.IsEmpty()) { // apply charset conversion to the search text if (!mQueryEncodingStr.IsEmpty()) { nsCOMPtr textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { nsCAutoString escapedSearchText; escapedSearchText.AssignWithConversion(searchText); // encoding +'s so as to preserve distinction between + and %2B escapedSearchText.ReplaceSubstring("%25", "%2B25"); escapedSearchText.ReplaceSubstring("+", "%25"); nsCAutoString aCharset; aCharset.AssignWithConversion(mQueryEncodingStr); PRUnichar *uni = nsnull; if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert(aCharset.get(), escapedSearchText.get(), &uni)) && (uni)) { char *convertedSearchText = nsnull; if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape("UTF-8", uni, &convertedSearchText))) { // decoding +'s thereby preserving distinction between + and %2B nsCAutoString unescapedSearchText(convertedSearchText); unescapedSearchText.ReplaceSubstring("%25", "+"); unescapedSearchText.ReplaceSubstring("%2B25", "%25"); searchText.AssignWithConversion(unescapedSearchText.get()); Recycle(convertedSearchText); } Recycle(uni); } } } // remember the text of the last search RememberLastSearchText(searchText.get()); // construct the search query uri engineURI.Assign(NS_LITERAL_STRING("internetsearch:engine=") + engineURI + NS_LITERAL_STRING("&text=") + searchText); #ifdef DEBUG_SEARCH_OUTPUT char *engineMatch = ToNewCString(searchText); if (engineMatch) { printf("FindInternetSearchResults: search for: '%s'\n\n", engineMatch); Recycle(engineMatch); engineMatch = nsnull; } #endif } else { // not able to determine engine URI, so just use the search URL engineURI = searchURL; // clear the text of the last search RememberLastSearchText(nsnull); } // update "#Ref" on LastSearchRoot nsCOMPtr oldNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref, PR_TRUE, getter_AddRefs(oldNode)))) { if (!engineURI.IsEmpty()) { const PRUnichar *uriUni = engineURI.get(); nsCOMPtr uriLiteral; nsresult temprv; if ((uriUni) && (NS_SUCCEEDED(temprv = gRDFService->GetLiteral(uriUni, getter_AddRefs(uriLiteral))))) { if (rv != NS_RDF_NO_VALUE) { rv = mInner->Change(kNC_LastSearchRoot, kNC_Ref, oldNode, uriLiteral); } else { rv = mInner->Assert(kNC_LastSearchRoot, kNC_Ref, uriLiteral, PR_TRUE); } } } else { rv = mInner->Unassert(kNC_LastSearchRoot, kNC_Ref, oldNode); } } // forget about any previous search results ClearResults(PR_FALSE); // do the search DoSearch(nsnull, engine, searchURL, EmptyString()); *searchInProgress = PR_TRUE; } return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::ClearResults(PRBool flushLastSearchRef) { if (!mInner) return(NS_ERROR_UNEXPECTED); // forget any nodes under the last search root nsresult rv; nsCOMPtr arcs; if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_LastSearchRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs)))) { PRBool hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; nsCOMPtr arc; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; nsCOMPtr child (do_QueryInterface(arc)); if (child) { mInner->Unassert(kNC_LastSearchRoot, kNC_Child, child); } // *after* (so that we won't thrash the XUL template builder) unasserting // child node, determine if there are any other references to the child // node in the graph PRBool hasInArcs = PR_FALSE; nsCOMPtr inArcs; if (NS_FAILED(mInner->ArcLabelsIn(child, getter_AddRefs(inArcs))) || (!inArcs)) continue; if (NS_FAILED(inArcs->HasMoreElements(&hasInArcs)) || hasInArcs) continue; // no other references, so also unassert any outgoing arcs nsCOMPtr outArcs; if (NS_FAILED(mInner->ArcLabelsOut(child, getter_AddRefs(outArcs))) || (!outArcs)) continue; PRBool hasMoreOutArcs = PR_TRUE; while (hasMoreOutArcs) { if (NS_FAILED(outArcs->HasMoreElements(&hasMoreOutArcs)) || !hasMoreOutArcs) break; nsCOMPtr outArc; if (NS_FAILED(outArcs->GetNext(getter_AddRefs(outArc)))) break; nsCOMPtr property (do_QueryInterface(outArc)); if (!property) continue; nsCOMPtr target; if (NS_FAILED(mInner->GetTarget(child, property, PR_TRUE, getter_AddRefs(target))) || (!target)) continue; mInner->Unassert(child, property, target); } } } if (flushLastSearchRef) { // forget the last search query nsCOMPtr lastTarget; if (NS_SUCCEEDED(rv = mInner->GetTarget(kNC_LastSearchRoot, kNC_Ref, PR_TRUE, getter_AddRefs(lastTarget))) && (rv != NS_RDF_NO_VALUE)) { nsCOMPtr lastLiteral (do_QueryInterface(lastTarget)); if (lastLiteral) { rv = mInner->Unassert(kNC_LastSearchRoot, kNC_Ref, lastLiteral); } } } return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::ClearResultSearchSites(void) { // forget about any previous search sites if (mInner) { nsresult rv; nsCOMPtr arcs; if (NS_SUCCEEDED(rv = mInner->GetTargets(kNC_SearchResultsSitesRoot, kNC_Child, PR_TRUE, getter_AddRefs(arcs)))) { PRBool hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; nsCOMPtr arc; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; nsCOMPtr child (do_QueryInterface(arc)); if (child) { mInner->Unassert(kNC_SearchResultsSitesRoot, kNC_Child, child); } } } } return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::GetCategoryDataSource(nsIRDFDataSource **ds) { nsresult rv; if (!categoryDataSource) { if (NS_FAILED(rv = GetCategoryList())) { *ds = nsnull; return(rv); } } if (categoryDataSource) { *ds = categoryDataSource.get(); NS_IF_ADDREF(*ds); return(NS_OK); } *ds = nsnull; return(NS_ERROR_FAILURE); } NS_IMETHODIMP InternetSearchDataSource::Stop() { nsresult rv; // cancel any outstanding connections if (mLoadGroup) { nsCOMPtr requests; if (NS_SUCCEEDED(rv = mLoadGroup->GetRequests(getter_AddRefs(requests)))) { PRBool more; while (NS_SUCCEEDED(rv = requests->HasMoreElements(&more)) && more) { nsCOMPtr isupports; if (NS_FAILED(rv = requests->GetNext(getter_AddRefs(isupports)))) break; nsCOMPtr request (do_QueryInterface(isupports)); if (!request) continue; request->Cancel(NS_BINDING_ABORTED); } } mLoadGroup->Cancel(NS_BINDING_ABORTED); } // remove any loading icons nsCOMPtr arcs; if (NS_SUCCEEDED(rv = mInner->GetSources(kNC_loading, kTrueLiteral, PR_TRUE, getter_AddRefs(arcs)))) { PRBool hasMore = PR_TRUE; while (hasMore) { if (NS_FAILED(arcs->HasMoreElements(&hasMore)) || !hasMore) break; nsCOMPtr arc; if (NS_FAILED(arcs->GetNext(getter_AddRefs(arc)))) break; nsCOMPtr src (do_QueryInterface(arc)); if (src) { mInner->Unassert(src, kNC_loading, kTrueLiteral); } } } return(NS_OK); } nsresult InternetSearchDataSource::BeginSearchRequest(nsIRDFResource *source, PRBool doNetworkRequest) { nsresult rv = NS_OK; const char *sourceURI = nsnull; if (NS_FAILED(rv = source->GetValueConst(&sourceURI))) return(rv); nsAutoString uri; uri.AssignWithConversion(sourceURI); if (uri.Find("internetsearch:") != 0) return(NS_ERROR_FAILURE); // forget about any previous search results ClearResults(PR_TRUE); // forget about any previous search sites ClearResultSearchSites(); // remember the last search query const PRUnichar *uriUni = uri.get(); nsCOMPtr uriLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(uriUni, getter_AddRefs(uriLiteral)))) { rv = mInner->Assert(kNC_LastSearchRoot, kNC_Ref, uriLiteral, PR_TRUE); } uri.Cut(0, strlen("internetsearch:")); nsVoidArray *engineArray = new nsVoidArray; if (!engineArray) return(NS_ERROR_FAILURE); nsAutoString text; // parse up attributes while(!uri.IsEmpty()) { nsAutoString item; PRInt32 andOffset = uri.Find("&"); if (andOffset >= 0) { uri.Left(item, andOffset); uri.Cut(0, andOffset + 1); } else { item = uri; uri.Truncate(); } PRInt32 equalOffset = item.Find("="); if (equalOffset < 0) break; nsAutoString attrib, value; item.Left(attrib, equalOffset); value = item; value.Cut(0, equalOffset + 1); if (!attrib.IsEmpty() && !value.IsEmpty()) { if (attrib.LowerCaseEqualsLiteral("engine")) { if ((value.Find(kEngineProtocol) == 0) || (value.Find(kURINC_SearchCategoryEnginePrefix) == 0)) { char *val = ToNewCString(value); if (val) { engineArray->AppendElement(val); } } } else if (attrib.LowerCaseEqualsLiteral("text")) { text = value; } } } mInner->Assert(source, kNC_loading, kTrueLiteral, PR_TRUE); PRBool requestInitiated = PR_FALSE; // loop over specified search engines while (engineArray->Count() > 0) { char *baseFilename = (char *)(engineArray->ElementAt(0)); engineArray->RemoveElementAt(0); if (!baseFilename) continue; #ifdef DEBUG_SEARCH_OUTPUT printf("Search engine to query: '%s'\n", baseFilename); #endif nsCOMPtr engine; gRDFService->GetResource(nsDependentCString(baseFilename), getter_AddRefs(engine)); nsCRT::free(baseFilename); baseFilename = nsnull; if (!engine) continue; // if its a engine from a search category, then get its "#Name", // and map from that back to the real engine reference; if an // error occurs, finish processing the rest of the engines, // don't just break/return out if (isSearchCategoryEngineURI(engine)) { nsCOMPtr trueEngine; rv = resolveSearchCategoryEngineURI(engine, getter_AddRefs(trueEngine)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); if (!trueEngine) continue; engine = trueEngine; } // mark this as a search site if (mInner) { mInner->Assert(kNC_SearchResultsSitesRoot, kNC_Child, engine, PR_TRUE); } if (doNetworkRequest) { DoSearch(source, engine, EmptyString(), text); requestInitiated = PR_TRUE; } } delete engineArray; engineArray = nsnull; if (!requestInitiated) { Stop(); } return(rv); } nsresult InternetSearchDataSource::FindData(nsIRDFResource *engine, nsIRDFLiteral **dataLit) { if (!engine) return(NS_ERROR_NULL_POINTER); if (!dataLit) return(NS_ERROR_NULL_POINTER); *dataLit = nsnull; if (!mInner) return(NS_RDF_NO_VALUE); nsresult rv; nsCOMPtr dataTarget = nsnull; if (NS_SUCCEEDED((rv = mInner->GetTarget(engine, kNC_Data, PR_TRUE, getter_AddRefs(dataTarget)))) && (dataTarget)) { nsCOMPtr aLiteral (do_QueryInterface(dataTarget)); if (!aLiteral) return(NS_ERROR_UNEXPECTED); *dataLit = aLiteral; NS_IF_ADDREF(*dataLit); return(NS_OK); } nsCOMPtr engineFile; rv = EngineFileFromResource(engine, getter_AddRefs(engineFile)); if (NS_FAILED(rv)) return rv; nsString data; rv = ReadFileContents(engineFile, data); if (NS_FAILED(rv)) { return(rv); } // save file contents if (data.IsEmpty()) return(NS_ERROR_UNEXPECTED); rv = updateDataHintsInGraph(engine, data.get()); nsCOMPtr aLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(data.get(), getter_AddRefs(aLiteral)))) { *dataLit = aLiteral; NS_IF_ADDREF(*dataLit); } return(rv); } nsresult InternetSearchDataSource::EngineFileFromResource(nsIRDFResource *aResource, nsILocalFile **aResult) { nsresult rv = NS_OK; // get resource uri const char *engineURI = nsnull; rv = aResource->GetValueConst(&engineURI); NS_ENSURE_SUCCESS(rv, rv); // remove protocol from uri and get escaped file path nsCAutoString nativePath; nativePath.Assign(engineURI); NS_ENSURE_TRUE(StringBeginsWith(nativePath, NS_LITERAL_CSTRING(kEngineProtocol)), NS_ERROR_FAILURE); nativePath.Cut(0, sizeof(kEngineProtocol) - 1); // unescape it NS_UnescapeURL(nativePath); #ifdef DEBUG_SEARCH_OUTPUT printf("InternetSearchDataSource::EngineFileFromResource\n" "File Path: %s\n", nativePath.get()); #endif rv = NS_NewNativeLocalFile(nativePath, PR_TRUE, aResult); return rv; } nsresult InternetSearchDataSource::DecodeData(const char *aCharset, const PRUnichar *aInString, PRUnichar **aOutString) { nsresult rv; nsCOMPtr charsetConv = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr unicodeDecoder; rv = charsetConv->GetUnicodeDecoder(aCharset, getter_AddRefs(unicodeDecoder)); // Use the sherlock default charset in case of failure if (NS_FAILED(rv)) rv = charsetConv->GetUnicodeDecoderRaw("x-mac-roman", getter_AddRefs(unicodeDecoder)); NS_ENSURE_SUCCESS(rv, rv); // This fixes the corruption occured in InternetSearchDataSource::ReadFileContents() // (eg. aValue contains "0x0082 0x00a1" for "0x82 0xa1" shift_jis double-byte char) NS_LossyConvertUCS2toASCII value(aInString); PRInt32 srcLength = value.Length(); PRInt32 outUnicodeLen; rv = unicodeDecoder->GetMaxLength(value.get(), srcLength, &outUnicodeLen); NS_ENSURE_SUCCESS(rv, rv); *aOutString = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc((outUnicodeLen + 1) * sizeof(PRUnichar))); NS_ENSURE_TRUE(*aOutString, NS_ERROR_OUT_OF_MEMORY); rv = unicodeDecoder->Convert(value.get(), &srcLength, *aOutString, &outUnicodeLen); NS_ENSURE_SUCCESS(rv, rv); (*aOutString)[outUnicodeLen] = (PRUnichar)'\0'; return rv; } nsresult InternetSearchDataSource::updateDataHintsInGraph(nsIRDFResource *engine, const PRUnichar *dataUni) { nsresult rv = NS_OK; // save/update search engine data nsCOMPtr dataLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(dataUni, getter_AddRefs(dataLiteral)))) { updateAtom(mInner, engine, kNC_Data, dataLiteral, nsnull); } // save/update name of search engine (as specified in file) nsAutoString scriptCodeValue; const char * charsetName = MapScriptCodeToCharsetName(0); nsXPIDLString decodedValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "sourceTextEncoding", scriptCodeValue)) && !scriptCodeValue.IsEmpty()) { PRInt32 err; PRInt32 scriptCode = scriptCodeValue.ToInteger(&err); if (NS_SUCCEEDED(err)) charsetName = MapScriptCodeToCharsetName(scriptCode); } nsAutoString nameValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "name", nameValue))) { rv = DecodeData(charsetName, nameValue.get(), getter_Copies(decodedValue)); nsCOMPtr nameLiteral; if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv = gRDFService->GetLiteral(decodedValue.get(), getter_AddRefs(nameLiteral)))) { rv = updateAtom(mInner, engine, kNC_Name, nameLiteral, nsnull); } } // save/update description of search engine (if specified) nsAutoString descValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "description", descValue))) { rv = DecodeData(charsetName, descValue.get(), getter_Copies(decodedValue)); nsCOMPtr descLiteral; if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv = gRDFService->GetLiteral(decodedValue.get(), getter_AddRefs(descLiteral)))) { rv = updateAtom(mInner, engine, kNC_Description, descLiteral, nsnull); } } // save/update version of search engine (if specified) nsAutoString versionValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "version", versionValue))) { nsCOMPtr versionLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(versionValue.get(), getter_AddRefs(versionLiteral)))) { rv = updateAtom(mInner, engine, kNC_Version, versionLiteral, nsnull); } } nsAutoString buttonValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "actionButton", buttonValue))) { nsCOMPtr buttonLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(buttonValue.get(), getter_AddRefs(buttonLiteral)))) { rv = updateAtom(mInner, engine, kNC_actionButton, buttonLiteral, nsnull); } } nsAutoString barValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "actionBar", barValue))) { nsCOMPtr barLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(barValue.get(), getter_AddRefs(barLiteral)))) { rv = updateAtom(mInner, engine, kNC_actionBar, barLiteral, nsnull); } } nsAutoString searchFormValue; if (NS_SUCCEEDED(rv = GetData(dataUni, "search", 0, "searchForm", searchFormValue))) { nsCOMPtr searchFormLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(searchFormValue.get(), getter_AddRefs(searchFormLiteral)))) { rv = updateAtom(mInner, engine, kNC_searchForm, searchFormLiteral, nsnull); } } PRBool updatePrivateFiles = PR_FALSE; rv = mInner->HasAssertion(engine, kNC_SearchType, kNC_Engine, PR_TRUE, &updatePrivateFiles); if (NS_SUCCEEDED(rv) && updatePrivateFiles) { // rjc says: so here is our strategy. The spec says that the "search"|"update" // attribute MUST refer to a binhex-ed file (i.e. ends with ".src.hqx"). We don't // support binhex (due to being cross-platform minded folks) and, even if we did, // its not enough info to figure out what the appropriate icon should be. // The answer: we're add additional attributes in our private section // to re-define these values. If they aren't there, we'll fallback to the // section values and try and make logical choices: for example, if we have an // "update" URL which ends with ".src.hqx", we'll strip off the ".hqx" part and // check to see if it exists... which at least makes it possible for a web site // to put up both a binhexed version and a straight text version of the search file. // get update URL and # of days to check for updates // Note: only check for updates on our private search files nsAutoString updateStr, updateIconStr, updateCheckDaysStr; GetData(dataUni, "browser", 0, "update", updateStr); if (updateStr.IsEmpty()) { // fallback to trying "search"|"updateCheckDays" GetData(dataUni, "search", 0, "update", updateStr); // if we have a ".hqx" extension, strip it off nsAutoString extension; updateStr.Right(extension, 4); if (extension.LowerCaseEqualsLiteral(".hqx")) { updateStr.Truncate(updateStr.Length() - 4); } // now, either way, ensure that we have a ".src" file updateStr.Right(extension, 4); if (!extension.LowerCaseEqualsLiteral(".src")) { // and if we don't, toss it updateStr.Truncate(); } } else { // note: its OK if the "updateIcon" isn't specified GetData(dataUni, "browser", 0, "updateIcon", updateIconStr); } if (!updateStr.IsEmpty()) { GetData(dataUni, "browser", 0, "updateCheckDays", updateCheckDaysStr); if (updateCheckDaysStr.IsEmpty()) { // fallback to trying "search"|"updateCheckDays" GetData(dataUni, "search", 0, "updateCheckDays", updateCheckDaysStr); } } if (!updateStr.IsEmpty() && !updateCheckDaysStr.IsEmpty()) { nsCOMPtr updateLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(updateStr.get(), getter_AddRefs(updateLiteral)))) { rv = updateAtom(mInner, engine, kNC_Update, updateLiteral, nsnull); } PRInt32 err; PRInt32 updateDays = updateCheckDaysStr.ToInteger(&err); if ((err) || (updateDays < 1)) { // default to something sane updateDays = 3; } nsCOMPtr updateCheckDaysLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral(updateDays, getter_AddRefs(updateCheckDaysLiteral)))) { rv = updateAtom(mInner, engine, kNC_UpdateCheckDays, updateCheckDaysLiteral, nsnull); } if (!updateIconStr.IsEmpty()) { nsCOMPtr updateIconLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(updateIconStr.get(), getter_AddRefs(updateIconLiteral)))) { rv = updateAtom(mInner, engine, kNC_UpdateIcon, updateIconLiteral, nsnull); } } } } return(rv); } nsresult InternetSearchDataSource::updateAtom(nsIRDFDataSource *db, nsIRDFResource *src, nsIRDFResource *prop, nsIRDFNode *newValue, PRBool *dirtyFlag) { nsresult rv; nsCOMPtr oldValue; if (dirtyFlag != nsnull) { *dirtyFlag = PR_FALSE; } if (NS_SUCCEEDED(rv = db->GetTarget(src, prop, PR_TRUE, getter_AddRefs(oldValue))) && (rv != NS_RDF_NO_VALUE)) { rv = db->Change(src, prop, oldValue, newValue); if ((oldValue.get() != newValue) && (dirtyFlag != nsnull)) { *dirtyFlag = PR_TRUE; } } else { rv = db->Assert(src, prop, newValue, PR_TRUE); if (dirtyFlag != nsnull) { *dirtyFlag = PR_TRUE; } } return(rv); } struct encodings { const char *numericEncoding; const char *stringEncoding; }; nsresult InternetSearchDataSource::MapEncoding(const nsString &numericEncoding, nsString &stringEncoding) { // XXX we need to have a full table of numeric --> string conversions struct encodings encodingList[] = { { "0", "x-mac-roman" }, { "6", "x-mac-greek" }, { "35", "x-mac-turkish" }, { "513", "ISO-8859-1" }, { "514", "ISO-8859-2" }, { "517", "ISO-8859-5" }, { "518", "ISO-8859-6" }, { "519", "ISO-8859-7" }, { "520", "ISO-8859-8" }, { "521", "ISO-8859-9" }, { "1049", "IBM864" }, { "1280", "windows-1252" }, { "1281", "windows-1250" }, { "1282", "windows-1251" }, { "1283", "windows-1253" }, { "1284", "windows-1254" }, { "1285", "windows-1255" }, { "1286", "windows-1256" }, { "1536", "us-ascii" }, { "1584", "GB2312" }, { "1585", "x-gbk" }, { "1600", "EUC-KR" }, { "2080", "ISO-2022-JP" }, { "2096", "ISO-2022-CN" }, { "2112", "ISO-2022-KR" }, { "2336", "EUC-JP" }, { "2352", "GB2312" }, { "2353", "x-euc-tw" }, { "2368", "EUC-KR" }, { "2561", "Shift_JIS" }, { "2562", "KOI8-R" }, { "2563", "Big5" }, { "2565", "HZ-GB-2312" }, { nsnull, nsnull } }; if (!numericEncoding.IsEmpty()) { for (PRUint32 i = 0; encodingList[i].numericEncoding != nsnull; i++) { if (numericEncoding.EqualsASCII(encodingList[i].numericEncoding)) { stringEncoding.AssignASCII(encodingList[i].stringEncoding); return NS_OK; } } } // Still no encoding, fall back to default charset if possible nsXPIDLString defCharset; nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); if (prefs) prefs->GetLocalizedUnicharPref("intl.charset.default", getter_Copies(defCharset)); if (!defCharset.IsEmpty()) stringEncoding = defCharset; else // make "ISO-8859-1" as the default (not "UTF-8") stringEncoding.AssignLiteral("ISO-8859-1"); return(NS_OK); } const char * const InternetSearchDataSource::MapScriptCodeToCharsetName(PRUint32 aScriptCode) { // Script codes listed here are taken from Inside Macintosh Text. // Used TECGetTextEncodingInternetName to map script code to charset name. // Some are edited to match with standard name (e.g. "x-mac-japanese" -> "Shift_JIS"). // In case no converter can be found for a charset name, // the default sherlock charset "x-mac-roman" should be used. // static const char* const scriptList[] = { "x-mac-roman", // 0 "Shift_JIS", // 1 "Big5", // 2 "EUC-KR", // 3 "X-MAC-ARABIC", // 4 "X-MAC-HEBREW", // 5 "X-MAC-GREEK", // 6 "X-MAC-CYRILLIC", // 7 "X-MAC-DEVANAGARI" , // 9 "X-MAC-GURMUKHI", // 10 "X-MAC-GUJARATI", // 11 "X-MAC-ORIYA", // 12 "X-MAC-BENGALI", // 13 "X-MAC-TAMIL", // 14 "X-MAC-TELUGU", // 15 "X-MAC-KANNADA", // 16 "X-MAC-MALAYALAM", // 17 "X-MAC-SINHALESE", // 18 "X-MAC-BURMESE", // 19 "X-MAC-KHMER", // 20 "X-MAC-THAI", // 21 "X-MAC-LAOTIAN", // 22 "X-MAC-GEORGIAN", // 23 "X-MAC-ARMENIAN", // 24 "GB2312", // 25 "X-MAC-TIBETAN", // 26 "X-MAC-MONGOLIAN", // 27 "X-MAC-ETHIOPIC", // 28 "X-MAC-CENTRALEURROMAN", // 29 "X-MAC-VIETNAMESE", // 30 "X-MAC-EXTARABIC", // 31 }; if (aScriptCode >= NS_ARRAY_LENGTH(scriptList)) aScriptCode = 0; return scriptList[aScriptCode]; } nsresult InternetSearchDataSource::validateEngine(nsIRDFResource *engine) { nsresult rv; // confirm whether the user wants to update plugins. nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); PRBool userAllowed = PR_TRUE; rv = prefBranch->GetBoolPref("browser.search.update", &userAllowed); // if the pref value is not set or wrong type, don't stop here. if (NS_SUCCEEDED(rv) && !userAllowed) return NS_OK; #ifdef DEBUG_SEARCH_UPDATES const char *engineURI = nsnull; engine->GetValueConst(&engineURI); #endif // get the engines "updateCheckDays" value nsCOMPtr updateCheckDaysNode; rv = mInner->GetTarget(engine, kNC_UpdateCheckDays, PR_TRUE, getter_AddRefs(updateCheckDaysNode)); if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); nsCOMPtr updateCheckDaysLiteral (do_QueryInterface(updateCheckDaysNode)); PRInt32 updateCheckDays; updateCheckDaysLiteral->GetValue(&updateCheckDays); // convert updateCheckDays from days to seconds; #ifndef DEBUG_SEARCH_UPDATES PRInt32 updateCheckSecs = updateCheckDays * (60 * 60 * 24); #else // rjc note: for debugging, use as minutes instead days PRInt32 updateCheckSecs = updateCheckDays * 60; #endif nsCOMPtr aNode; rv = mLocalstore->GetTarget(engine, kWEB_LastPingDate, PR_TRUE, getter_AddRefs(aNode)); if (NS_FAILED(rv)) return(rv); // if aNode is a valid entry, we should check the durationSecs. if (rv != NS_RDF_NO_VALUE) { // get last validate date/time nsCOMPtr lastCheckLiteral(do_QueryInterface(aNode)); if (!lastCheckLiteral) return NS_ERROR_UNEXPECTED; const PRUnichar *lastCheckUni = nsnull; lastCheckLiteral->GetValueConst(&lastCheckUni); if (!lastCheckUni) return NS_ERROR_UNEXPECTED; PRInt32 lastCheckInt = 0, err = 0; lastCheckInt = nsDependentString(lastCheckUni).ToInteger(&err); // signed int32 -> unsigned int32 rv = (nsresult) err; NS_ENSURE_SUCCESS(rv, rv); // get the current date/time [from microseconds (PRTime) to seconds] PRTime now64 = PR_Now(), temp64, million; LL_I2L(million, PR_USEC_PER_SEC); LL_DIV(temp64, now64, million); PRInt32 now32; LL_L2I(now32, temp64); // calculate duration since last validation // just return if it's too early to check again PRInt32 durationSecs = now32 - lastCheckInt; if (durationSecs < updateCheckSecs) { #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine '%s' is valid for %d more seconds.\n", engineURI, (updateCheckSecs-durationSecs)); #endif return NS_OK; } } // search engine needs to be checked again, so add it into the to-be-validated array PRInt32 elementIndex = mUpdateArray->IndexOf(engine); if (elementIndex < 0) { mUpdateArray->AppendElement(engine); #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine '%s' is now queued to be validated" " via HTTP HEAD method.\n", engineURI); #endif } else { #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine '%s' is already in queue to be validated.\n", engineURI); #endif } return(NS_OK); } nsresult InternetSearchDataSource::DoSearch(nsIRDFResource *source, nsIRDFResource *engine, const nsString &fullURL, const nsString &text) { nsresult rv; nsAutoString textTemp(text); if (!mInner) return(NS_RDF_NO_VALUE); // Note: source can be null // if (!source) return(NS_ERROR_NULL_POINTER); if (!engine) return(NS_ERROR_NULL_POINTER); validateEngine(engine); nsCOMPtr unicodeDecoder; nsAutoString action, methodStr, input, userVar; nsCOMPtr dataLit; if (NS_FAILED(rv = FindData(engine, getter_AddRefs(dataLit))) || (rv == NS_RDF_NO_VALUE)) return(rv); const PRUnichar *dataUni = nsnull; dataLit->GetValueConst(&dataUni); if (!dataUni) return(NS_RDF_NO_VALUE); if (!fullURL.IsEmpty()) { action.Assign(fullURL); methodStr.AssignLiteral("get"); } else { if (NS_FAILED(rv = GetData(dataUni, "search", 0, "action", action))) return(rv); if (NS_FAILED(rv = GetData(dataUni, "search", 0, "method", methodStr))) return(rv); } nsAutoString encodingStr, resultEncodingStr; // first look for "interpret/charset"... if that isn't specified, // then fall back to looking for "interpret/resultEncoding" (a decimal) GetData(dataUni, "interpret", 0, "charset", resultEncodingStr); if (resultEncodingStr.IsEmpty()) { GetData(dataUni, "interpret", 0, "resultEncoding", encodingStr); // decimal string values MapEncoding(encodingStr, resultEncodingStr); } // rjc note: ignore "interpret/resultTranslationEncoding" as well as // "interpret/resultTranslationFont" since we always convert results to Unicode if (!resultEncodingStr.IsEmpty()) { nsCOMPtr charsetConv = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { NS_LossyConvertUCS2toASCII charset(resultEncodingStr); rv = charsetConv->GetUnicodeDecoder(charset.get(), getter_AddRefs(unicodeDecoder)); } } // first look for "search/queryCharset"... if that isn't specified, // then fall back to looking for "search/queryEncoding" (a decimal) nsAutoString queryEncodingStr; GetData(dataUni, "search", 0, "queryCharset", queryEncodingStr); if (queryEncodingStr.IsEmpty()) { GetData(dataUni, "search", 0, "queryEncoding", encodingStr); // decimal string values MapEncoding(encodingStr, queryEncodingStr); } if (!queryEncodingStr.IsEmpty()) { // convert from escaped-UTF_8, to unicode, and then to // the charset indicated by the dataset in question char *utf8data = ToNewUTF8String(textTemp); if (utf8data) { nsCOMPtr textToSubURI = do_GetService(kTextToSubURICID, &rv); if (NS_SUCCEEDED(rv) && (textToSubURI)) { PRUnichar *uni = nsnull; if (NS_SUCCEEDED(rv = textToSubURI->UnEscapeAndConvert("UTF-8", utf8data, &uni)) && (uni)) { char *charsetData = nsnull; nsCAutoString queryencodingstrC; queryencodingstrC.AssignWithConversion(queryEncodingStr); if (NS_SUCCEEDED(rv = textToSubURI->ConvertAndEscape(queryencodingstrC.get(), uni, &charsetData)) && (charsetData)) { textTemp.AssignWithConversion(charsetData); Recycle(charsetData); } Recycle(uni); } } Recycle(utf8data); } } if (fullURL.IsEmpty() && methodStr.LowerCaseEqualsLiteral("get")) { nsAutoString engineNameStr; GetData(dataUni, "search", 0, "name", engineNameStr); if (NS_FAILED(rv = GetInputs(dataUni, engineNameStr, userVar, textTemp, input, 0, 0, 0))) return(rv); if (input.IsEmpty()) return(NS_ERROR_UNEXPECTED); // HTTP Get method support action += input; } nsCOMPtr context; if (NS_FAILED(rv = NS_NewInternetSearchContext(nsIInternetSearchContext::WEB_SEARCH_CONTEXT, source, engine, unicodeDecoder, nsnull, getter_AddRefs(context)))) return(rv); if (!context) return(NS_ERROR_UNEXPECTED); nsCOMPtr url; if (NS_SUCCEEDED(rv = NS_NewURI(getter_AddRefs(url), action))) { nsCOMPtr channel; if (NS_SUCCEEDED(rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull, mLoadGroup))) { // send a "MultiSearch" header nsCOMPtr httpMultiChannel (do_QueryInterface(channel)); if (httpMultiChannel) { httpMultiChannel->SetRequestHeader(NS_LITERAL_CSTRING("MultiSearch"), NS_LITERAL_CSTRING("true"), PR_FALSE); } // get it just from the cache if we can (do not validate) channel->SetLoadFlags(nsIRequest::LOAD_FROM_CACHE); if (methodStr.LowerCaseEqualsLiteral("post")) { nsCOMPtr httpChannel (do_QueryInterface(channel)); if (httpChannel) { httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST")); // construct post data to send nsAutoString postStr; postStr.AssignASCII(POSTHEADER_PREFIX); postStr.AppendInt(input.Length(), 10); postStr.AppendASCII(POSTHEADER_SUFFIX); postStr += input; nsCOMPtr postDataStream; nsCAutoString poststrC; poststrC.AssignWithConversion(postStr); if (NS_SUCCEEDED(rv = NS_NewPostDataStream(getter_AddRefs(postDataStream), PR_FALSE, poststrC, 0))) { nsCOMPtr uploadChannel(do_QueryInterface(httpChannel)); NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); uploadChannel->SetUploadStream(postDataStream, EmptyCString(), -1); } } } nsCOMPtr request; rv = channel->AsyncOpen(this, context); } } // dispose of any last HTML results page if (mInner) { nsCOMPtr htmlNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(engine, kNC_HTML, PR_TRUE, getter_AddRefs(htmlNode))) && (rv != NS_RDF_NO_VALUE)) { rv = mInner->Unassert(engine, kNC_HTML, htmlNode); } } // start "loading" animation for this search engine if (NS_SUCCEEDED(rv) && (mInner)) { // remove status icon so that loading icon style can be used nsCOMPtr engineIconNode = nsnull; mInner->GetTarget(engine, kNC_StatusIcon, PR_TRUE, getter_AddRefs(engineIconNode)); if (engineIconNode) { rv = mInner->Unassert(engine, kNC_StatusIcon, engineIconNode); } mInner->Assert(engine, kNC_loading, kTrueLiteral, PR_TRUE); } return(rv); } nsresult InternetSearchDataSource::SaveEngineInfoIntoGraph(nsIFile *file, nsIFile *icon, const PRUnichar *categoryHint, const PRUnichar *dataUni, PRBool isSystemSearchFile) { nsresult rv = NS_OK; if (!file && !icon) return(NS_ERROR_UNEXPECTED); nsCOMPtr searchRes; nsCOMPtr categoryRes; nsCOMPtr native; if (icon != nsnull) { native = icon; } if (file != nsnull) { native = file; } PRBool exists; rv = native->Exists(&exists); if (NS_FAILED(rv)) return(rv); if (!exists) return(NS_ERROR_UNEXPECTED); nsAutoString basename; rv = native->GetLeafName(basename); if (NS_FAILED(rv)) return rv; // ensure that the basename points to the search engine file PRInt32 extensionOffset; if ((extensionOffset = basename.RFindChar(PRUnichar('.'))) > 0) { basename.Truncate(extensionOffset); basename.AppendLiteral(".src"); } nsCAutoString filePath; rv = native->GetNativePath(filePath); if (NS_FAILED(rv)) return rv; nsAutoString searchURL; searchURL.AssignASCII(kEngineProtocol); char *uriCescaped = nsEscape(filePath.get(), url_Path); if (!uriCescaped) return(NS_ERROR_NULL_POINTER); searchURL.AppendASCII(uriCescaped); nsCRT::free(uriCescaped); if ((extensionOffset = searchURL.RFindChar(PRUnichar('.'))) > 0) { searchURL.Truncate(extensionOffset); searchURL.AppendLiteral(".src"); } if (NS_FAILED(rv = gRDFService->GetUnicodeResource(searchURL, getter_AddRefs(searchRes)))) return(rv); // save the basename reference if (!basename.IsEmpty()) { basename.Insert(NS_ConvertASCIItoUTF16(kURINC_SearchCategoryEngineBasenamePrefix), 0); if (NS_FAILED(rv = gRDFService->GetUnicodeResource(basename, getter_AddRefs(categoryRes)))) return(rv); nsCOMPtr searchLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(basename.get(), getter_AddRefs(searchLiteral)))) { if (file) { updateAtom(mInner, searchRes, kNC_URL, searchLiteral, nsnull); } } } if (!searchRes) return(NS_ERROR_UNEXPECTED); if (!categoryRes) return(NS_ERROR_UNEXPECTED); nsAutoString iconURL; if (icon) { nsCAutoString iconFileURL; if (NS_FAILED(rv = NS_GetURLSpecFromFile(icon, iconFileURL))) return(rv); AppendUTF8toUTF16(iconFileURL, iconURL); } // save icon url (if we have one) if (iconURL.Length() > 0) { nsCOMPtr iconLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(iconURL.get(), getter_AddRefs(iconLiteral)))) { updateAtom(mInner, searchRes, kNC_Icon, iconLiteral, nsnull); } } if (!isSystemSearchFile) { // mark our private search files, so that we can distinguish // between ours and any that are included with the OS updateAtom(mInner, searchRes, kNC_SearchType, kNC_Engine, nsnull); } if (dataUni != nsnull) { updateDataHintsInGraph(searchRes, dataUni); // finally, if we have a category hint, add this new engine into the category (if it exists) if (categoryHint && categoryDataSource) { nsCOMPtr catLiteral; rv = gRDFService->GetLiteral(categoryHint, getter_AddRefs(catLiteral)); nsCOMPtr catSrc; if (catLiteral) { rv = categoryDataSource->GetSource(kNC_Title, catLiteral, PR_TRUE, getter_AddRefs(catSrc)); } const char *catURI = nsnull; if (catSrc) { rv = catSrc->GetValueConst(&catURI); } nsCOMPtr catRes; if (catURI) { nsAutoString catList; catList.AssignASCII(kURINC_SearchCategoryPrefix); catList.AppendWithConversion(catURI); gRDFService->GetUnicodeResource(catList, getter_AddRefs(catRes)); } nsCOMPtr container; if (catRes) { container = do_CreateInstance(kRDFContainerCID, &rv); } if (container) { rv = container->Init(categoryDataSource, catRes); if (NS_SUCCEEDED(rv)) { rv = gRDFC->MakeSeq(categoryDataSource, catRes, nsnull); } if (NS_SUCCEEDED(rv)) { PRInt32 searchIndex = -1; if (NS_SUCCEEDED(rv = container->IndexOf(categoryRes, &searchIndex)) && (searchIndex < 0)) { rv = container->AppendElement(categoryRes); } } if (NS_SUCCEEDED(rv)) { // flush categoryDataSource nsCOMPtr remoteCategoryStore; remoteCategoryStore = do_QueryInterface(categoryDataSource); if (remoteCategoryStore) { remoteCategoryStore->Flush(); } } } } } // Note: add the child relationship last PRBool hasChildFlag = PR_FALSE; rv = mInner->HasAssertion(kNC_SearchEngineRoot, kNC_Child, searchRes, PR_TRUE, &hasChildFlag); if (NS_SUCCEEDED(rv) && !hasChildFlag) { mInner->Assert(kNC_SearchEngineRoot, kNC_Child, searchRes, PR_TRUE); } return(NS_OK); } nsresult InternetSearchDataSource::GetSearchEngineList(nsIFile *searchDir, PRBool isSystemSearchFile) { nsresult rv = NS_OK; if (!mInner) { return(NS_RDF_NO_VALUE); } PRBool hasMore = PR_FALSE; nsCOMPtr dirIterator; rv = searchDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); if (NS_FAILED(rv)) return rv; nsCOMPtr dirEntry; while ((rv = dirIterator->HasMoreElements(&hasMore)) == NS_OK && hasMore) { rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); if (NS_FAILED(rv)) continue; // Ignore hidden files/directories PRBool isHidden; rv = dirEntry->IsHidden(&isHidden); if (NS_FAILED(rv) || isHidden) continue; PRBool isDirectory; rv = dirEntry->IsDirectory(&isDirectory); if (NS_FAILED(rv)) continue; if (isDirectory) { GetSearchEngineList(dirEntry, isSystemSearchFile); continue; } // Skip over empty files // Note: use GetFileSize even on Mac [instead of GetFileSizeWithResFork()] // as we want the size of ONLY the data fork PRInt64 fileSize; rv = dirEntry->GetFileSize(&fileSize); if (NS_FAILED(rv) || (fileSize == 0)) continue; nsAutoString uri; rv = dirEntry->GetPath(uri); if (NS_FAILED(rv)) continue; PRInt32 len = uri.Length(); if (len < 5) { continue; } // check the extension (must be ".src") nsAutoString extension; if ((uri.Right(extension, 4) != 4) || (!extension.LowerCaseEqualsLiteral(".src"))) { continue; } // check for various icons PRBool foundIconFlag = PR_FALSE; nsAutoString temp; nsCOMPtr iconFile, loopFile; static const char *extensions[] = { ".gif", ".jpg", ".jpeg", ".png", nsnull, }; for (int ext_count = 0; extensions[ext_count] != nsnull; ext_count++) { temp = Substring(uri, 0, uri.Length()-4); temp.Append(NS_ConvertASCIItoUCS2(extensions[ext_count])); rv = NS_NewLocalFile(temp, PR_TRUE, getter_AddRefs(loopFile)); if (NS_FAILED(rv)) return rv; rv = loopFile->Exists(&foundIconFlag); if (NS_FAILED(rv)) return rv; if (!foundIconFlag) continue; rv = loopFile->IsFile(&foundIconFlag); if (NS_FAILED(rv)) return rv; if (foundIconFlag) { iconFile = loopFile; break; } } SaveEngineInfoIntoGraph(dirEntry, iconFile, nsnull, nsnull, isSystemSearchFile); } #ifdef MOZ_PHOENIX if (!gReorderedEngineList) ReorderEngineList(); #endif return(rv); } nsresult InternetSearchDataSource::ReadFileContents(nsILocalFile *localFile, nsString& sourceContents) { nsresult rv = NS_ERROR_FAILURE; PRInt64 contentsLen, total = 0; char *contents; NS_ENSURE_ARG_POINTER(localFile); sourceContents.Truncate(); rv = localFile->GetFileSize(&contentsLen); if (NS_FAILED(rv)) return rv; if (contentsLen > 0) { contents = new char [contentsLen + 1]; if (contents) { nsCOMPtr inputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), localFile); if (NS_FAILED(rv)) { delete [] contents; return rv; } PRUint32 howMany; while (total < contentsLen) { rv = inputStream->Read(contents+total, PRUint32(contentsLen), &howMany); if (NS_FAILED(rv)) { delete [] contents; return rv; } total += howMany; } if (total == contentsLen) { contents[contentsLen] = '\0'; sourceContents.AssignWithConversion(contents, contentsLen); rv = NS_OK; } delete [] contents; contents = nsnull; } } return(rv); } nsresult InternetSearchDataSource::GetNumInterpretSections(const PRUnichar *dataUni, PRUint32 &numInterpretSections) { numInterpretSections = 0; nsString buffer(dataUni); NS_NAMED_LITERAL_STRING(section, " 0) { buffer.Left(line, eol); } buffer.Cut(0, eol+1); if (line.IsEmpty()) continue; // skip empty lines if (line[0] == PRUnichar('#')) continue; // skip comments line.Trim(" \t"); if (!inSection) { PRInt32 sectionOffset = nsString_Find(section, line, PR_TRUE); if (sectionOffset < 0) continue; line.Cut(0, sectionOffset + section.Length() + 1); inSection = PR_TRUE; ++numInterpretSections; // increment # of sections } line.Trim(" \t"); PRInt32 len = line.Length(); if (len > 0) { if (line[len-1] == PRUnichar('>')) { inSection = PR_FALSE; line.SetLength(len-1); } } } return(NS_OK); } nsresult InternetSearchDataSource::GetData(const PRUnichar *dataUni, const char *sectionToFind, PRUint32 sectionNum, const char *attribToFind, nsString &value) { nsString buffer(dataUni); nsresult rv = NS_RDF_NO_VALUE; PRBool inSection = PR_FALSE; nsAutoString section; section.AssignLiteral("<"); section.AppendWithConversion(sectionToFind); while(!buffer.IsEmpty()) { PRInt32 eol = buffer.FindCharInSet("\r\n", 0); if (eol < 0) break; nsAutoString line; if (eol > 0) { buffer.Left(line, eol); } buffer.Cut(0, eol+1); if (line.IsEmpty()) continue; // skip empty lines if (line[0] == PRUnichar('#')) continue; // skip comments line.Trim(" \t"); if (!inSection) { PRInt32 sectionOffset = nsString_Find(section, line, PR_TRUE); if (sectionOffset < 0) continue; if (sectionNum > 0) { --sectionNum; continue; } line.Cut(0, sectionOffset + section.Length() + 1); inSection = PR_TRUE; } line.Trim(" \t"); PRInt32 len = line.Length(); if (len > 0) { if (line[len-1] == PRUnichar('>')) { inSection = PR_FALSE; line.SetLength(len-1); } } PRInt32 equal = line.FindChar(PRUnichar('=')); if (equal < 0) continue; // skip lines with no equality nsAutoString attrib; if (equal > 0) { line.Left(attrib, equal /* - 1 */); } attrib.Trim(" \t"); if (attrib.EqualsIgnoreCase(attribToFind)) { line.Cut(0, equal+1); line.Trim(" \t"); value = line; // strip of any enclosing quotes and trailing comments if ((value[0] == PRUnichar('\"')) || (value[0] == PRUnichar('\''))) { PRUnichar quoteChar = value[0]; value.Cut(0,1); if (!value.IsEmpty()) { PRInt32 quoteEnd = value.FindChar(quoteChar); if (quoteEnd >= 0) { value.Truncate(quoteEnd); } } } else { PRInt32 commentOffset = value.FindCharInSet("# \t", 0); if (commentOffset >= 0) { value.Truncate(commentOffset); } value.Trim(" \t"); } rv = NS_OK; break; } } return(rv); } nsresult InternetSearchDataSource::GetInputs(const PRUnichar *dataUni, nsString &engineName, nsString &userVar, const nsString &text, nsString &input, PRInt16 direction, PRUint16 pageNumber, PRUint16 *whichButtons) { nsString buffer(dataUni); nsresult rv = NS_OK; PRBool inSection = PR_FALSE; PRBool inDirInput; // directional input: "inputnext" or "inputprev" PRBool foundInput = PR_FALSE; while(!buffer.IsEmpty()) { PRInt32 eol = buffer.FindCharInSet("\r\n", 0); if (eol < 0) break; nsAutoString line; if (eol > 0) { buffer.Left(line, eol); } buffer.Cut(0, eol+1); if (line.IsEmpty()) continue; // skip empty lines if (line[0] == PRUnichar('#')) continue; // skip comments line.Trim(" \t"); if (!inSection) { if (line[0] != PRUnichar('<')) continue; line.Cut(0, 1); inSection = PR_TRUE; } PRInt32 len = line.Length(); if (len > 0) { if (line[len-1] == PRUnichar('>')) { inSection = PR_FALSE; line.SetLength(len-1); } } if (inSection) continue; // look for inputs if (line.Find("input", PR_TRUE) == 0) { line.Cut(0, 5); // look for "inputnext" or "inputprev" inDirInput = PR_FALSE; if (line.Find("next", PR_TRUE) == 0) { inDirInput = PR_TRUE; if (whichButtons) *whichButtons |= kHaveNext; } if (line.Find("prev", PR_TRUE) == 0) { inDirInput = PR_TRUE; if (whichButtons) *whichButtons |= kHavePrev; } if (inDirInput) line.Cut(0, 4); line.Trim(" \t"); // first look for name attribute nsAutoString nameAttrib; PRInt32 nameOffset = line.Find("name", PR_TRUE); if (nameOffset >= 0) { PRInt32 equal = line.FindChar(PRUnichar('='), nameOffset); if (equal >= 0) { PRInt32 startQuote = line.FindChar(PRUnichar('\"'), equal + 1); if (startQuote >= 0) { PRInt32 endQuote = line.FindChar(PRUnichar('\"'), startQuote + 1); if (endQuote > 0) { line.Mid(nameAttrib, startQuote+1, endQuote-startQuote-1); line.Cut(0, endQuote + 1); } } else { nameAttrib = line; nameAttrib.Cut(0, equal+1); nameAttrib.Trim(" \t"); PRInt32 space = nameAttrib.FindCharInSet(" \t", 0); if (space > 0) { nameAttrib.Truncate(space); line.Cut(0, equal+1+space); } else { line.Truncate(); } } } } if (foundInput && nameAttrib.IsEmpty()) continue; // first look for value attribute nsAutoString valueAttrib; PRInt32 valueOffset; if (!inDirInput) valueOffset = line.Find("value", PR_TRUE); else valueOffset = line.Find("factor", PR_TRUE); if (valueOffset >= 0) { PRInt32 equal = line.FindChar(PRUnichar('='), valueOffset); if (equal >= 0) { PRInt32 startQuote = line.FindChar(PRUnichar('\"'), equal + 1); if (startQuote >= 0) { PRInt32 endQuote = line.FindChar(PRUnichar('\"'), startQuote + 1); if (endQuote >= 0) { line.Mid(valueAttrib, startQuote+1, endQuote-startQuote-1); } } else { // if value attribute's "value" isn't quoted, get the first word... ? valueAttrib = line; valueAttrib.Cut(0, equal+1); valueAttrib.Trim(" \t"); PRInt32 space = valueAttrib.FindCharInSet(" \t>", 0); if (space > 0) { valueAttrib.Truncate(space); } } } } else if (line.Find("user", PR_TRUE) >= 0) { userVar = nameAttrib; valueAttrib.Assign(text); } // XXX should ignore if mode=browser is specified // XXX need to do this better if (line.RFind("mode=browser", PR_TRUE) >= 0) continue; if (!valueAttrib.IsEmpty()) { // Here's how we construct the input string: // is first: Name Attr: Prefix Data Example: // YES EMPTY None ACTION // YES NON-EMPTY ? = ACTION?= // NO EMPTY ----------- ------------- // NO NON-EMPTY & = ACTION?=&= if (!input.IsEmpty()) input.AppendLiteral("&"); else if (!nameAttrib.IsEmpty()) input.AppendLiteral("?"); if (!nameAttrib.IsEmpty()) { input += nameAttrib; input.AppendLiteral("="); } // Indicate that we've already found an input, so we cannot have any // inputs after this that do not have names. I could be more sophisticated // than this but I don't care right now since I'm only doing this for one // plugin. --ben foundInput = PR_TRUE; if (!inDirInput) input += valueAttrib; else input.AppendInt( computeIndex(valueAttrib, pageNumber, direction) ); } } } // Now add the default vs. non-default parameters, which come from // preferences and are part of the pre-configuration. nsCOMPtr pserv(do_QueryInterface(prefs)); if (pserv) { // If the pref "browser.search.defaultenginename" has a user value, that // means the user has changed the engine in the list. This implies that // the selected engine was _not_ configured as the default by the // distributor, because if the value of the pref matched, prefHasUserValue // would return false. PRBool engineIsNotDefault = PR_FALSE; nsCOMPtr rootBranch(do_QueryInterface(pserv)); nsCOMPtr defaultBranch; pserv->GetDefaultBranch("", getter_AddRefs(defaultBranch)); if (defaultBranch) { nsXPIDLString defaultEngineNameStr; nsCOMPtr defaultEngineName; rv = defaultBranch->GetComplexValue("browser.search.defaultenginename", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(defaultEngineName)); if (NS_SUCCEEDED(rv)) { defaultEngineName->GetData(getter_Copies(defaultEngineNameStr)); nsXPIDLString selectedEngineNameStr; nsCOMPtr selectedEngineName; rv = rootBranch->GetComplexValue("browser.search.selectedEngine", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(selectedEngineName)); if (NS_SUCCEEDED(rv) && selectedEngineName) { selectedEngineName->GetData(getter_Copies(selectedEngineNameStr)); engineIsNotDefault = !defaultEngineNameStr.Equals(selectedEngineNameStr); } else { engineIsNotDefault = PR_FALSE; // The selected engine *is* the default // since the user has not changed the // selected item in the list causing // the selectedEngine pref to be set. } } } PRInt32 i = 0; char prefNameBuf[1096]; do { ++i; sprintf(prefNameBuf, "browser.search.param.%s.%d.", NS_ConvertUCS2toUTF8(engineName).get(), i); nsCOMPtr pb; rv = pserv->GetBranch(prefNameBuf, getter_AddRefs(pb)); if (NS_FAILED(rv)) break; nsCOMPtr parameter; nsXPIDLString parameterStr; rv = pb->GetComplexValue(engineIsNotDefault ? "custom" : "default", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(parameter)); if (NS_FAILED(rv)) break; parameter->GetData(getter_Copies(parameterStr)); if (!parameterStr.IsEmpty()) { if (!input.IsEmpty()) input.Append(NS_LITERAL_STRING("&")); input += parameterStr; } } while (1); // Now add the release identifier nsCOMPtr stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID)); nsCOMPtr bundle; rv = stringService->CreateBundle(SEARCHCONFIG_PROPERTIES, getter_AddRefs(bundle)); nsCOMPtr intlBundle; rv = stringService->CreateBundle(INTL_PROPERTIES, getter_AddRefs(intlBundle)); nsXPIDLString langName; intlBundle->GetStringFromName(NS_LITERAL_STRING("general.useragent.locale").get(), getter_Copies(langName)); nsAutoString keyTemplate(NS_LITERAL_STRING("browser.search.param.")); keyTemplate += engineName; keyTemplate.Append(NS_LITERAL_STRING(".release")); nsXPIDLString releaseValue; NS_NAMED_LITERAL_STRING(distributionID, MOZ_DISTRIBUTION_ID); const PRUnichar* strings[] = { distributionID.get(), langName.get() }; bundle->FormatStringFromName(keyTemplate.get(), strings, 2, getter_Copies(releaseValue)); if (!releaseValue.IsEmpty()) { if (!input.IsEmpty()) input.Append(NS_LITERAL_STRING("&")); input += releaseValue; } // Now add order parameters. nsCOMPtr pb; rv = pserv->GetBranch("", getter_AddRefs(pb)); if (NS_FAILED(rv)) return rv; i = 0; do { ++i; sprintf(prefNameBuf, "browser.search.order.%d", i); nsCOMPtr orderEngineName; rv = pb->GetComplexValue(prefNameBuf, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(orderEngineName)); if (NS_FAILED(rv)) break; nsXPIDLString orderEngineNameStr; orderEngineName->GetData(getter_Copies(orderEngineNameStr)); if (orderEngineNameStr.Equals(engineName)) break; } while (PR_TRUE); if (NS_SUCCEEDED(rv)) { sprintf(prefNameBuf, "browser.search.order.%s.%d", NS_ConvertUCS2toUTF8(engineName).get(), i); nsCOMPtr orderParam; rv = rootBranch->GetComplexValue(prefNameBuf, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(orderParam)); if (NS_FAILED(rv)) { sprintf(prefNameBuf, "browser.search.order.%s", NS_ConvertUCS2toUTF8(engineName).get()); rv = rootBranch->GetComplexValue(prefNameBuf, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(orderParam)); } if (NS_SUCCEEDED(rv)) { nsXPIDLString orderParamStr; orderParam->GetData(getter_Copies(orderParamStr)); if (!orderParamStr.IsEmpty()) { if (!input.IsEmpty()) input.Append(NS_LITERAL_STRING("&")); input += orderParamStr; } } } rv = NS_OK; } return(rv); } PRInt32 InternetSearchDataSource::computeIndex(nsAutoString &factor, PRUint16 page, PRInt16 direction) { // XXX get page PRInt32 errorCode, index = 0; PRInt32 factorInt = factor.ToInteger(&errorCode); if (NS_SUCCEEDED(errorCode)) { // if factor is garbled assume 10 if (factorInt <= 0) factorInt = 10; if (direction < 0) { // don't pass back a negative index! if (0 <= (page - 1)) --page; } index = factorInt * page; } return index; } nsresult InternetSearchDataSource::GetURL(nsIRDFResource *source, nsIRDFLiteral** aResult) { const char *uri = nsnull; source->GetValueConst( &uri ); nsAutoString url; url.AssignWithConversion(uri); nsIRDFLiteral *literal; gRDFService->GetLiteral(url.get(), &literal); *aResult = literal; return NS_OK; } // stream observer methods NS_IMETHODIMP InternetSearchDataSource::OnStartRequest(nsIRequest *request, nsISupports *ctxt) { #ifdef DEBUG_SEARCH_OUTPUT printf("InternetSearchDataSourceCallback::OnStartRequest entered.\n"); #endif return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, nsIInputStream *aIStream, PRUint32 sourceOffset, PRUint32 aLength) { if (!ctxt) return(NS_ERROR_NO_INTERFACE); nsCOMPtr context (do_QueryInterface(ctxt)); if (!context) return(NS_ERROR_NO_INTERFACE); nsresult rv = NS_OK; if (aLength < 1) return(rv); PRUint32 count; char *buffer = new char[ aLength ]; if (!buffer) return(NS_ERROR_OUT_OF_MEMORY); if (NS_FAILED(rv = aIStream->Read(buffer, aLength, &count)) || count == 0) { #ifdef DEBUG printf("Search datasource read failure.\n"); #endif delete []buffer; return(rv); } if (count != aLength) { #ifdef DEBUG printf("Search datasource read # of bytes failure.\n"); #endif delete []buffer; return(NS_ERROR_UNEXPECTED); } nsCOMPtr decoder; context->GetUnicodeDecoder(getter_AddRefs(decoder)); if (decoder) { char *aBuffer = buffer; PRInt32 unicharBufLen = 0; decoder->GetMaxLength(aBuffer, aLength, &unicharBufLen); PRUnichar *unichars = new PRUnichar [ unicharBufLen+1 ]; do { PRInt32 srcLength = aLength; PRInt32 unicharLength = unicharBufLen; rv = decoder->Convert(aBuffer, &srcLength, unichars, &unicharLength); unichars[unicharLength]=0; //add this since the unicode converters can't be trusted to do so. // Move the nsParser.cpp 00 -> space hack to here so it won't break UCS2 file // Hack Start for(PRInt32 i=0;i < unicharLength; i++) { if(0x0000 == unichars[i]) { unichars[i] = PRUnichar(' '); } } // Hack End context->AppendUnicodeBytes(unichars, unicharLength); // if we failed, we consume one byte by replace it with U+FFFD // and try conversion again. if(NS_FAILED(rv)) { decoder->Reset(); unsigned char smallBuf[2]; smallBuf[0] = 0xFF; smallBuf[1] = 0xFD; context->AppendBytes( (const char *)&smallBuf, 2L); if(((PRUint32) (srcLength + 1)) > aLength) srcLength = aLength; else srcLength++; aBuffer += srcLength; aLength -= srcLength; } } while (NS_FAILED(rv) && (aLength > 0)); delete [] unichars; unichars = nsnull; } else { context->AppendBytes(buffer, aLength); } delete [] buffer; buffer = nsnull; return(rv); } NS_IMETHODIMP InternetSearchDataSource::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status) { if (!mInner) return(NS_OK); nsCOMPtr channel (do_QueryInterface(request)); nsCOMPtr context (do_QueryInterface(ctxt)); if (!ctxt) return(NS_ERROR_NO_INTERFACE); nsresult rv; PRUint32 contextType = 0; if (NS_FAILED(rv = context->GetContextType(&contextType))) return(rv); if (contextType == nsIInternetSearchContext::WEB_SEARCH_CONTEXT) { // continue to process nsIInternetSearchContext::WEB_SEARCH_CONTEXT rv = webSearchFinalize(channel, context); } else if (contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_NEW_CONTEXT || contextType == nsIInternetSearchContext::ENGINE_DOWNLOAD_UPDATE_CONTEXT || contextType == nsIInternetSearchContext::ICON_DOWNLOAD_UPDATE_CONTEXT) { nsCOMPtr httpChannel (do_QueryInterface(channel)); if (!httpChannel) return(NS_ERROR_UNEXPECTED); // check HTTP status to ensure success PRUint32 httpStatus = 0; if (NS_SUCCEEDED(rv = httpChannel->GetResponseStatus(&httpStatus)) && (httpStatus == 200)) { rv = saveContents(channel, context, contextType); } } else if (contextType == nsIInternetSearchContext::ENGINE_UPDATE_HEAD_CONTEXT) { nsCOMPtr theEngine; if (NS_FAILED(rv = context->GetEngine(getter_AddRefs(theEngine)))) return(rv); if (!theEngine) return(NS_ERROR_NO_INTERFACE); #ifdef DEBUG_SEARCH_UPDATES const char *engineURI = nsnull; theEngine->GetValueConst(&engineURI); #endif // free up "busy" info now & mark as non-busy busySchedule = PR_FALSE; busyResource = nsnull; // mark now as the last time we stat'ted the search engine // regardless of HTTP status rv = validateEngineNow(theEngine); NS_ENSURE_SUCCESS(rv, rv); // we only have HTTP "HEAD" information when doing updates nsCOMPtr httpChannel (do_QueryInterface(channel)); if (!httpChannel) return(NS_ERROR_UNEXPECTED); // check HTTP status to ensure success PRUint32 httpStatus = 0; if (NS_FAILED(rv = httpChannel->GetResponseStatus(&httpStatus))) return(rv); if (httpStatus != 200) return(NS_ERROR_UNEXPECTED); // get last-modified & content-length info nsCAutoString lastModValue, contentLengthValue; if (NS_FAILED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Last-Modified"), lastModValue))) lastModValue.Truncate(); if (NS_FAILED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthValue))) contentLengthValue.Truncate(); // should we fetch the entire file? PRBool updateSearchEngineFile = PR_FALSE; // save out new search engine state data into localstore PRBool tempDirty = PR_FALSE; nsCOMPtr newValue; if (!lastModValue.IsEmpty()) { gRDFService->GetLiteral(NS_ConvertASCIItoUCS2(lastModValue).get(), getter_AddRefs(newValue)); if (newValue) { updateAtom(mLocalstore, theEngine, kWEB_LastPingModDate, newValue, &tempDirty); if (tempDirty) updateSearchEngineFile = PR_TRUE; } } if (!contentLengthValue.IsEmpty()) { gRDFService->GetLiteral(NS_ConvertASCIItoUCS2(contentLengthValue).get(), getter_AddRefs(newValue)); if (newValue) { updateAtom(mLocalstore, theEngine, kWEB_LastPingContentLen, newValue, &tempDirty); if (tempDirty) { updateSearchEngineFile = PR_TRUE; } else { // worst case: compare local data size vs. remote content size nsCOMPtr dataLit; if (NS_SUCCEEDED(rv = FindData(theEngine, getter_AddRefs(dataLit))) && (rv != NS_RDF_NO_VALUE)) { const PRUnichar *dataUni = nsnull; dataLit->GetValueConst(&dataUni); nsAutoString dataStr(dataUni); PRInt32 dataLen=dataStr.Length(); #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine='%s' data length='%d'\n", engineURI, dataLen); #endif PRInt32 contentLen=0, err=0; contentLen = contentLengthValue.ToInteger(&err); if ((!err) && (dataLen != contentLen)) { #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine '%s' data length != remote content length, so update\n", engineURI, dataLen); #endif updateSearchEngineFile = PR_TRUE; } } } } } if (updateSearchEngineFile) { #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine='%s' needs updating, so fetching it\n", engineURI); #endif // get update URL nsCString updateURL; nsCOMPtr aNode; if (NS_SUCCEEDED(rv = mInner->GetTarget(theEngine, kNC_Update, PR_TRUE, getter_AddRefs(aNode))) && (rv != NS_RDF_NO_VALUE)) { nsCOMPtr aLiteral (do_QueryInterface(aNode)); if (aLiteral) { const PRUnichar *updateUni = nsnull; aLiteral->GetValueConst(&updateUni); if (updateUni) { updateURL.AssignWithConversion(updateUni); } } } // get update icon nsCString updateIconURL; if (NS_SUCCEEDED(rv = mInner->GetTarget(theEngine, kNC_UpdateIcon, PR_TRUE, getter_AddRefs(aNode))) && (rv != NS_RDF_NO_VALUE)) { nsCOMPtr aIconLiteral (do_QueryInterface(aNode)); if (aIconLiteral) { const PRUnichar *updateIconUni = nsnull; aIconLiteral->GetValueConst(&updateIconUni); if (updateIconUni) { updateIconURL.AssignWithConversion(updateIconUni); } } } // download it! AddSearchEngineInternal(updateURL.get(), updateIconURL.get(), nsnull, nsnull, theEngine); } else { #ifdef DEBUG_SEARCH_UPDATES printf(" Search engine='%s' is current and requires no updating\n", engineURI); #endif } } else { rv = NS_ERROR_UNEXPECTED; } return(rv); } nsresult InternetSearchDataSource::validateEngineNow(nsIRDFResource *engine) { // get the current date/time [from microseconds (PRTime) to seconds] // also, need to convert from 64 bites to 32 bites as we don't have an easy // way to convert from 64 bit number to a string like we do for 32 bit numbers PRTime now64 = PR_Now(), temp64, million; LL_I2L(million, PR_USEC_PER_SEC); LL_DIV(temp64, now64, million); PRInt32 now32; LL_L2I(now32, temp64); // validate this engine as of now (save as string // literal as that's all RDF can currently serialize) nsAutoString nowStr; nowStr.AppendInt(now32); nsresult rv; nsCOMPtr nowLiteral; if (NS_FAILED(rv = gRDFService->GetLiteral(nowStr.get(), getter_AddRefs(nowLiteral)))) return(rv); updateAtom(mLocalstore, engine, kWEB_LastPingDate, nowLiteral, nsnull); // flush localstore nsCOMPtr remoteLocalStore (do_QueryInterface(mLocalstore)); if (remoteLocalStore) { remoteLocalStore->Flush(); } return(NS_OK); } nsresult InternetSearchDataSource::webSearchFinalize(nsIChannel* channel, nsIInternetSearchContext *context) { nsresult rv; nsCOMPtr mParent; if (NS_FAILED(rv = context->GetParent(getter_AddRefs(mParent)))) return(rv); // Note: mParent can be null // if (!mParent) return(NS_ERROR_NO_INTERFACE); nsCOMPtr mEngine; if (NS_FAILED(rv = context->GetEngine(getter_AddRefs(mEngine)))) return(rv); if (!mEngine) return(NS_ERROR_NO_INTERFACE); nsCOMPtr aURL; rv = channel->GetURI(getter_AddRefs(aURL)); if (NS_FAILED(rv)) return rv; // copy the engine's icon reference (if it has one) onto the result node nsCOMPtr engineIconStatusNode = nsnull; mInner->GetTarget(mEngine, kNC_Icon, PR_TRUE, getter_AddRefs(engineIconStatusNode)); if (engineIconStatusNode) { rv = mInner->Assert(mEngine, kNC_StatusIcon, engineIconStatusNode, PR_TRUE); } const PRUnichar *uniBuf = nsnull; if (NS_SUCCEEDED(rv = context->GetBufferConst(&uniBuf)) && (uniBuf)) { if (mParent && (gBrowserSearchMode>0)) { // save HTML result page for this engine nsCOMPtr htmlLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(uniBuf, getter_AddRefs(htmlLiteral)))) { rv = mInner->Assert(mEngine, kNC_HTML, htmlLiteral, PR_TRUE); } } // parse up HTML results PRInt32 uniBufLen = 0L; if (NS_SUCCEEDED(rv = context->GetBufferLength(&uniBufLen))) { rv = ParseHTML(aURL, mParent, mEngine, uniBuf, uniBufLen); } } else { #ifdef DEBUG_SEARCH_OUTPUT printf(" *** InternetSearchDataSourceCallback::OnStopRequest: no data.\n\n"); #endif } // after we're all done with the html buffer, get rid of it context->Truncate(); // (do this last) potentially remove the loading attribute mInner->Unassert(mEngine, kNC_loading, kTrueLiteral); if (mLoadGroup) { PRUint32 count = 0; if (NS_SUCCEEDED(rv = mLoadGroup->GetActiveCount(&count))) { // is this the last connection in the loadgroup? if (count <= 1) { Stop(); } } } return(NS_OK); } nsresult InternetSearchDataSource::ParseHTML(nsIURI *aURL, nsIRDFResource *mParent, nsIRDFResource *mEngine, const PRUnichar *htmlPage, PRInt32 htmlPageSize) { // get data out of graph nsresult rv; nsCOMPtr dataNode; if (NS_FAILED(rv = mInner->GetTarget(mEngine, kNC_Data, PR_TRUE, getter_AddRefs(dataNode)))) { return(rv); } nsCOMPtr dataLiteral (do_QueryInterface(dataNode)); if (!dataLiteral) return(NS_ERROR_NULL_POINTER); const PRUnichar *dataUni = nsnull; if (NS_FAILED(rv = dataLiteral->GetValueConst(&dataUni))) return(rv); if (!dataUni) return(NS_ERROR_NULL_POINTER); // get name of this engine once nsAutoString engineStr; GetData(dataUni, "search", 0, "name", engineStr); // pre-compute host (we might discard URLs that match this) nsCAutoString hostName; aURL->GetAsciiHost(hostName); // pre-compute server path (we might discard URLs that match this) nsAutoString serverPathStr; nsCAutoString serverPath; aURL->GetPath(serverPath); if (!serverPath.IsEmpty()) { AppendUTF8toUTF16(serverPath, serverPathStr); serverPath.Truncate(); PRInt32 serverOptionsOffset = serverPathStr.FindChar(PRUnichar('?')); if (serverOptionsOffset >= 0) serverPathStr.Truncate(serverOptionsOffset); } PRBool hasPriceFlag = PR_FALSE, hasAvailabilityFlag = PR_FALSE, hasRelevanceFlag = PR_FALSE; PRBool hasDateFlag = PR_FALSE; PRBool skipLocalFlag = PR_FALSE, useAllHREFsFlag = PR_FALSE; PRInt32 pageRank = 1; PRUint32 numInterpretSections, numResults = 0; GetNumInterpretSections(dataUni, numInterpretSections); if (numInterpretSections < 1) { // if no sections, use all the HREFS on the page numInterpretSections = 1; useAllHREFsFlag = PR_TRUE; skipLocalFlag = PR_TRUE; } #ifdef DEBUG PRTime now; now = PR_Now(); printf("\nStart processing search results: %u bytes \n", htmlPageSize); #endif // need to handle multiple sections, per spec for (PRUint32 interpretSectionNum=0; interpretSectionNum < numInterpretSections; interpretSectionNum++) { nsAutoString resultListStartStr, resultListEndStr; nsAutoString resultItemStartStr, resultItemEndStr; nsAutoString relevanceStartStr, relevanceEndStr; nsAutoString bannerStartStr, bannerEndStr, skiplocalStr; nsAutoString priceStartStr, priceEndStr, availStartStr, availEndStr; nsAutoString dateStartStr, dateEndStr; nsAutoString nameStartStr, nameEndStr; nsAutoString emailStartStr, emailEndStr; nsAutoString browserResultTypeStr; browserResultTypeStr.AssignLiteral("result"); // default to "result" // use a nsDependentString so that "htmlPage" data isn't copied nsDependentString htmlResults(htmlPage, htmlPageSize); PRUint32 startIndex = 0L, stopIndex = htmlPageSize; if (!useAllHREFsFlag) { GetData(dataUni, "interpret", interpretSectionNum, "resultListStart", resultListStartStr); GetData(dataUni, "interpret", interpretSectionNum, "resultListEnd", resultListEndStr); GetData(dataUni, "interpret", interpretSectionNum, "resultItemStart", resultItemStartStr); GetData(dataUni, "interpret", interpretSectionNum, "resultItemEnd", resultItemEndStr); GetData(dataUni, "interpret", interpretSectionNum, "relevanceStart", relevanceStartStr); GetData(dataUni, "interpret", interpretSectionNum, "relevanceEnd", relevanceEndStr); GetData(dataUni, "interpret", interpretSectionNum, "bannerStart", bannerStartStr); GetData(dataUni, "interpret", interpretSectionNum, "bannerEnd", bannerEndStr); GetData(dataUni, "interpret", interpretSectionNum, "skiplocal", skiplocalStr); skipLocalFlag = (skiplocalStr.LowerCaseEqualsLiteral("true")) ? PR_TRUE : PR_FALSE; // shopping channel support GetData(dataUni, "interpret", interpretSectionNum, "priceStart", priceStartStr); GetData(dataUni, "interpret", interpretSectionNum, "priceEnd", priceEndStr); GetData(dataUni, "interpret", interpretSectionNum, "availStart", availStartStr); GetData(dataUni, "interpret", interpretSectionNum, "availEnd", availEndStr); // news channel support GetData(dataUni, "interpret", interpretSectionNum, "dateStart", dateStartStr); GetData(dataUni, "interpret", interpretSectionNum, "dateEnd", dateEndStr); // people channel support GetData(dataUni, "interpret", interpretSectionNum, "nameStart", nameStartStr); GetData(dataUni, "interpret", interpretSectionNum, "nameEnd", nameEndStr); GetData(dataUni, "interpret", interpretSectionNum, "emailStart", emailStartStr); GetData(dataUni, "interpret", interpretSectionNum, "emailEnd", emailEndStr); // special browser support GetData(dataUni, "interpret", interpretSectionNum, "browserResultType", browserResultTypeStr); if (browserResultTypeStr.IsEmpty()) { browserResultTypeStr.AssignLiteral("result"); // default to "result" } } // look for banner nsCOMPtr bannerLiteral; if ((!bannerStartStr.IsEmpty()) && (!bannerEndStr.IsEmpty())) { PRInt32 bannerStart = nsString_Find(bannerStartStr, htmlResults, PR_TRUE); if (bannerStart >= 0) { startIndex = bannerStart; PRInt32 bannerEnd = nsString_Find(bannerEndStr, htmlResults, PR_TRUE, bannerStart + bannerStartStr.Length()); if (bannerEnd > bannerStart) { stopIndex = bannerEnd - 1; nsAutoString htmlBanner; htmlResults.Mid(htmlBanner, bannerStart, bannerEnd - bannerStart - 1); if (!htmlBanner.IsEmpty()) { const PRUnichar *bannerUni = htmlBanner.get(); if (bannerUni) { gRDFService->GetLiteral(bannerUni, getter_AddRefs(bannerLiteral)); } } } } } if (!resultListStartStr.IsEmpty()) { PRInt32 resultListStart = nsString_Find(resultListStartStr, htmlResults, PR_TRUE); if (resultListStart >= 0) { startIndex = resultListStart + resultListStartStr.Length(); } else if (!useAllHREFsFlag) { // if we have multiple sections but can't find the startIndex // of a result list block, just continue on with the the next block continue; } } if (!resultListEndStr.IsEmpty()) { // rjc note: use RFind to find the LAST // occurrence of resultListEndStr nsAString::const_iterator originalStart, start, end; htmlResults.BeginReading(start); htmlResults.EndReading(end); originalStart = start; if (RFindInReadable(resultListEndStr, start, end)) stopIndex = Distance(originalStart, start); } PRBool trimItemStart = PR_TRUE; PRBool trimItemEnd = PR_FALSE; // rjc note: testing shows we should NEVER trim end??? // if resultItemStartStr is not specified, try making it just be "HREF=" if (resultItemStartStr.IsEmpty()) { resultItemStartStr.AssignLiteral("HREF="); trimItemStart = PR_FALSE; } // if resultItemEndStr is not specified, try making it the same as resultItemStartStr if (resultItemEndStr.IsEmpty()) { resultItemEndStr = resultItemStartStr; trimItemEnd = PR_TRUE; } while(startIndex < stopIndex) { PRInt32 resultItemStart; resultItemStart = nsString_Find(resultItemStartStr, htmlResults, PR_TRUE, startIndex); if (resultItemStart < 0) break; PRInt32 resultItemEnd; if (trimItemStart) { resultItemStart += resultItemStartStr.Length(); resultItemEnd = nsString_Find(resultItemEndStr, htmlResults, PR_TRUE, resultItemStart); } else { resultItemEnd = nsString_Find(resultItemEndStr, htmlResults, PR_TRUE, resultItemStart + resultItemStartStr.Length()); } if (resultItemEnd < 0) { resultItemEnd = stopIndex; } else if (!trimItemEnd && resultItemEnd >= 0) { resultItemEnd += resultItemEndStr.Length(); } // forced to use an nsAutoString (which copies) // as CBufDescriptor doesn't guarantee null terminator if (resultItemEnd - resultItemStart - 1 <= 0) break; nsAutoString resultItem(&htmlPage[resultItemStart], resultItemEnd - resultItemStart - 1); if (resultItem.IsEmpty()) break; // advance startIndex here so that, from this point onward, "continue" can be used startIndex = resultItemEnd; #ifdef DEBUG_SEARCH_OUTPUT char *results = ToNewCString(resultItem); if (results) { printf("\n----- Search result: '%s'\n\n", results); nsCRT::free(results); results = nsnull; } #endif // look for href PRInt32 hrefOffset = resultItem.Find("HREF=", PR_TRUE); if (hrefOffset < 0) { #ifdef DEBUG_SEARCH_OUTPUT printf("\n***** Unable to find HREF!\n\n"); #endif continue; } nsAutoString hrefStr; PRInt32 quoteStartOffset = resultItem.FindCharInSet("\"\'>", hrefOffset); PRInt32 quoteEndOffset; if (quoteStartOffset < hrefOffset) { // handle case where HREF isn't quoted quoteStartOffset = hrefOffset + strlen("HREF="); quoteEndOffset = resultItem.FindChar('>', quoteStartOffset); if (quoteEndOffset < quoteStartOffset) continue; } else { if (resultItem[quoteStartOffset] == PRUnichar('>')) { // handle case where HREF isn't quoted quoteEndOffset = quoteStartOffset; quoteStartOffset = hrefOffset + strlen("HREF=") -1; } else { quoteEndOffset = resultItem.FindCharInSet("\"\'", quoteStartOffset + 1); if (quoteEndOffset < hrefOffset) continue; } } resultItem.Mid(hrefStr, quoteStartOffset + 1, quoteEndOffset - quoteStartOffset - 1); ConvertEntities(hrefStr, PR_FALSE, PR_TRUE, PR_FALSE); if (hrefStr.IsEmpty()) continue; char *absURIStr = nsnull; nsCAutoString hrefstrC; hrefstrC.AssignWithConversion(hrefStr); if (NS_SUCCEEDED(rv = NS_MakeAbsoluteURI(&absURIStr, hrefstrC.get(), aURL)) && (absURIStr)) { hrefStr.AssignWithConversion(absURIStr); nsCOMPtr absURI; rv = NS_NewURI(getter_AddRefs(absURI), absURIStr); nsCRT::free(absURIStr); absURIStr = nsnull; if (absURI && skipLocalFlag) { nsCAutoString absPath; absURI->GetPath(absPath); if (!absPath.IsEmpty()) { NS_ConvertUTF8toUCS2 absPathStr(absPath); PRInt32 pathOptionsOffset = absPathStr.FindChar(PRUnichar('?')); if (pathOptionsOffset >= 0) absPathStr.Truncate(pathOptionsOffset); PRBool pathsMatchFlag = serverPathStr.Equals(absPathStr, nsCaseInsensitiveStringComparator()); if (pathsMatchFlag) continue; } if (!hostName.IsEmpty()) { nsCAutoString absHost; absURI->GetAsciiHost(absHost); if (!absHost.IsEmpty()) { PRBool hostsMatchFlag = !nsCRT::strcasecmp(hostName.get(), absHost.get()); if (hostsMatchFlag) continue; } } } } // if this result is to be filtered out, notice it now if (isSearchResultFiltered(hrefStr)) continue; nsAutoString site(hrefStr); #ifdef DEBUG_SEARCH_OUTPUT char *hrefCStr = ToNewCString(hrefStr); if (hrefCStr) { printf("HREF: '%s'\n", hrefCStr); nsCRT::free(hrefCStr); hrefCStr = nsnull; } #endif nsCOMPtr res; // save HREF attribute as URL if (NS_SUCCEEDED(rv = gRDFService->GetAnonymousResource(getter_AddRefs(res)))) { const PRUnichar *hrefUni = hrefStr.get(); if (hrefUni) { nsCOMPtr hrefLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(hrefUni, getter_AddRefs(hrefLiteral)))) { mInner->Assert(res, kNC_URL, hrefLiteral, PR_TRUE); } } } if (NS_FAILED(rv)) continue; // set HTML response chunk const PRUnichar *htmlResponseUni = resultItem.get(); if (htmlResponseUni && (gBrowserSearchMode>0)) { nsCOMPtr htmlResponseLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(htmlResponseUni, getter_AddRefs(htmlResponseLiteral)))) { if (htmlResponseLiteral) { mInner->Assert(res, kNC_HTML, htmlResponseLiteral, PR_TRUE); } } } // set banner (if we have one) if (bannerLiteral) { mInner->Assert(res, kNC_Banner, bannerLiteral, PR_TRUE); } // look for Site (if it isn't already set) nsCOMPtr oldSiteRes = nsnull; mInner->GetTarget(res, kNC_Site, PR_TRUE, getter_AddRefs(oldSiteRes)); if (!oldSiteRes) { PRInt32 protocolOffset = site.FindChar(':', 0); if (protocolOffset >= 0) { site.Cut(0, protocolOffset+1); while (site[0] == PRUnichar('/')) { site.Cut(0, 1); } PRInt32 slashOffset = site.FindChar('/', 0); if (slashOffset >= 0) { site.Truncate(slashOffset); } if (!site.IsEmpty()) { const PRUnichar *siteUni = site.get(); if (siteUni) { nsCOMPtr siteLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(siteUni, getter_AddRefs(siteLiteral)))) { if (siteLiteral) { mInner->Assert(res, kNC_Site, siteLiteral, PR_TRUE); } } } } } } // look for name nsAutoString nameStr; if ((!nameStartStr.IsEmpty()) && (!nameEndStr.IsEmpty())) { PRInt32 nameStart; if ((nameStart = nsString_Find(nameStartStr, resultItem, PR_TRUE)) >= 0) { nameStart += nameStartStr.Length(); PRInt32 nameEnd = nsString_Find(nameEndStr, resultItem, PR_TRUE, nameStart); if (nameEnd > nameStart) { resultItem.Mid(nameStr, nameStart, nameEnd - nameStart); } } } if (nameStr.IsEmpty()) { PRInt32 anchorEnd = resultItem.FindChar('>', quoteEndOffset); if (anchorEnd < quoteEndOffset) { #ifdef DEBUG_SEARCH_OUTPUT printf("\n\nSearch: Unable to find ending > when computing name.\n\n"); #endif continue; } PRInt32 anchorStop = resultItem.Find("", PR_TRUE, quoteEndOffset); if (anchorStop < anchorEnd) { #ifdef DEBUG_SEARCH_OUTPUT printf("\n\nSearch: Unable to find tag to compute name.\n\n"); #endif continue; } resultItem.Mid(nameStr, anchorEnd + 1, anchorStop - anchorEnd - 1); } ConvertEntities(nameStr); // look for Name (if it isn't already set) nsCOMPtr oldNameRes = nsnull; if (!oldNameRes) { if (!nameStr.IsEmpty()) { const PRUnichar *nameUni = nameStr.get(); if (nameUni) { nsCOMPtr nameLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(nameUni, getter_AddRefs(nameLiteral)))) { if (nameLiteral) { mInner->Assert(res, kNC_Name, nameLiteral, PR_TRUE); } } } } } // look for date if (!dateStartStr.IsEmpty()) { nsAutoString dateItem; PRInt32 dateStart; if ((dateStart = nsString_Find(dateStartStr, resultItem, PR_TRUE)) >= 0) { dateStart += dateStartStr.Length(); PRInt32 dateEnd = nsString_Find(dateEndStr, resultItem, PR_TRUE, dateStart); if (dateEnd > dateStart) { resultItem.Mid(dateItem, dateStart, dateEnd - dateStart); } } // strip out any html tags PRInt32 ltOffset, gtOffset; while ((ltOffset = dateItem.FindChar(PRUnichar('<'))) >= 0) { if ((gtOffset = dateItem.FindChar(PRUnichar('>'), ltOffset)) <= ltOffset) break; dateItem.Cut(ltOffset, gtOffset - ltOffset + 1); } // strip out whitespace and any CR/LFs dateItem.Trim("\n\r\t "); if (!dateItem.IsEmpty()) { const PRUnichar *dateUni = dateItem.get(); nsCOMPtr dateLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(dateUni, getter_AddRefs(dateLiteral)))) { if (dateLiteral) { mInner->Assert(res, kNC_Date, dateLiteral, PR_TRUE); hasDateFlag = PR_TRUE; } } } } // look for price if (!priceStartStr.IsEmpty()) { nsAutoString priceItem; PRInt32 priceStart; if ((priceStart = nsString_Find(priceStartStr, resultItem, PR_TRUE)) >= 0) { priceStart += priceStartStr.Length(); PRInt32 priceEnd = nsString_Find(priceEndStr, resultItem, PR_TRUE, priceStart); if (priceEnd > priceStart) { resultItem.Mid(priceItem, priceStart, priceEnd - priceStart); ConvertEntities(priceItem); } } if (!priceItem.IsEmpty()) { const PRUnichar *priceUni = priceItem.get(); nsCOMPtr priceLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(priceUni, getter_AddRefs(priceLiteral)))) { if (priceLiteral) { mInner->Assert(res, kNC_Price, priceLiteral, PR_TRUE); hasPriceFlag = PR_TRUE; } } PRInt32 priceCharStartOffset = priceItem.FindCharInSet("1234567890"); if (priceCharStartOffset >= 0) { priceItem.Cut(0, priceCharStartOffset); PRInt32 priceErr; float val = priceItem.ToFloat(&priceErr); if (priceItem.FindChar(PRUnichar('.')) >= 0) val *= 100; nsCOMPtr priceSortLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral((PRInt32)val, getter_AddRefs(priceSortLiteral)))) { if (priceSortLiteral) { mInner->Assert(res, kNC_PriceSort, priceSortLiteral, PR_TRUE); } } } } // look for availability (if we looked for price) if (!availStartStr.IsEmpty()) { nsAutoString availItem; PRInt32 availStart; if ((availStart = nsString_Find(availStartStr, resultItem, PR_TRUE)) >= 0) { availStart += availStartStr.Length(); PRInt32 availEnd = nsString_Find(availEndStr, resultItem, PR_TRUE, availStart); if (availEnd > availStart) { resultItem.Mid(availItem, availStart, availEnd - availStart); ConvertEntities(availItem); } } if (!availItem.IsEmpty()) { const PRUnichar *availUni = availItem.get(); nsCOMPtr availLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(availUni, getter_AddRefs(availLiteral)))) { if (availLiteral) { mInner->Assert(res, kNC_Availability, availLiteral, PR_TRUE); hasAvailabilityFlag = PR_TRUE; } } } } } // look for relevance nsAutoString relItem; PRInt32 relStart; if ((relStart = nsString_Find(relevanceStartStr, resultItem, PR_TRUE)) >= 0) { relStart += relevanceStartStr.Length(); PRInt32 relEnd = nsString_Find(relevanceEndStr, resultItem, PR_TRUE); if (relEnd > relStart) { resultItem.Mid(relItem, relStart, relEnd - relStart); } } // look for Relevance (if it isn't already set) nsCOMPtr oldRelRes = nsnull; if (!oldRelRes) { if (!relItem.IsEmpty()) { // save real relevance const PRUnichar *relUni = relItem.get(); if (relUni) { nsAutoString relStr(relUni); // take out any characters that aren't numeric or "%" PRInt32 len = relStr.Length(); for (PRInt32 x=len-1; x>=0; x--) { PRUnichar ch; ch = relStr.CharAt(x); if ((ch != PRUnichar('%')) && ((ch < PRUnichar('0')) || (ch > PRUnichar('9')))) { relStr.Cut(x, 1); } } // make sure it ends with a "%" len = relStr.Length(); if (len > 0) { PRUnichar ch; ch = relStr.CharAt(len - 1); if (ch != PRUnichar('%')) { relStr += PRUnichar('%'); } relItem = relStr; hasRelevanceFlag = PR_TRUE; } else { relItem.Truncate(); } } } if (relItem.IsEmpty()) { relItem.AssignLiteral("-"); } const PRUnichar *relItemUni = relItem.get(); nsCOMPtr relLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(relItemUni, getter_AddRefs(relLiteral)))) { if (relLiteral) { mInner->Assert(res, kNC_Relevance, relLiteral, PR_TRUE); } } if ((!relItem.IsEmpty()) && (!relItem.EqualsLiteral("-"))) { // If its a percentage, remove "%" if (relItem[relItem.Length()-1] == PRUnichar('%')) { relItem.Cut(relItem.Length()-1, 1); } // left-pad with "0"s and set special sorting value nsAutoString zero; zero.AssignLiteral("000"); if (relItem.Length() < 3) { relItem.Insert(zero.get(), 0, zero.Length() - relItem.Length()); } } else { relItem.AssignLiteral("000"); } const PRUnichar *relSortUni = relItem.get(); if (relSortUni) { nsCOMPtr relSortLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(relSortUni, getter_AddRefs(relSortLiteral)))) { if (relSortLiteral) { mInner->Assert(res, kNC_RelevanceSort, relSortLiteral, PR_TRUE); } } } } // set reference to engine this came from (if it isn't already set) nsCOMPtr oldEngineRes = nsnull; if (!oldEngineRes) { if (!engineStr.IsEmpty()) { const PRUnichar *engineUni = engineStr.get(); nsCOMPtr engineLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(engineUni, getter_AddRefs(engineLiteral)))) { if (engineLiteral) { mInner->Assert(res, kNC_Engine, engineLiteral, PR_TRUE); } } } } // copy the engine's icon reference (if it has one) onto the result node nsCOMPtr engineIconNode = nsnull; mInner->GetTarget(mEngine, kNC_Icon, PR_TRUE, getter_AddRefs(engineIconNode)); // if no branding icon, use some default icons nsAutoString iconChromeDefault; if (browserResultTypeStr.LowerCaseEqualsLiteral("category")) iconChromeDefault.AssignLiteral("chrome://communicator/skin/search/category.gif"); else if ((browserResultTypeStr.LowerCaseEqualsLiteral("result")) && (!engineIconNode)) iconChromeDefault.AssignLiteral("chrome://communicator/skin/search/result.gif"); if (!iconChromeDefault.IsEmpty()) { const PRUnichar *iconUni = iconChromeDefault.get(); nsCOMPtr iconLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(iconUni, getter_AddRefs(iconLiteral)))) { if (iconLiteral) { mInner->Assert(res, kNC_Icon, iconLiteral, PR_TRUE); } } } else if (engineIconNode) { rv = mInner->Assert(res, kNC_Icon, engineIconNode, PR_TRUE); } // set result page rank nsCOMPtr pageRankLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetIntLiteral(pageRank++, getter_AddRefs(pageRankLiteral)))) { rv = mInner->Assert(res, kNC_PageRank, pageRankLiteral, PR_TRUE); } // set the result type if (!browserResultTypeStr.IsEmpty()) { const PRUnichar *resultTypeUni = browserResultTypeStr.get(); nsCOMPtr resultTypeLiteral; if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(resultTypeUni, getter_AddRefs(resultTypeLiteral)))) { if (resultTypeLiteral) { mInner->Assert(res, kNC_SearchType, resultTypeLiteral, PR_TRUE); } } } // set the node type rv = mInner->Assert(res, kRDF_type, kNC_SearchResult, PR_TRUE); // Note: always add in parent-child relationship last! (if it isn't already set) #ifdef OLDWAY PRBool parentHasChildFlag = PR_FALSE; if (mParent) { mInner->HasAssertion(mParent, kNC_Child, res, PR_TRUE, &parentHasChildFlag); } if (!parentHasChildFlag) #endif { if (mParent) { rv = mInner->Assert(mParent, kNC_Child, res, PR_TRUE); } } // Persist this under kNC_LastSearchRoot if (mInner) { rv = mInner->Assert(kNC_LastSearchRoot, kNC_Child, res, PR_TRUE); } ++numResults; // place a cap on the # of results we can process if (numResults >= MAX_SEARCH_RESULTS_ALLOWED) break; } } // set hints so that the appropriate columns can be displayed if (mParent) { if (hasPriceFlag) SetHint(mParent, kNC_Price); if (hasAvailabilityFlag) SetHint(mParent, kNC_Availability); if (hasRelevanceFlag) SetHint(mParent, kNC_Relevance); if (hasDateFlag) SetHint(mParent, kNC_Date); } #ifdef DEBUG PRTime now2; now2 = PR_Now(); PRUint64 loadTime64; LL_SUB(loadTime64, now2, now); PRUint32 loadTime32; LL_L2UI(loadTime32, loadTime64); printf("Finished processing search results (%u microseconds)\n", loadTime32); #endif return(NS_OK); } nsresult InternetSearchDataSource::SetHint(nsIRDFResource *mParent, nsIRDFResource *hintRes) { if (!mInner) return(NS_OK); nsresult rv; PRBool hasAssertionFlag = PR_FALSE; rv = mInner->HasAssertion(mParent, hintRes, kTrueLiteral, PR_TRUE, &hasAssertionFlag); if (NS_SUCCEEDED(rv) && !hasAssertionFlag) { rv = mInner->Assert(mParent, hintRes, kTrueLiteral, PR_TRUE); } return(rv); } nsresult InternetSearchDataSource::ConvertEntities(nsString &nameStr, PRBool removeHTMLFlag, PRBool removeCRLFsFlag, PRBool trimWhiteSpaceFlag) { PRInt32 startOffset = 0, ampOffset, semiOffset, offset; // do this before converting entities if (removeHTMLFlag) { // munge out anything inside of HTML "<" / ">" tags while ((offset = nameStr.FindChar(PRUnichar('<'), 0)) >= 0) { PRInt32 offsetEnd = nameStr.FindChar(PRUnichar('>'), offset+1); if (offsetEnd <= offset) break; nameStr.Cut(offset, offsetEnd - offset + 1); } } while ((ampOffset = nameStr.FindChar(PRUnichar('&'), startOffset)) >= 0) { if ((semiOffset = nameStr.FindChar(PRUnichar(';'), ampOffset+1)) <= ampOffset) break; nsAutoString entityStr; nameStr.Mid(entityStr, ampOffset, semiOffset-ampOffset+1); nameStr.Cut(ampOffset, semiOffset-ampOffset+1); PRUnichar entityChar = 0; if (entityStr.LowerCaseEqualsLiteral(""")) entityChar = PRUnichar('\"'); else if (entityStr.LowerCaseEqualsLiteral("&")) entityChar = PRUnichar('&'); else if (entityStr.LowerCaseEqualsLiteral(" ")) entityChar = PRUnichar(' '); else if (entityStr.LowerCaseEqualsLiteral("<")) entityChar = PRUnichar('<'); else if (entityStr.LowerCaseEqualsLiteral(">")) entityChar = PRUnichar('>'); else if (entityStr.LowerCaseEqualsLiteral("¡")) entityChar = PRUnichar(161); else if (entityStr.LowerCaseEqualsLiteral("¢")) entityChar = PRUnichar(162); else if (entityStr.LowerCaseEqualsLiteral("£")) entityChar = PRUnichar(163); else if (entityStr.LowerCaseEqualsLiteral("¤")) entityChar = PRUnichar(164); else if (entityStr.LowerCaseEqualsLiteral("¥")) entityChar = PRUnichar(165); else if (entityStr.LowerCaseEqualsLiteral("¦")) entityChar = PRUnichar(166); else if (entityStr.LowerCaseEqualsLiteral("§")) entityChar = PRUnichar(167); else if (entityStr.LowerCaseEqualsLiteral("¨")) entityChar = PRUnichar(168); else if (entityStr.LowerCaseEqualsLiteral("©")) entityChar = PRUnichar(169); else if (entityStr.LowerCaseEqualsLiteral("ª")) entityChar = PRUnichar(170); else if (entityStr.LowerCaseEqualsLiteral("«")) entityChar = PRUnichar(171); else if (entityStr.LowerCaseEqualsLiteral("¬")) entityChar = PRUnichar(172); else if (entityStr.LowerCaseEqualsLiteral("­")) entityChar = PRUnichar(173); else if (entityStr.LowerCaseEqualsLiteral("®")) entityChar = PRUnichar(174); else if (entityStr.LowerCaseEqualsLiteral("¯")) entityChar = PRUnichar(175); else if (entityStr.LowerCaseEqualsLiteral("°")) entityChar = PRUnichar(176); else if (entityStr.LowerCaseEqualsLiteral("±")) entityChar = PRUnichar(177); else if (entityStr.LowerCaseEqualsLiteral("²")) entityChar = PRUnichar(178); else if (entityStr.LowerCaseEqualsLiteral("³")) entityChar = PRUnichar(179); else if (entityStr.LowerCaseEqualsLiteral("´")) entityChar = PRUnichar(180); else if (entityStr.LowerCaseEqualsLiteral("µ")) entityChar = PRUnichar(181); else if (entityStr.LowerCaseEqualsLiteral("¶")) entityChar = PRUnichar(182); else if (entityStr.LowerCaseEqualsLiteral("·")) entityChar = PRUnichar(183); else if (entityStr.LowerCaseEqualsLiteral("¸")) entityChar = PRUnichar(184); else if (entityStr.LowerCaseEqualsLiteral("¹")) entityChar = PRUnichar(185); else if (entityStr.LowerCaseEqualsLiteral("º")) entityChar = PRUnichar(186); else if (entityStr.LowerCaseEqualsLiteral("»")) entityChar = PRUnichar(187); else if (entityStr.LowerCaseEqualsLiteral("¼")) entityChar = PRUnichar(188); else if (entityStr.LowerCaseEqualsLiteral("½")) entityChar = PRUnichar(189); else if (entityStr.LowerCaseEqualsLiteral("¾")) entityChar = PRUnichar(190); else if (entityStr.LowerCaseEqualsLiteral("¿")) entityChar = PRUnichar(191); else if (entityStr.LowerCaseEqualsLiteral("à")) entityChar = PRUnichar(192); else if (entityStr.LowerCaseEqualsLiteral("á")) entityChar = PRUnichar(193); else if (entityStr.LowerCaseEqualsLiteral("â")) entityChar = PRUnichar(194); else if (entityStr.LowerCaseEqualsLiteral("ã")) entityChar = PRUnichar(195); else if (entityStr.LowerCaseEqualsLiteral("ä")) entityChar = PRUnichar(196); else if (entityStr.LowerCaseEqualsLiteral("å")) entityChar = PRUnichar(197); else if (entityStr.LowerCaseEqualsLiteral("æ")) entityChar = PRUnichar(198); else if (entityStr.LowerCaseEqualsLiteral("ç")) entityChar = PRUnichar(199); else if (entityStr.LowerCaseEqualsLiteral("è")) entityChar = PRUnichar(200); else if (entityStr.LowerCaseEqualsLiteral("é")) entityChar = PRUnichar(201); else if (entityStr.LowerCaseEqualsLiteral("ê")) entityChar = PRUnichar(202); else if (entityStr.LowerCaseEqualsLiteral("ë")) entityChar = PRUnichar(203); else if (entityStr.LowerCaseEqualsLiteral("ì")) entityChar = PRUnichar(204); else if (entityStr.LowerCaseEqualsLiteral("í")) entityChar = PRUnichar(205); else if (entityStr.LowerCaseEqualsLiteral("î")) entityChar = PRUnichar(206); else if (entityStr.LowerCaseEqualsLiteral("ï")) entityChar = PRUnichar(207); else if (entityStr.LowerCaseEqualsLiteral("ð")) entityChar = PRUnichar(208); else if (entityStr.LowerCaseEqualsLiteral("ñ")) entityChar = PRUnichar(209); else if (entityStr.LowerCaseEqualsLiteral("ò")) entityChar = PRUnichar(210); else if (entityStr.LowerCaseEqualsLiteral("ó")) entityChar = PRUnichar(211); else if (entityStr.LowerCaseEqualsLiteral("ô")) entityChar = PRUnichar(212); else if (entityStr.LowerCaseEqualsLiteral("õ")) entityChar = PRUnichar(213); else if (entityStr.LowerCaseEqualsLiteral("ö")) entityChar = PRUnichar(214); else if (entityStr.LowerCaseEqualsLiteral("×")) entityChar = PRUnichar(215); else if (entityStr.LowerCaseEqualsLiteral("ø")) entityChar = PRUnichar(216); else if (entityStr.LowerCaseEqualsLiteral("ù")) entityChar = PRUnichar(217); else if (entityStr.LowerCaseEqualsLiteral("ú")) entityChar = PRUnichar(218); else if (entityStr.LowerCaseEqualsLiteral("û")) entityChar = PRUnichar(219); else if (entityStr.LowerCaseEqualsLiteral("ü")) entityChar = PRUnichar(220); else if (entityStr.LowerCaseEqualsLiteral("ý")) entityChar = PRUnichar(221); else if (entityStr.LowerCaseEqualsLiteral("þ")) entityChar = PRUnichar(222); else if (entityStr.LowerCaseEqualsLiteral("ß")) entityChar = PRUnichar(223); else if (entityStr.LowerCaseEqualsLiteral("à")) entityChar = PRUnichar(224); else if (entityStr.LowerCaseEqualsLiteral("á")) entityChar = PRUnichar(225); else if (entityStr.LowerCaseEqualsLiteral("â")) entityChar = PRUnichar(226); else if (entityStr.LowerCaseEqualsLiteral("ã")) entityChar = PRUnichar(227); else if (entityStr.LowerCaseEqualsLiteral("ä")) entityChar = PRUnichar(228); else if (entityStr.LowerCaseEqualsLiteral("å")) entityChar = PRUnichar(229); else if (entityStr.LowerCaseEqualsLiteral("æ")) entityChar = PRUnichar(230); else if (entityStr.LowerCaseEqualsLiteral("ç")) entityChar = PRUnichar(231); else if (entityStr.LowerCaseEqualsLiteral("è")) entityChar = PRUnichar(232); else if (entityStr.LowerCaseEqualsLiteral("é")) entityChar = PRUnichar(233); else if (entityStr.LowerCaseEqualsLiteral("ê")) entityChar = PRUnichar(234); else if (entityStr.LowerCaseEqualsLiteral("ë")) entityChar = PRUnichar(235); else if (entityStr.LowerCaseEqualsLiteral("ì")) entityChar = PRUnichar(236); else if (entityStr.LowerCaseEqualsLiteral("í")) entityChar = PRUnichar(237); else if (entityStr.LowerCaseEqualsLiteral("î")) entityChar = PRUnichar(238); else if (entityStr.LowerCaseEqualsLiteral("ï")) entityChar = PRUnichar(239); else if (entityStr.LowerCaseEqualsLiteral("ð")) entityChar = PRUnichar(240); else if (entityStr.LowerCaseEqualsLiteral("ñ")) entityChar = PRUnichar(241); else if (entityStr.LowerCaseEqualsLiteral("ò")) entityChar = PRUnichar(242); else if (entityStr.LowerCaseEqualsLiteral("ó")) entityChar = PRUnichar(243); else if (entityStr.LowerCaseEqualsLiteral("ô")) entityChar = PRUnichar(244); else if (entityStr.LowerCaseEqualsLiteral("õ")) entityChar = PRUnichar(245); else if (entityStr.LowerCaseEqualsLiteral("ö")) entityChar = PRUnichar(246); else if (entityStr.LowerCaseEqualsLiteral("÷")) entityChar = PRUnichar(247); else if (entityStr.LowerCaseEqualsLiteral("ø")) entityChar = PRUnichar(248); else if (entityStr.LowerCaseEqualsLiteral("ù")) entityChar = PRUnichar(249); else if (entityStr.LowerCaseEqualsLiteral("ú")) entityChar = PRUnichar(250); else if (entityStr.LowerCaseEqualsLiteral("û")) entityChar = PRUnichar(251); else if (entityStr.LowerCaseEqualsLiteral("ü")) entityChar = PRUnichar(252); else if (entityStr.LowerCaseEqualsLiteral("ý")) entityChar = PRUnichar(253); else if (entityStr.LowerCaseEqualsLiteral("þ")) entityChar = PRUnichar(254); else if (entityStr.LowerCaseEqualsLiteral("ÿ")) entityChar = PRUnichar(255); startOffset = ampOffset; if (entityChar != 0) { nameStr.Insert(entityChar, ampOffset); ++startOffset; } } if (removeCRLFsFlag) { // cut out any CRs or LFs while ((offset = nameStr.FindCharInSet("\n\r", 0)) >= 0) { nameStr.Cut(offset, 1); } } if (trimWhiteSpaceFlag) { // trim name nameStr.Trim(" \t"); } return(NS_OK); } NS_IMETHODIMP InternetSearchDataSource::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) { nsresult rv = NS_OK; if (!nsCRT::strcmp(aTopic, "profile-before-change")) { // The profile is about to change. categoryDataSource = nsnull; if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) { // Delete search.rdf nsCOMPtr searchFile; rv = NS_GetSpecialDirectory(NS_APP_SEARCH_50_FILE, getter_AddRefs(searchFile)); if (NS_SUCCEEDED(rv)) rv = searchFile->Remove(PR_FALSE); } } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { // The profile has aleady changed. if (!categoryDataSource) GetCategoryList(); } return rv; } NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(LocalSearchDataSource, Init) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(InternetSearchDataSource, Init) static const nsModuleComponentInfo components[] = { { "Local Search", NS_RDFFINDDATASOURCE_CID, NS_LOCALSEARCH_SERVICE_CONTRACTID, LocalSearchDataSourceConstructor }, { "Local Search", NS_RDFFINDDATASOURCE_CID, NS_LOCALSEARCH_DATASOURCE_CONTRACTID, LocalSearchDataSourceConstructor }, { "Internet Search", NS_RDFSEARCHDATASOURCE_CID, NS_INTERNETSEARCH_SERVICE_CONTRACTID, InternetSearchDataSourceConstructor }, { "Internet Search", NS_RDFSEARCHDATASOURCE_CID, NS_INTERNETSEARCH_DATASOURCE_CONTRACTID, InternetSearchDataSourceConstructor }, }; NS_IMPL_NSGETMODULE(SearchServiceModule, components)