michael@0: //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * This file contains the definitions of nsNavHistoryQuery, michael@0: * nsNavHistoryQueryOptions, and those functions in nsINavHistory that directly michael@0: * support queries (specifically QueryStringToQueries and QueriesToQueryString). michael@0: */ michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #include "nsNavHistory.h" michael@0: #include "nsNavBookmarks.h" michael@0: #include "nsEscape.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsTArray.h" michael@0: #include "prprf.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: class QueryKeyValuePair michael@0: { michael@0: public: michael@0: michael@0: // QueryKeyValuePair michael@0: // michael@0: // 01234567890 michael@0: // input : qwerty&key=value&qwerty michael@0: // ^ ^ ^ michael@0: // aKeyBegin | aPastEnd (may point to null terminator) michael@0: // aEquals michael@0: // michael@0: // Special case: if aKeyBegin == aEquals, then there is only one string michael@0: // and no equal sign, so we treat the entire thing as a key with no value michael@0: michael@0: QueryKeyValuePair(const nsCSubstring& aSource, int32_t aKeyBegin, michael@0: int32_t aEquals, int32_t aPastEnd) michael@0: { michael@0: if (aEquals == aKeyBegin) michael@0: aEquals = aPastEnd; michael@0: key = Substring(aSource, aKeyBegin, aEquals - aKeyBegin); michael@0: if (aPastEnd - aEquals > 0) michael@0: value = Substring(aSource, aEquals + 1, aPastEnd - aEquals - 1); michael@0: } michael@0: nsCString key; michael@0: nsCString value; michael@0: }; michael@0: michael@0: static nsresult TokenizeQueryString(const nsACString& aQuery, michael@0: nsTArray* aTokens); michael@0: static nsresult ParseQueryBooleanString(const nsCString& aString, michael@0: bool* aValue); michael@0: michael@0: // query getters michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, BoolQueryGetter, nsINavHistoryQuery, michael@0: GetOnlyBookmarked, (bool*)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32QueryGetter, nsINavHistoryQuery, michael@0: GetBeginTimeReference, (uint32_t*)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Int64QueryGetter, nsINavHistoryQuery, michael@0: GetBeginTime, (int64_t*)); michael@0: static void AppendBoolKeyValueIfTrue(nsACString& aString, michael@0: const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: BoolQueryGetter getter); michael@0: static void AppendUint32KeyValueIfNonzero(nsACString& aString, michael@0: const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: Uint32QueryGetter getter); michael@0: static void AppendInt64KeyValueIfNonzero(nsACString& aString, michael@0: const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: Int64QueryGetter getter); michael@0: michael@0: // query setters michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, BoolQuerySetter, nsINavHistoryQuery, michael@0: SetOnlyBookmarked, (bool)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32QuerySetter, nsINavHistoryQuery, michael@0: SetBeginTimeReference, (uint32_t)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Int64QuerySetter, nsINavHistoryQuery, michael@0: SetBeginTime, (int64_t)); michael@0: static void SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: BoolQuerySetter setter); michael@0: static void SetQueryKeyUint32(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: Uint32QuerySetter setter); michael@0: static void SetQueryKeyInt64(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: Int64QuerySetter setter); michael@0: michael@0: // options setters michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, BoolOptionsSetter, michael@0: nsINavHistoryQueryOptions, michael@0: SetExpandQueries, (bool)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32OptionsSetter, michael@0: nsINavHistoryQueryOptions, michael@0: SetMaxResults, (uint32_t)); michael@0: typedef NS_STDCALL_FUNCPROTO(nsresult, Uint16OptionsSetter, michael@0: nsINavHistoryQueryOptions, michael@0: SetResultType, (uint16_t)); michael@0: static void SetOptionsKeyBool(const nsCString& aValue, michael@0: nsINavHistoryQueryOptions* aOptions, michael@0: BoolOptionsSetter setter); michael@0: static void SetOptionsKeyUint16(const nsCString& aValue, michael@0: nsINavHistoryQueryOptions* aOptions, michael@0: Uint16OptionsSetter setter); michael@0: static void SetOptionsKeyUint32(const nsCString& aValue, michael@0: nsINavHistoryQueryOptions* aOptions, michael@0: Uint32OptionsSetter setter); michael@0: michael@0: // Components of a query string. michael@0: // Note that query strings are also generated in nsNavBookmarks::GetFolderURI michael@0: // for performance reasons, so if you change these values, change that, too. michael@0: #define QUERYKEY_BEGIN_TIME "beginTime" michael@0: #define QUERYKEY_BEGIN_TIME_REFERENCE "beginTimeRef" michael@0: #define QUERYKEY_END_TIME "endTime" michael@0: #define QUERYKEY_END_TIME_REFERENCE "endTimeRef" michael@0: #define QUERYKEY_SEARCH_TERMS "terms" michael@0: #define QUERYKEY_MIN_VISITS "minVisits" michael@0: #define QUERYKEY_MAX_VISITS "maxVisits" michael@0: #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked" michael@0: #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost" michael@0: #define QUERYKEY_DOMAIN "domain" michael@0: #define QUERYKEY_FOLDER "folder" michael@0: #define QUERYKEY_NOTANNOTATION "!annotation" michael@0: #define QUERYKEY_ANNOTATION "annotation" michael@0: #define QUERYKEY_URI "uri" michael@0: #define QUERYKEY_URIISPREFIX "uriIsPrefix" michael@0: #define QUERYKEY_SEPARATOR "OR" michael@0: #define QUERYKEY_GROUP "group" michael@0: #define QUERYKEY_SORT "sort" michael@0: #define QUERYKEY_SORTING_ANNOTATION "sortingAnnotation" michael@0: #define QUERYKEY_RESULT_TYPE "type" michael@0: #define QUERYKEY_EXCLUDE_ITEMS "excludeItems" michael@0: #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries" michael@0: #define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders" michael@0: #define QUERYKEY_EXPAND_QUERIES "expandQueries" michael@0: #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle" michael@0: #define QUERYKEY_INCLUDE_HIDDEN "includeHidden" michael@0: #define QUERYKEY_MAX_RESULTS "maxResults" michael@0: #define QUERYKEY_QUERY_TYPE "queryType" michael@0: #define QUERYKEY_TAG "tag" michael@0: #define QUERYKEY_NOTTAGS "!tags" michael@0: #define QUERYKEY_ASYNC_ENABLED "asyncEnabled" michael@0: #define QUERYKEY_TRANSITION "transition" michael@0: michael@0: inline void AppendAmpersandIfNonempty(nsACString& aString) michael@0: { michael@0: if (! aString.IsEmpty()) michael@0: aString.Append('&'); michael@0: } michael@0: inline void AppendInt16(nsACString& str, int16_t i) michael@0: { michael@0: nsAutoCString tmp; michael@0: tmp.AppendInt(i); michael@0: str.Append(tmp); michael@0: } michael@0: inline void AppendInt32(nsACString& str, int32_t i) michael@0: { michael@0: nsAutoCString tmp; michael@0: tmp.AppendInt(i); michael@0: str.Append(tmp); michael@0: } michael@0: inline void AppendInt64(nsACString& str, int64_t i) michael@0: { michael@0: nsCString tmp; michael@0: tmp.AppendInt(i); michael@0: str.Append(tmp); michael@0: } michael@0: michael@0: namespace PlacesFolderConversion { michael@0: #define PLACES_ROOT_FOLDER "PLACES_ROOT" michael@0: #define BOOKMARKS_MENU_FOLDER "BOOKMARKS_MENU" michael@0: #define TAGS_FOLDER "TAGS" michael@0: #define UNFILED_BOOKMARKS_FOLDER "UNFILED_BOOKMARKS" michael@0: #define TOOLBAR_FOLDER "TOOLBAR" michael@0: michael@0: /** michael@0: * Converts a folder name to a folder id. michael@0: * michael@0: * @param aName michael@0: * The name of the folder to convert to a folder id. michael@0: * @returns the folder id if aName is a recognizable name, -1 otherwise. michael@0: */ michael@0: inline int64_t DecodeFolder(const nsCString &aName) michael@0: { michael@0: nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService(); michael@0: NS_ENSURE_TRUE(bs, false); michael@0: int64_t folderID = -1; michael@0: michael@0: if (aName.EqualsLiteral(PLACES_ROOT_FOLDER)) michael@0: (void)bs->GetPlacesRoot(&folderID); michael@0: else if (aName.EqualsLiteral(BOOKMARKS_MENU_FOLDER)) michael@0: (void)bs->GetBookmarksMenuFolder(&folderID); michael@0: else if (aName.EqualsLiteral(TAGS_FOLDER)) michael@0: (void)bs->GetTagsFolder(&folderID); michael@0: else if (aName.EqualsLiteral(UNFILED_BOOKMARKS_FOLDER)) michael@0: (void)bs->GetUnfiledBookmarksFolder(&folderID); michael@0: else if (aName.EqualsLiteral(TOOLBAR_FOLDER)) michael@0: (void)bs->GetToolbarFolder(&folderID); michael@0: michael@0: return folderID; michael@0: } michael@0: michael@0: /** michael@0: * Converts a folder id to a named constant, or a string representation of the michael@0: * folder id if there is no named constant for the folder, and appends it to michael@0: * aQuery. michael@0: * michael@0: * @param aQuery michael@0: * The string to append the folder string to. This is generally a michael@0: * query string, but could really be anything. michael@0: * @param aFolderID michael@0: * The folder ID to convert to the proper named constant. michael@0: */ michael@0: inline nsresult AppendFolder(nsCString &aQuery, int64_t aFolderID) michael@0: { michael@0: nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService(); michael@0: NS_ENSURE_STATE(bs); michael@0: int64_t folderID; michael@0: michael@0: if (NS_SUCCEEDED(bs->GetPlacesRoot(&folderID)) && michael@0: aFolderID == folderID) { michael@0: aQuery.AppendLiteral(PLACES_ROOT_FOLDER); michael@0: } michael@0: else if (NS_SUCCEEDED(bs->GetBookmarksMenuFolder(&folderID)) && michael@0: aFolderID == folderID) { michael@0: aQuery.AppendLiteral(BOOKMARKS_MENU_FOLDER); michael@0: } michael@0: else if (NS_SUCCEEDED(bs->GetTagsFolder(&folderID)) && michael@0: aFolderID == folderID) { michael@0: aQuery.AppendLiteral(TAGS_FOLDER); michael@0: } michael@0: else if (NS_SUCCEEDED(bs->GetUnfiledBookmarksFolder(&folderID)) && michael@0: aFolderID == folderID) { michael@0: aQuery.AppendLiteral(UNFILED_BOOKMARKS_FOLDER); michael@0: } michael@0: else if (NS_SUCCEEDED(bs->GetToolbarFolder(&folderID)) && michael@0: aFolderID == folderID) { michael@0: aQuery.AppendLiteral(TOOLBAR_FOLDER); michael@0: } michael@0: else { michael@0: // It wasn't one of our named constants, so just convert it to a string. michael@0: aQuery.AppendInt(aFolderID); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // nsNavHistory::QueryStringToQueries michael@0: // michael@0: // From C++ places code, you should use QueryStringToQueryArray, this is michael@0: // the harder-to-use XPCOM version. michael@0: michael@0: NS_IMETHODIMP michael@0: nsNavHistory::QueryStringToQueries(const nsACString& aQueryString, michael@0: nsINavHistoryQuery*** aQueries, michael@0: uint32_t* aResultCount, michael@0: nsINavHistoryQueryOptions** aOptions) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aQueries); michael@0: NS_ENSURE_ARG_POINTER(aResultCount); michael@0: NS_ENSURE_ARG_POINTER(aOptions); michael@0: michael@0: *aQueries = nullptr; michael@0: *aResultCount = 0; michael@0: nsCOMPtr options; michael@0: nsCOMArray queries; michael@0: nsresult rv = QueryStringToQueryArray(aQueryString, &queries, michael@0: getter_AddRefs(options)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aResultCount = queries.Count(); michael@0: if (queries.Count() > 0) { michael@0: // convert COM array to raw michael@0: *aQueries = static_cast michael@0: (nsMemory::Alloc(sizeof(nsINavHistoryQuery*) * queries.Count())); michael@0: NS_ENSURE_TRUE(*aQueries, NS_ERROR_OUT_OF_MEMORY); michael@0: for (int32_t i = 0; i < queries.Count(); i ++) { michael@0: (*aQueries)[i] = queries[i]; michael@0: NS_ADDREF((*aQueries)[i]); michael@0: } michael@0: } michael@0: NS_ADDREF(*aOptions = options); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // nsNavHistory::QueryStringToQueryArray michael@0: // michael@0: // An internal version of QueryStringToQueries that fills a COM array for michael@0: // ease-of-use. michael@0: michael@0: nsresult michael@0: nsNavHistory::QueryStringToQueryArray(const nsACString& aQueryString, michael@0: nsCOMArray* aQueries, michael@0: nsNavHistoryQueryOptions** aOptions) michael@0: { michael@0: nsresult rv; michael@0: aQueries->Clear(); michael@0: *aOptions = nullptr; michael@0: michael@0: nsRefPtr options(new nsNavHistoryQueryOptions()); michael@0: if (! options) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsTArray tokens; michael@0: rv = TokenizeQueryString(aQueryString, &tokens); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = TokensToQueries(tokens, aQueries, options); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Unable to parse the query string: "); michael@0: NS_WARNING(PromiseFlatCString(aQueryString).get()); michael@0: return rv; michael@0: } michael@0: michael@0: NS_ADDREF(*aOptions = options); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // nsNavHistory::QueriesToQueryString michael@0: michael@0: NS_IMETHODIMP michael@0: nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries, michael@0: uint32_t aQueryCount, michael@0: nsINavHistoryQueryOptions* aOptions, michael@0: nsACString& aQueryString) michael@0: { michael@0: NS_ENSURE_ARG(aQueries); michael@0: NS_ENSURE_ARG(aOptions); michael@0: michael@0: nsCOMPtr options = do_QueryInterface(aOptions); michael@0: NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG); michael@0: michael@0: nsAutoCString queryString; michael@0: for (uint32_t queryIndex = 0; queryIndex < aQueryCount; queryIndex ++) { michael@0: nsCOMPtr query = do_QueryInterface(aQueries[queryIndex]); michael@0: if (queryIndex > 0) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_SEPARATOR); michael@0: } michael@0: michael@0: bool hasIt; michael@0: michael@0: // begin time michael@0: query->GetHasBeginTime(&hasIt); michael@0: if (hasIt) { michael@0: AppendInt64KeyValueIfNonzero(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME), michael@0: query, &nsINavHistoryQuery::GetBeginTime); michael@0: AppendUint32KeyValueIfNonzero(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME_REFERENCE), michael@0: query, &nsINavHistoryQuery::GetBeginTimeReference); michael@0: } michael@0: michael@0: // end time michael@0: query->GetHasEndTime(&hasIt); michael@0: if (hasIt) { michael@0: AppendInt64KeyValueIfNonzero(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_END_TIME), michael@0: query, &nsINavHistoryQuery::GetEndTime); michael@0: AppendUint32KeyValueIfNonzero(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_END_TIME_REFERENCE), michael@0: query, &nsINavHistoryQuery::GetEndTimeReference); michael@0: } michael@0: michael@0: // search terms michael@0: query->GetHasSearchTerms(&hasIt); michael@0: if (hasIt) { michael@0: nsAutoString searchTerms; michael@0: query->GetSearchTerms(searchTerms); michael@0: nsCString escapedTerms; michael@0: if (! NS_Escape(NS_ConvertUTF16toUTF8(searchTerms), escapedTerms, michael@0: url_XAlphas)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_SEARCH_TERMS "="); michael@0: queryString += escapedTerms; michael@0: } michael@0: michael@0: // min and max visits michael@0: int32_t minVisits; michael@0: if (NS_SUCCEEDED(query->GetMinVisits(&minVisits)) && minVisits >= 0) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_MIN_VISITS "=")); michael@0: AppendInt32(queryString, minVisits); michael@0: } michael@0: michael@0: int32_t maxVisits; michael@0: if (NS_SUCCEEDED(query->GetMaxVisits(&maxVisits)) && maxVisits >= 0) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_MAX_VISITS "=")); michael@0: AppendInt32(queryString, maxVisits); michael@0: } michael@0: michael@0: // only bookmarked michael@0: AppendBoolKeyValueIfTrue(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_ONLY_BOOKMARKED), michael@0: query, &nsINavHistoryQuery::GetOnlyBookmarked); michael@0: michael@0: // domain (+ is host), only call if hasDomain, which means non-IsVoid michael@0: // this means we may get an empty string for the domain in the result, michael@0: // which is valid michael@0: query->GetHasDomain(&hasIt); michael@0: if (hasIt) { michael@0: AppendBoolKeyValueIfTrue(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_DOMAIN_IS_HOST), michael@0: query, &nsINavHistoryQuery::GetDomainIsHost); michael@0: nsAutoCString domain; michael@0: nsresult rv = query->GetDomain(domain); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsCString escapedDomain; michael@0: bool success = NS_Escape(domain, escapedDomain, url_XAlphas); michael@0: NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_DOMAIN "=")); michael@0: queryString.Append(escapedDomain); michael@0: } michael@0: michael@0: // uri michael@0: query->GetHasUri(&hasIt); michael@0: if (hasIt) { michael@0: AppendBoolKeyValueIfTrue(aQueryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_URIISPREFIX), michael@0: query, &nsINavHistoryQuery::GetUriIsPrefix); michael@0: nsCOMPtr uri; michael@0: query->GetUri(getter_AddRefs(uri)); michael@0: NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); // hasURI should tell is if invalid michael@0: nsAutoCString uriSpec; michael@0: nsresult rv = uri->GetSpec(uriSpec); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsAutoCString escaped; michael@0: bool success = NS_Escape(uriSpec, escaped, url_XAlphas); michael@0: NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_URI "=")); michael@0: queryString.Append(escaped); michael@0: } michael@0: michael@0: // annotation michael@0: query->GetHasAnnotation(&hasIt); michael@0: if (hasIt) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: bool annotationIsNot; michael@0: query->GetAnnotationIsNot(&annotationIsNot); michael@0: if (annotationIsNot) michael@0: queryString.AppendLiteral(QUERYKEY_NOTANNOTATION "="); michael@0: else michael@0: queryString.AppendLiteral(QUERYKEY_ANNOTATION "="); michael@0: nsAutoCString annot; michael@0: query->GetAnnotation(annot); michael@0: nsAutoCString escaped; michael@0: bool success = NS_Escape(annot, escaped, url_XAlphas); michael@0: NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); michael@0: queryString.Append(escaped); michael@0: } michael@0: michael@0: // folders michael@0: int64_t *folders = nullptr; michael@0: uint32_t folderCount = 0; michael@0: query->GetFolders(&folderCount, &folders); michael@0: for (uint32_t i = 0; i < folderCount; ++i) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "="); michael@0: nsresult rv = PlacesFolderConversion::AppendFolder(queryString, folders[i]); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: nsMemory::Free(folders); michael@0: michael@0: // tags michael@0: const nsTArray &tags = query->Tags(); michael@0: for (uint32_t i = 0; i < tags.Length(); ++i) { michael@0: nsAutoCString escapedTag; michael@0: if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_TAG "="); michael@0: queryString += escapedTag; michael@0: } michael@0: AppendBoolKeyValueIfTrue(queryString, michael@0: NS_LITERAL_CSTRING(QUERYKEY_NOTTAGS), michael@0: query, michael@0: &nsINavHistoryQuery::GetTagsAreNot); michael@0: michael@0: // transitions michael@0: const nsTArray& transitions = query->Transitions(); michael@0: for (uint32_t i = 0; i < transitions.Length(); ++i) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_TRANSITION "="); michael@0: AppendInt64(queryString, transitions[i]); michael@0: } michael@0: } michael@0: michael@0: // sorting michael@0: if (options->SortingMode() != nsINavHistoryQueryOptions::SORT_BY_NONE) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_SORT "="); michael@0: AppendInt16(queryString, options->SortingMode()); michael@0: if (options->SortingMode() == nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_DESCENDING || michael@0: options->SortingMode() == nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_ASCENDING) { michael@0: // sortingAnnotation michael@0: nsAutoCString sortingAnnotation; michael@0: if (NS_SUCCEEDED(options->GetSortingAnnotation(sortingAnnotation))) { michael@0: nsCString escaped; michael@0: if (!NS_Escape(sortingAnnotation, escaped, url_XAlphas)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_SORTING_ANNOTATION "="); michael@0: queryString.Append(escaped); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // result type michael@0: if (options->ResultType() != nsINavHistoryQueryOptions::RESULTS_AS_URI) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_RESULT_TYPE "="); michael@0: AppendInt16(queryString, options->ResultType()); michael@0: } michael@0: michael@0: // exclude items michael@0: if (options->ExcludeItems()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_ITEMS "=1"); michael@0: } michael@0: michael@0: // exclude queries michael@0: if (options->ExcludeQueries()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_QUERIES "=1"); michael@0: } michael@0: michael@0: // exclude read only folders michael@0: if (options->ExcludeReadOnlyFolders()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "=1"); michael@0: } michael@0: michael@0: // expand queries michael@0: if (!options->ExpandQueries()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_EXPAND_QUERIES "=0"); michael@0: } michael@0: michael@0: // include hidden michael@0: if (options->IncludeHidden()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_INCLUDE_HIDDEN "=1"); michael@0: } michael@0: michael@0: // max results michael@0: if (options->MaxResults()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_MAX_RESULTS "="); michael@0: AppendInt32(queryString, options->MaxResults()); michael@0: } michael@0: michael@0: // queryType michael@0: if (options->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_QUERY_TYPE "="); michael@0: AppendInt16(queryString, options->QueryType()); michael@0: } michael@0: michael@0: // async enabled michael@0: if (options->AsyncEnabled()) { michael@0: AppendAmpersandIfNonempty(queryString); michael@0: queryString += NS_LITERAL_CSTRING(QUERYKEY_ASYNC_ENABLED "=1"); michael@0: } michael@0: michael@0: aQueryString.Assign(NS_LITERAL_CSTRING("place:") + queryString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // TokenizeQueryString michael@0: michael@0: nsresult michael@0: TokenizeQueryString(const nsACString& aQuery, michael@0: nsTArray* aTokens) michael@0: { michael@0: // Strip off the "place:" prefix michael@0: const uint32_t prefixlen = 6; // = strlen("place:"); michael@0: nsCString query; michael@0: if (aQuery.Length() >= prefixlen && michael@0: Substring(aQuery, 0, prefixlen).EqualsLiteral("place:")) michael@0: query = Substring(aQuery, prefixlen); michael@0: else michael@0: query = aQuery; michael@0: michael@0: int32_t keyFirstIndex = 0; michael@0: int32_t equalsIndex = 0; michael@0: for (uint32_t i = 0; i < query.Length(); i ++) { michael@0: if (query[i] == '&') { michael@0: // new clause, save last one michael@0: if (i - keyFirstIndex > 1) { michael@0: if (! aTokens->AppendElement(QueryKeyValuePair(query, keyFirstIndex, michael@0: equalsIndex, i))) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: keyFirstIndex = equalsIndex = i + 1; michael@0: } else if (query[i] == '=') { michael@0: equalsIndex = i; michael@0: } michael@0: } michael@0: michael@0: // handle last pair, if any michael@0: if (query.Length() - keyFirstIndex > 1) { michael@0: if (! aTokens->AppendElement(QueryKeyValuePair(query, keyFirstIndex, michael@0: equalsIndex, query.Length()))) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsNavHistory::TokensToQueries michael@0: michael@0: nsresult michael@0: nsNavHistory::TokensToQueries(const nsTArray& aTokens, michael@0: nsCOMArray* aQueries, michael@0: nsNavHistoryQueryOptions* aOptions) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr query(new nsNavHistoryQuery()); michael@0: if (! query) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: if (! aQueries->AppendObject(query)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: if (aTokens.Length() == 0) michael@0: return NS_OK; // nothing to do michael@0: michael@0: nsTArray folders; michael@0: nsTArray tags; michael@0: nsTArray transitions; michael@0: for (uint32_t i = 0; i < aTokens.Length(); i ++) { michael@0: const QueryKeyValuePair& kvp = aTokens[i]; michael@0: michael@0: // begin time michael@0: if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME)) { michael@0: SetQueryKeyInt64(kvp.value, query, &nsINavHistoryQuery::SetBeginTime); michael@0: michael@0: // begin time reference michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME_REFERENCE)) { michael@0: SetQueryKeyUint32(kvp.value, query, &nsINavHistoryQuery::SetBeginTimeReference); michael@0: michael@0: // end time michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME)) { michael@0: SetQueryKeyInt64(kvp.value, query, &nsINavHistoryQuery::SetEndTime); michael@0: michael@0: // end time reference michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME_REFERENCE)) { michael@0: SetQueryKeyUint32(kvp.value, query, &nsINavHistoryQuery::SetEndTimeReference); michael@0: michael@0: // search terms michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_SEARCH_TERMS)) { michael@0: nsCString unescapedTerms = kvp.value; michael@0: NS_UnescapeURL(unescapedTerms); // modifies input michael@0: rv = query->SetSearchTerms(NS_ConvertUTF8toUTF16(unescapedTerms)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // min visits michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_MIN_VISITS)) { michael@0: int32_t visits = kvp.value.ToInteger(&rv); michael@0: if (NS_SUCCEEDED(rv)) michael@0: query->SetMinVisits(visits); michael@0: else michael@0: NS_WARNING("Bad number for minVisits in query"); michael@0: michael@0: // max visits michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_VISITS)) { michael@0: int32_t visits = kvp.value.ToInteger(&rv); michael@0: if (NS_SUCCEEDED(rv)) michael@0: query->SetMaxVisits(visits); michael@0: else michael@0: NS_WARNING("Bad number for maxVisits in query"); michael@0: michael@0: // onlyBookmarked flag michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_ONLY_BOOKMARKED)) { michael@0: SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetOnlyBookmarked); michael@0: michael@0: // domainIsHost flag michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN_IS_HOST)) { michael@0: SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetDomainIsHost); michael@0: michael@0: // domain string michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN)) { michael@0: nsAutoCString unescapedDomain(kvp.value); michael@0: NS_UnescapeURL(unescapedDomain); // modifies input michael@0: rv = query->SetDomain(unescapedDomain); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // folders michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDER)) { michael@0: int64_t folder; michael@0: if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) { michael@0: NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY); michael@0: } else { michael@0: folder = PlacesFolderConversion::DecodeFolder(kvp.value); michael@0: if (folder != -1) michael@0: NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY); michael@0: else michael@0: NS_WARNING("folders value in query is invalid, ignoring"); michael@0: } michael@0: michael@0: // uri michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_URI)) { michael@0: nsAutoCString unescapedUri(kvp.value); michael@0: NS_UnescapeURL(unescapedUri); // modifies input michael@0: nsCOMPtr uri; michael@0: nsresult rv = NS_NewURI(getter_AddRefs(uri), unescapedUri); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Unable to parse URI"); michael@0: } michael@0: rv = query->SetUri(uri); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // URI is prefix michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_URIISPREFIX)) { michael@0: SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetUriIsPrefix); michael@0: michael@0: // not annotation michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTANNOTATION)) { michael@0: nsAutoCString unescaped(kvp.value); michael@0: NS_UnescapeURL(unescaped); // modifies input michael@0: query->SetAnnotationIsNot(true); michael@0: query->SetAnnotation(unescaped); michael@0: michael@0: // annotation michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_ANNOTATION)) { michael@0: nsAutoCString unescaped(kvp.value); michael@0: NS_UnescapeURL(unescaped); // modifies input michael@0: query->SetAnnotationIsNot(false); michael@0: query->SetAnnotation(unescaped); michael@0: michael@0: // tag michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_TAG)) { michael@0: nsAutoCString unescaped(kvp.value); michael@0: NS_UnescapeURL(unescaped); // modifies input michael@0: NS_ConvertUTF8toUTF16 tag(unescaped); michael@0: if (!tags.Contains(tag)) { michael@0: NS_ENSURE_TRUE(tags.AppendElement(tag), NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: // not tags michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTTAGS)) { michael@0: SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetTagsAreNot); michael@0: michael@0: // transition michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_TRANSITION)) { michael@0: uint32_t transition = kvp.value.ToInteger(&rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!transitions.Contains(transition)) michael@0: NS_ENSURE_TRUE(transitions.AppendElement(transition), michael@0: NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: else { michael@0: NS_WARNING("Invalid Int32 transition value."); michael@0: } michael@0: michael@0: // new query component michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_SEPARATOR)) { michael@0: michael@0: if (folders.Length() != 0) { michael@0: query->SetFolders(folders.Elements(), folders.Length()); michael@0: folders.Clear(); michael@0: } michael@0: michael@0: if (tags.Length() > 0) { michael@0: rv = query->SetTags(tags); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: tags.Clear(); michael@0: } michael@0: michael@0: if (transitions.Length() > 0) { michael@0: rv = query->SetTransitions(transitions); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: transitions.Clear(); michael@0: } michael@0: michael@0: query = new nsNavHistoryQuery(); michael@0: if (! query) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: if (! aQueries->AppendObject(query)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: // sorting mode michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_SORT)) { michael@0: SetOptionsKeyUint16(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetSortingMode); michael@0: // sorting annotation michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_SORTING_ANNOTATION)) { michael@0: nsCString sortingAnnotation = kvp.value; michael@0: NS_UnescapeURL(sortingAnnotation); michael@0: rv = aOptions->SetSortingAnnotation(sortingAnnotation); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: // result type michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_RESULT_TYPE)) { michael@0: SetOptionsKeyUint16(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetResultType); michael@0: michael@0: // exclude items michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_ITEMS)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetExcludeItems); michael@0: michael@0: // exclude queries michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_QUERIES)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetExcludeQueries); michael@0: michael@0: // exclude read only folders michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetExcludeReadOnlyFolders); michael@0: michael@0: // expand queries michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetExpandQueries); michael@0: // include hidden michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_INCLUDE_HIDDEN)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetIncludeHidden); michael@0: // max results michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) { michael@0: SetOptionsKeyUint32(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetMaxResults); michael@0: // query type michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_QUERY_TYPE)) { michael@0: SetOptionsKeyUint16(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetQueryType); michael@0: // async enabled michael@0: } else if (kvp.key.EqualsLiteral(QUERYKEY_ASYNC_ENABLED)) { michael@0: SetOptionsKeyBool(kvp.value, aOptions, michael@0: &nsINavHistoryQueryOptions::SetAsyncEnabled); michael@0: // unknown key michael@0: } else { michael@0: NS_WARNING("TokensToQueries(), ignoring unknown key: "); michael@0: NS_WARNING(kvp.key.get()); michael@0: } michael@0: } michael@0: michael@0: if (folders.Length() != 0) michael@0: query->SetFolders(folders.Elements(), folders.Length()); michael@0: michael@0: if (tags.Length() > 0) { michael@0: rv = query->SetTags(tags); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: if (transitions.Length() > 0) { michael@0: rv = query->SetTransitions(transitions); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // ParseQueryBooleanString michael@0: // michael@0: // Converts a 0/1 or true/false string into a bool michael@0: michael@0: nsresult michael@0: ParseQueryBooleanString(const nsCString& aString, bool* aValue) michael@0: { michael@0: if (aString.EqualsLiteral("1") || aString.EqualsLiteral("true")) { michael@0: *aValue = true; michael@0: return NS_OK; michael@0: } else if (aString.EqualsLiteral("0") || aString.EqualsLiteral("false")) { michael@0: *aValue = false; michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: michael@0: // nsINavHistoryQuery ********************************************************** michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNavHistoryQuery, nsNavHistoryQuery, nsINavHistoryQuery) michael@0: michael@0: // nsINavHistoryQuery::nsNavHistoryQuery michael@0: // michael@0: // This must initialize the object such that the default values will cause michael@0: // all history to be returned if this query is used. Then the caller can michael@0: // just set the things it's interested in. michael@0: michael@0: nsNavHistoryQuery::nsNavHistoryQuery() michael@0: : mMinVisits(-1), mMaxVisits(-1), mBeginTime(0), michael@0: mBeginTimeReference(TIME_RELATIVE_EPOCH), michael@0: mEndTime(0), mEndTimeReference(TIME_RELATIVE_EPOCH), michael@0: mOnlyBookmarked(false), michael@0: mDomainIsHost(false), mUriIsPrefix(false), michael@0: mAnnotationIsNot(false), michael@0: mTagsAreNot(false) michael@0: { michael@0: // differentiate not set (IsVoid) from empty string (local files) michael@0: mDomain.SetIsVoid(true); michael@0: } michael@0: michael@0: /* attribute PRTime beginTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetBeginTime(PRTime *aBeginTime) michael@0: { michael@0: *aBeginTime = mBeginTime; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetBeginTime(PRTime aBeginTime) michael@0: { michael@0: mBeginTime = aBeginTime; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute long beginTimeReference; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetBeginTimeReference(uint32_t* _retval) michael@0: { michael@0: *_retval = mBeginTimeReference; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetBeginTimeReference(uint32_t aReference) michael@0: { michael@0: if (aReference > TIME_RELATIVE_NOW) michael@0: return NS_ERROR_INVALID_ARG; michael@0: mBeginTimeReference = aReference; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute boolean hasBeginTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasBeginTime(bool* _retval) michael@0: { michael@0: *_retval = ! (mBeginTimeReference == TIME_RELATIVE_EPOCH && mBeginTime == 0); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute PRTime absoluteBeginTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteBeginTime(PRTime* _retval) michael@0: { michael@0: *_retval = nsNavHistory::NormalizeTime(mBeginTimeReference, mBeginTime); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute PRTime endTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetEndTime(PRTime *aEndTime) michael@0: { michael@0: *aEndTime = mEndTime; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetEndTime(PRTime aEndTime) michael@0: { michael@0: mEndTime = aEndTime; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute long endTimeReference; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetEndTimeReference(uint32_t* _retval) michael@0: { michael@0: *_retval = mEndTimeReference; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetEndTimeReference(uint32_t aReference) michael@0: { michael@0: if (aReference > TIME_RELATIVE_NOW) michael@0: return NS_ERROR_INVALID_ARG; michael@0: mEndTimeReference = aReference; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute boolean hasEndTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasEndTime(bool* _retval) michael@0: { michael@0: *_retval = ! (mEndTimeReference == TIME_RELATIVE_EPOCH && mEndTime == 0); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute PRTime absoluteEndTime; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteEndTime(PRTime* _retval) michael@0: { michael@0: *_retval = nsNavHistory::NormalizeTime(mEndTimeReference, mEndTime); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute string searchTerms; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetSearchTerms(nsAString& aSearchTerms) michael@0: { michael@0: aSearchTerms = mSearchTerms; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetSearchTerms(const nsAString& aSearchTerms) michael@0: { michael@0: mSearchTerms = aSearchTerms; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasSearchTerms(bool* _retval) michael@0: { michael@0: *_retval = (! mSearchTerms.IsEmpty()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute int32_t minVisits; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetMinVisits(int32_t* _retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = mMinVisits; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetMinVisits(int32_t aVisits) michael@0: { michael@0: mMinVisits = aVisits; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute PRint32 maxVisits; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetMaxVisits(int32_t* _retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = mMaxVisits; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetMaxVisits(int32_t aVisits) michael@0: { michael@0: mMaxVisits = aVisits; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute boolean onlyBookmarked; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetOnlyBookmarked(bool *aOnlyBookmarked) michael@0: { michael@0: *aOnlyBookmarked = mOnlyBookmarked; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetOnlyBookmarked(bool aOnlyBookmarked) michael@0: { michael@0: mOnlyBookmarked = aOnlyBookmarked; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute boolean domainIsHost; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetDomainIsHost(bool *aDomainIsHost) michael@0: { michael@0: *aDomainIsHost = mDomainIsHost; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetDomainIsHost(bool aDomainIsHost) michael@0: { michael@0: mDomainIsHost = aDomainIsHost; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute AUTF8String domain; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetDomain(nsACString& aDomain) michael@0: { michael@0: aDomain = mDomain; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetDomain(const nsACString& aDomain) michael@0: { michael@0: mDomain = aDomain; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasDomain(bool* _retval) michael@0: { michael@0: // note that empty but not void is still a valid query (local files) michael@0: *_retval = (! mDomain.IsVoid()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute boolean uriIsPrefix; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetUriIsPrefix(bool* aIsPrefix) michael@0: { michael@0: *aIsPrefix = mUriIsPrefix; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetUriIsPrefix(bool aIsPrefix) michael@0: { michael@0: mUriIsPrefix = aIsPrefix; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute nsIURI uri; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetUri(nsIURI** aUri) michael@0: { michael@0: NS_IF_ADDREF(*aUri = mUri); michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetUri(nsIURI* aUri) michael@0: { michael@0: mUri = aUri; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasUri(bool* aHasUri) michael@0: { michael@0: *aHasUri = (mUri != nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute boolean annotationIsNot; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetAnnotationIsNot(bool* aIsNot) michael@0: { michael@0: *aIsNot = mAnnotationIsNot; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetAnnotationIsNot(bool aIsNot) michael@0: { michael@0: mAnnotationIsNot = aIsNot; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute AUTF8String annotation; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetAnnotation(nsACString& aAnnotation) michael@0: { michael@0: aAnnotation = mAnnotation; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetAnnotation(const nsACString& aAnnotation) michael@0: { michael@0: mAnnotation = aAnnotation; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetHasAnnotation(bool* aHasIt) michael@0: { michael@0: *aHasIt = ! mAnnotation.IsEmpty(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute nsIVariant tags; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetTags(nsIVariant **aTags) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aTags); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr out = do_CreateInstance(NS_VARIANT_CONTRACTID, michael@0: &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: uint32_t arrayLen = mTags.Length(); michael@0: michael@0: if (arrayLen == 0) michael@0: rv = out->SetAsEmptyArray(); michael@0: else { michael@0: // Note: The resulting nsIVariant dupes both the array and its elements. michael@0: const char16_t **array = reinterpret_cast michael@0: (NS_Alloc(arrayLen * sizeof(char16_t *))); michael@0: NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: for (uint32_t i = 0; i < arrayLen; ++i) { michael@0: array[i] = mTags[i].get(); michael@0: } michael@0: michael@0: rv = out->SetAsArray(nsIDataType::VTYPE_WCHAR_STR, michael@0: nullptr, michael@0: arrayLen, michael@0: reinterpret_cast(array)); michael@0: NS_Free(array); michael@0: } michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: NS_ADDREF(*aTags = out); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetTags(nsIVariant *aTags) michael@0: { michael@0: NS_ENSURE_ARG(aTags); michael@0: michael@0: uint16_t dataType; michael@0: aTags->GetDataType(&dataType); michael@0: michael@0: // Caller passed in empty array. Easy -- clear our mTags array and return. michael@0: if (dataType == nsIDataType::VTYPE_EMPTY_ARRAY) { michael@0: mTags.Clear(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Before we go any further, make sure caller passed in an array. michael@0: NS_ENSURE_TRUE(dataType == nsIDataType::VTYPE_ARRAY, NS_ERROR_ILLEGAL_VALUE); michael@0: michael@0: uint16_t eltType; michael@0: nsIID eltIID; michael@0: uint32_t arrayLen; michael@0: void *array; michael@0: michael@0: // Convert the nsIVariant to an array. We own the resulting buffer and its michael@0: // elements. michael@0: nsresult rv = aTags->GetAsArray(&eltType, &eltIID, &arrayLen, &array); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // If element type is not wstring, thanks a lot. Your memory die now. michael@0: if (eltType != nsIDataType::VTYPE_WCHAR_STR) { michael@0: switch (eltType) { michael@0: case nsIDataType::VTYPE_ID: michael@0: case nsIDataType::VTYPE_CHAR_STR: michael@0: { michael@0: char **charArray = reinterpret_cast(array); michael@0: for (uint32_t i = 0; i < arrayLen; ++i) { michael@0: if (charArray[i]) michael@0: NS_Free(charArray[i]); michael@0: } michael@0: } michael@0: break; michael@0: case nsIDataType::VTYPE_INTERFACE: michael@0: case nsIDataType::VTYPE_INTERFACE_IS: michael@0: { michael@0: nsISupports **supportsArray = reinterpret_cast(array); michael@0: for (uint32_t i = 0; i < arrayLen; ++i) { michael@0: NS_IF_RELEASE(supportsArray[i]); michael@0: } michael@0: } michael@0: break; michael@0: // The other types are primitives that do not need to be freed. michael@0: } michael@0: NS_Free(array); michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: michael@0: char16_t **tags = reinterpret_cast(array); michael@0: mTags.Clear(); michael@0: michael@0: // Finally, add each passed-in tag to our mTags array and then sort it. michael@0: for (uint32_t i = 0; i < arrayLen; ++i) { michael@0: michael@0: // Don't allow nulls. michael@0: if (!tags[i]) { michael@0: NS_Free(tags); michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: michael@0: nsDependentString tag(tags[i]); michael@0: michael@0: // Don't store duplicate tags. This isn't just to save memory or to be michael@0: // fancy; the SQL that's built from the tags relies on no dupes. michael@0: if (!mTags.Contains(tag)) { michael@0: if (!mTags.AppendElement(tag)) { michael@0: NS_Free(tags[i]); michael@0: NS_Free(tags); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: NS_Free(tags[i]); michael@0: } michael@0: NS_Free(tags); michael@0: michael@0: mTags.Sort(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute boolean tagsAreNot; */ michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetTagsAreNot(bool *aTagsAreNot) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aTagsAreNot); michael@0: *aTagsAreNot = mTagsAreNot; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetTagsAreNot(bool aTagsAreNot) michael@0: { michael@0: mTagsAreNot = aTagsAreNot; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetFolders(uint32_t *aCount, michael@0: int64_t **aFolders) michael@0: { michael@0: uint32_t count = mFolders.Length(); michael@0: int64_t *folders = nullptr; michael@0: if (count > 0) { michael@0: folders = static_cast michael@0: (nsMemory::Alloc(count * sizeof(int64_t))); michael@0: NS_ENSURE_TRUE(folders, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: for (uint32_t i = 0; i < count; ++i) { michael@0: folders[i] = mFolders[i]; michael@0: } michael@0: } michael@0: *aCount = count; michael@0: *aFolders = folders; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetFolderCount(uint32_t *aCount) michael@0: { michael@0: *aCount = mFolders.Length(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetFolders(const int64_t *aFolders, michael@0: uint32_t aFolderCount) michael@0: { michael@0: if (!mFolders.ReplaceElementsAt(0, mFolders.Length(), michael@0: aFolders, aFolderCount)) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetTransitions(uint32_t* aCount, michael@0: uint32_t** aTransitions) michael@0: { michael@0: uint32_t count = mTransitions.Length(); michael@0: uint32_t* transitions = nullptr; michael@0: if (count > 0) { michael@0: transitions = reinterpret_cast michael@0: (NS_Alloc(count * sizeof(uint32_t))); michael@0: NS_ENSURE_TRUE(transitions, NS_ERROR_OUT_OF_MEMORY); michael@0: for (uint32_t i = 0; i < count; ++i) { michael@0: transitions[i] = mTransitions[i]; michael@0: } michael@0: } michael@0: *aCount = count; michael@0: *aTransitions = transitions; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::GetTransitionCount(uint32_t* aCount) michael@0: { michael@0: *aCount = mTransitions.Length(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::SetTransitions(const uint32_t* aTransitions, michael@0: uint32_t aCount) michael@0: { michael@0: if (!mTransitions.ReplaceElementsAt(0, mTransitions.Length(), aTransitions, michael@0: aCount)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNavHistoryQuery::Clone(nsINavHistoryQuery** _retval) michael@0: { michael@0: *_retval = nullptr; michael@0: michael@0: nsNavHistoryQuery *clone = new nsNavHistoryQuery(*this); michael@0: NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: clone->mRefCnt = 0; // the clone doesn't inherit our refcount michael@0: NS_ADDREF(*_retval = clone); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // nsNavHistoryQueryOptions michael@0: NS_IMPL_ISUPPORTS(nsNavHistoryQueryOptions, nsNavHistoryQueryOptions, nsINavHistoryQueryOptions) michael@0: michael@0: // sortingMode michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetSortingMode(uint16_t* aMode) michael@0: { michael@0: *aMode = mSort; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetSortingMode(uint16_t aMode) michael@0: { michael@0: if (aMode > SORT_BY_FRECENCY_DESCENDING) michael@0: return NS_ERROR_INVALID_ARG; michael@0: mSort = aMode; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // sortingAnnotation michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetSortingAnnotation(nsACString& _result) { michael@0: _result.Assign(mSortingAnnotation); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetSortingAnnotation(const nsACString& aSortingAnnotation) { michael@0: mSortingAnnotation.Assign(aSortingAnnotation); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // resultType michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetResultType(uint16_t* aType) michael@0: { michael@0: *aType = mResultType; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetResultType(uint16_t aType) michael@0: { michael@0: if (aType > RESULTS_AS_TAG_CONTENTS) michael@0: return NS_ERROR_INVALID_ARG; michael@0: // Tag queries and containers are bookmarks related, so we set the QueryType michael@0: // accordingly. michael@0: if (aType == RESULTS_AS_TAG_QUERY || aType == RESULTS_AS_TAG_CONTENTS) michael@0: mQueryType = QUERY_TYPE_BOOKMARKS; michael@0: mResultType = aType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // excludeItems michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetExcludeItems(bool* aExclude) michael@0: { michael@0: *aExclude = mExcludeItems; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetExcludeItems(bool aExclude) michael@0: { michael@0: mExcludeItems = aExclude; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // excludeQueries michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetExcludeQueries(bool* aExclude) michael@0: { michael@0: *aExclude = mExcludeQueries; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetExcludeQueries(bool aExclude) michael@0: { michael@0: mExcludeQueries = aExclude; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // excludeReadOnlyFolders michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetExcludeReadOnlyFolders(bool* aExclude) michael@0: { michael@0: *aExclude = mExcludeReadOnlyFolders; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetExcludeReadOnlyFolders(bool aExclude) michael@0: { michael@0: mExcludeReadOnlyFolders = aExclude; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // expandQueries michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetExpandQueries(bool* aExpand) michael@0: { michael@0: *aExpand = mExpandQueries; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetExpandQueries(bool aExpand) michael@0: { michael@0: mExpandQueries = aExpand; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // includeHidden michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetIncludeHidden(bool* aIncludeHidden) michael@0: { michael@0: *aIncludeHidden = mIncludeHidden; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetIncludeHidden(bool aIncludeHidden) michael@0: { michael@0: mIncludeHidden = aIncludeHidden; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // maxResults michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetMaxResults(uint32_t* aMaxResults) michael@0: { michael@0: *aMaxResults = mMaxResults; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetMaxResults(uint32_t aMaxResults) michael@0: { michael@0: mMaxResults = aMaxResults; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // queryType michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetQueryType(uint16_t* _retval) michael@0: { michael@0: *_retval = mQueryType; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetQueryType(uint16_t aQueryType) michael@0: { michael@0: // Tag query and containers are forced to QUERY_TYPE_BOOKMARKS when the michael@0: // resultType is set. michael@0: if (mResultType == RESULTS_AS_TAG_CONTENTS || michael@0: mResultType == RESULTS_AS_TAG_QUERY) michael@0: return NS_OK; michael@0: mQueryType = aQueryType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // asyncEnabled michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::GetAsyncEnabled(bool* _asyncEnabled) michael@0: { michael@0: *_asyncEnabled = mAsyncEnabled; michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::SetAsyncEnabled(bool aAsyncEnabled) michael@0: { michael@0: mAsyncEnabled = aAsyncEnabled; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** aResult) michael@0: { michael@0: nsNavHistoryQueryOptions *clone = nullptr; michael@0: nsresult rv = Clone(&clone); michael@0: *aResult = clone; michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions **aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: nsNavHistoryQueryOptions *result = new nsNavHistoryQueryOptions(); michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsRefPtr resultHolder(result); michael@0: result->mSort = mSort; michael@0: result->mResultType = mResultType; michael@0: result->mExcludeItems = mExcludeItems; michael@0: result->mExcludeQueries = mExcludeQueries; michael@0: result->mExpandQueries = mExpandQueries; michael@0: result->mMaxResults = mMaxResults; michael@0: result->mQueryType = mQueryType; michael@0: result->mParentAnnotationToExclude = mParentAnnotationToExclude; michael@0: result->mAsyncEnabled = mAsyncEnabled; michael@0: michael@0: resultHolder.swap(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // AppendBoolKeyValueIfTrue michael@0: michael@0: void // static michael@0: AppendBoolKeyValueIfTrue(nsACString& aString, const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: BoolQueryGetter getter) michael@0: { michael@0: bool value; michael@0: DebugOnly rv = (aQuery->*getter)(&value); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting boolean value"); michael@0: if (value) { michael@0: AppendAmpersandIfNonempty(aString); michael@0: aString += aName; michael@0: aString.AppendLiteral("=1"); michael@0: } michael@0: } michael@0: michael@0: michael@0: // AppendUint32KeyValueIfNonzero michael@0: michael@0: void // static michael@0: AppendUint32KeyValueIfNonzero(nsACString& aString, michael@0: const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: Uint32QueryGetter getter) michael@0: { michael@0: uint32_t value; michael@0: DebugOnly rv = (aQuery->*getter)(&value); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value"); michael@0: if (value) { michael@0: AppendAmpersandIfNonempty(aString); michael@0: aString += aName; michael@0: michael@0: // AppendInt requires a concrete string michael@0: nsAutoCString appendMe("="); michael@0: appendMe.AppendInt(value); michael@0: aString.Append(appendMe); michael@0: } michael@0: } michael@0: michael@0: michael@0: // AppendInt64KeyValueIfNonzero michael@0: michael@0: void // static michael@0: AppendInt64KeyValueIfNonzero(nsACString& aString, michael@0: const nsCString& aName, michael@0: nsINavHistoryQuery* aQuery, michael@0: Int64QueryGetter getter) michael@0: { michael@0: PRTime value; michael@0: DebugOnly rv = (aQuery->*getter)(&value); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value"); michael@0: if (value) { michael@0: AppendAmpersandIfNonempty(aString); michael@0: aString += aName; michael@0: nsAutoCString appendMe("="); michael@0: appendMe.AppendInt(static_cast(value)); michael@0: aString.Append(appendMe); michael@0: } michael@0: } michael@0: michael@0: michael@0: // SetQuery/OptionsKeyBool michael@0: michael@0: void // static michael@0: SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: BoolQuerySetter setter) michael@0: { michael@0: bool value; michael@0: nsresult rv = ParseQueryBooleanString(aValue, &value); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = (aQuery->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting boolean key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid boolean key value in query string."); michael@0: } michael@0: } michael@0: void // static michael@0: SetOptionsKeyBool(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions, michael@0: BoolOptionsSetter setter) michael@0: { michael@0: bool value; michael@0: nsresult rv = ParseQueryBooleanString(aValue, &value); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = (aOptions->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting boolean key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid boolean key value in query string."); michael@0: } michael@0: } michael@0: michael@0: michael@0: // SetQuery/OptionsKeyUint32 michael@0: michael@0: void // static michael@0: SetQueryKeyUint32(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: Uint32QuerySetter setter) michael@0: { michael@0: nsresult rv; michael@0: uint32_t value = aValue.ToInteger(&rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = (aQuery->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting Int32 key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid Int32 key value in query string."); michael@0: } michael@0: } michael@0: void // static michael@0: SetOptionsKeyUint32(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions, michael@0: Uint32OptionsSetter setter) michael@0: { michael@0: nsresult rv; michael@0: uint32_t value = aValue.ToInteger(&rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = (aOptions->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting Int32 key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid Int32 key value in query string."); michael@0: } michael@0: } michael@0: michael@0: void // static michael@0: SetOptionsKeyUint16(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions, michael@0: Uint16OptionsSetter setter) michael@0: { michael@0: nsresult rv; michael@0: uint16_t value = static_cast(aValue.ToInteger(&rv)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = (aOptions->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting Int16 key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid Int16 key value in query string."); michael@0: } michael@0: } michael@0: michael@0: michael@0: // SetQueryKeyInt64 michael@0: michael@0: void SetQueryKeyInt64(const nsCString& aValue, nsINavHistoryQuery* aQuery, michael@0: Int64QuerySetter setter) michael@0: { michael@0: nsresult rv; michael@0: int64_t value; michael@0: if (PR_sscanf(aValue.get(), "%lld", &value) == 1) { michael@0: rv = (aQuery->*setter)(value); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Error setting Int64 key value"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Invalid Int64 value in query string."); michael@0: } michael@0: }