Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /**
7 * This file contains the definitions of nsNavHistoryQuery,
8 * nsNavHistoryQueryOptions, and those functions in nsINavHistory that directly
9 * support queries (specifically QueryStringToQueries and QueriesToQueryString).
10 */
12 #include "mozilla/DebugOnly.h"
14 #include "nsNavHistory.h"
15 #include "nsNavBookmarks.h"
16 #include "nsEscape.h"
17 #include "nsCOMArray.h"
18 #include "nsNetUtil.h"
19 #include "nsTArray.h"
20 #include "prprf.h"
22 using namespace mozilla;
24 class QueryKeyValuePair
25 {
26 public:
28 // QueryKeyValuePair
29 //
30 // 01234567890
31 // input : qwerty&key=value&qwerty
32 // ^ ^ ^
33 // aKeyBegin | aPastEnd (may point to null terminator)
34 // aEquals
35 //
36 // Special case: if aKeyBegin == aEquals, then there is only one string
37 // and no equal sign, so we treat the entire thing as a key with no value
39 QueryKeyValuePair(const nsCSubstring& aSource, int32_t aKeyBegin,
40 int32_t aEquals, int32_t aPastEnd)
41 {
42 if (aEquals == aKeyBegin)
43 aEquals = aPastEnd;
44 key = Substring(aSource, aKeyBegin, aEquals - aKeyBegin);
45 if (aPastEnd - aEquals > 0)
46 value = Substring(aSource, aEquals + 1, aPastEnd - aEquals - 1);
47 }
48 nsCString key;
49 nsCString value;
50 };
52 static nsresult TokenizeQueryString(const nsACString& aQuery,
53 nsTArray<QueryKeyValuePair>* aTokens);
54 static nsresult ParseQueryBooleanString(const nsCString& aString,
55 bool* aValue);
57 // query getters
58 typedef NS_STDCALL_FUNCPROTO(nsresult, BoolQueryGetter, nsINavHistoryQuery,
59 GetOnlyBookmarked, (bool*));
60 typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32QueryGetter, nsINavHistoryQuery,
61 GetBeginTimeReference, (uint32_t*));
62 typedef NS_STDCALL_FUNCPROTO(nsresult, Int64QueryGetter, nsINavHistoryQuery,
63 GetBeginTime, (int64_t*));
64 static void AppendBoolKeyValueIfTrue(nsACString& aString,
65 const nsCString& aName,
66 nsINavHistoryQuery* aQuery,
67 BoolQueryGetter getter);
68 static void AppendUint32KeyValueIfNonzero(nsACString& aString,
69 const nsCString& aName,
70 nsINavHistoryQuery* aQuery,
71 Uint32QueryGetter getter);
72 static void AppendInt64KeyValueIfNonzero(nsACString& aString,
73 const nsCString& aName,
74 nsINavHistoryQuery* aQuery,
75 Int64QueryGetter getter);
77 // query setters
78 typedef NS_STDCALL_FUNCPROTO(nsresult, BoolQuerySetter, nsINavHistoryQuery,
79 SetOnlyBookmarked, (bool));
80 typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32QuerySetter, nsINavHistoryQuery,
81 SetBeginTimeReference, (uint32_t));
82 typedef NS_STDCALL_FUNCPROTO(nsresult, Int64QuerySetter, nsINavHistoryQuery,
83 SetBeginTime, (int64_t));
84 static void SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery,
85 BoolQuerySetter setter);
86 static void SetQueryKeyUint32(const nsCString& aValue, nsINavHistoryQuery* aQuery,
87 Uint32QuerySetter setter);
88 static void SetQueryKeyInt64(const nsCString& aValue, nsINavHistoryQuery* aQuery,
89 Int64QuerySetter setter);
91 // options setters
92 typedef NS_STDCALL_FUNCPROTO(nsresult, BoolOptionsSetter,
93 nsINavHistoryQueryOptions,
94 SetExpandQueries, (bool));
95 typedef NS_STDCALL_FUNCPROTO(nsresult, Uint32OptionsSetter,
96 nsINavHistoryQueryOptions,
97 SetMaxResults, (uint32_t));
98 typedef NS_STDCALL_FUNCPROTO(nsresult, Uint16OptionsSetter,
99 nsINavHistoryQueryOptions,
100 SetResultType, (uint16_t));
101 static void SetOptionsKeyBool(const nsCString& aValue,
102 nsINavHistoryQueryOptions* aOptions,
103 BoolOptionsSetter setter);
104 static void SetOptionsKeyUint16(const nsCString& aValue,
105 nsINavHistoryQueryOptions* aOptions,
106 Uint16OptionsSetter setter);
107 static void SetOptionsKeyUint32(const nsCString& aValue,
108 nsINavHistoryQueryOptions* aOptions,
109 Uint32OptionsSetter setter);
111 // Components of a query string.
112 // Note that query strings are also generated in nsNavBookmarks::GetFolderURI
113 // for performance reasons, so if you change these values, change that, too.
114 #define QUERYKEY_BEGIN_TIME "beginTime"
115 #define QUERYKEY_BEGIN_TIME_REFERENCE "beginTimeRef"
116 #define QUERYKEY_END_TIME "endTime"
117 #define QUERYKEY_END_TIME_REFERENCE "endTimeRef"
118 #define QUERYKEY_SEARCH_TERMS "terms"
119 #define QUERYKEY_MIN_VISITS "minVisits"
120 #define QUERYKEY_MAX_VISITS "maxVisits"
121 #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked"
122 #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost"
123 #define QUERYKEY_DOMAIN "domain"
124 #define QUERYKEY_FOLDER "folder"
125 #define QUERYKEY_NOTANNOTATION "!annotation"
126 #define QUERYKEY_ANNOTATION "annotation"
127 #define QUERYKEY_URI "uri"
128 #define QUERYKEY_URIISPREFIX "uriIsPrefix"
129 #define QUERYKEY_SEPARATOR "OR"
130 #define QUERYKEY_GROUP "group"
131 #define QUERYKEY_SORT "sort"
132 #define QUERYKEY_SORTING_ANNOTATION "sortingAnnotation"
133 #define QUERYKEY_RESULT_TYPE "type"
134 #define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
135 #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries"
136 #define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders"
137 #define QUERYKEY_EXPAND_QUERIES "expandQueries"
138 #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle"
139 #define QUERYKEY_INCLUDE_HIDDEN "includeHidden"
140 #define QUERYKEY_MAX_RESULTS "maxResults"
141 #define QUERYKEY_QUERY_TYPE "queryType"
142 #define QUERYKEY_TAG "tag"
143 #define QUERYKEY_NOTTAGS "!tags"
144 #define QUERYKEY_ASYNC_ENABLED "asyncEnabled"
145 #define QUERYKEY_TRANSITION "transition"
147 inline void AppendAmpersandIfNonempty(nsACString& aString)
148 {
149 if (! aString.IsEmpty())
150 aString.Append('&');
151 }
152 inline void AppendInt16(nsACString& str, int16_t i)
153 {
154 nsAutoCString tmp;
155 tmp.AppendInt(i);
156 str.Append(tmp);
157 }
158 inline void AppendInt32(nsACString& str, int32_t i)
159 {
160 nsAutoCString tmp;
161 tmp.AppendInt(i);
162 str.Append(tmp);
163 }
164 inline void AppendInt64(nsACString& str, int64_t i)
165 {
166 nsCString tmp;
167 tmp.AppendInt(i);
168 str.Append(tmp);
169 }
171 namespace PlacesFolderConversion {
172 #define PLACES_ROOT_FOLDER "PLACES_ROOT"
173 #define BOOKMARKS_MENU_FOLDER "BOOKMARKS_MENU"
174 #define TAGS_FOLDER "TAGS"
175 #define UNFILED_BOOKMARKS_FOLDER "UNFILED_BOOKMARKS"
176 #define TOOLBAR_FOLDER "TOOLBAR"
178 /**
179 * Converts a folder name to a folder id.
180 *
181 * @param aName
182 * The name of the folder to convert to a folder id.
183 * @returns the folder id if aName is a recognizable name, -1 otherwise.
184 */
185 inline int64_t DecodeFolder(const nsCString &aName)
186 {
187 nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
188 NS_ENSURE_TRUE(bs, false);
189 int64_t folderID = -1;
191 if (aName.EqualsLiteral(PLACES_ROOT_FOLDER))
192 (void)bs->GetPlacesRoot(&folderID);
193 else if (aName.EqualsLiteral(BOOKMARKS_MENU_FOLDER))
194 (void)bs->GetBookmarksMenuFolder(&folderID);
195 else if (aName.EqualsLiteral(TAGS_FOLDER))
196 (void)bs->GetTagsFolder(&folderID);
197 else if (aName.EqualsLiteral(UNFILED_BOOKMARKS_FOLDER))
198 (void)bs->GetUnfiledBookmarksFolder(&folderID);
199 else if (aName.EqualsLiteral(TOOLBAR_FOLDER))
200 (void)bs->GetToolbarFolder(&folderID);
202 return folderID;
203 }
205 /**
206 * Converts a folder id to a named constant, or a string representation of the
207 * folder id if there is no named constant for the folder, and appends it to
208 * aQuery.
209 *
210 * @param aQuery
211 * The string to append the folder string to. This is generally a
212 * query string, but could really be anything.
213 * @param aFolderID
214 * The folder ID to convert to the proper named constant.
215 */
216 inline nsresult AppendFolder(nsCString &aQuery, int64_t aFolderID)
217 {
218 nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
219 NS_ENSURE_STATE(bs);
220 int64_t folderID;
222 if (NS_SUCCEEDED(bs->GetPlacesRoot(&folderID)) &&
223 aFolderID == folderID) {
224 aQuery.AppendLiteral(PLACES_ROOT_FOLDER);
225 }
226 else if (NS_SUCCEEDED(bs->GetBookmarksMenuFolder(&folderID)) &&
227 aFolderID == folderID) {
228 aQuery.AppendLiteral(BOOKMARKS_MENU_FOLDER);
229 }
230 else if (NS_SUCCEEDED(bs->GetTagsFolder(&folderID)) &&
231 aFolderID == folderID) {
232 aQuery.AppendLiteral(TAGS_FOLDER);
233 }
234 else if (NS_SUCCEEDED(bs->GetUnfiledBookmarksFolder(&folderID)) &&
235 aFolderID == folderID) {
236 aQuery.AppendLiteral(UNFILED_BOOKMARKS_FOLDER);
237 }
238 else if (NS_SUCCEEDED(bs->GetToolbarFolder(&folderID)) &&
239 aFolderID == folderID) {
240 aQuery.AppendLiteral(TOOLBAR_FOLDER);
241 }
242 else {
243 // It wasn't one of our named constants, so just convert it to a string.
244 aQuery.AppendInt(aFolderID);
245 }
247 return NS_OK;
248 }
249 }
251 // nsNavHistory::QueryStringToQueries
252 //
253 // From C++ places code, you should use QueryStringToQueryArray, this is
254 // the harder-to-use XPCOM version.
256 NS_IMETHODIMP
257 nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
258 nsINavHistoryQuery*** aQueries,
259 uint32_t* aResultCount,
260 nsINavHistoryQueryOptions** aOptions)
261 {
262 NS_ENSURE_ARG_POINTER(aQueries);
263 NS_ENSURE_ARG_POINTER(aResultCount);
264 NS_ENSURE_ARG_POINTER(aOptions);
266 *aQueries = nullptr;
267 *aResultCount = 0;
268 nsCOMPtr<nsNavHistoryQueryOptions> options;
269 nsCOMArray<nsNavHistoryQuery> queries;
270 nsresult rv = QueryStringToQueryArray(aQueryString, &queries,
271 getter_AddRefs(options));
272 NS_ENSURE_SUCCESS(rv, rv);
274 *aResultCount = queries.Count();
275 if (queries.Count() > 0) {
276 // convert COM array to raw
277 *aQueries = static_cast<nsINavHistoryQuery**>
278 (nsMemory::Alloc(sizeof(nsINavHistoryQuery*) * queries.Count()));
279 NS_ENSURE_TRUE(*aQueries, NS_ERROR_OUT_OF_MEMORY);
280 for (int32_t i = 0; i < queries.Count(); i ++) {
281 (*aQueries)[i] = queries[i];
282 NS_ADDREF((*aQueries)[i]);
283 }
284 }
285 NS_ADDREF(*aOptions = options);
286 return NS_OK;
287 }
290 // nsNavHistory::QueryStringToQueryArray
291 //
292 // An internal version of QueryStringToQueries that fills a COM array for
293 // ease-of-use.
295 nsresult
296 nsNavHistory::QueryStringToQueryArray(const nsACString& aQueryString,
297 nsCOMArray<nsNavHistoryQuery>* aQueries,
298 nsNavHistoryQueryOptions** aOptions)
299 {
300 nsresult rv;
301 aQueries->Clear();
302 *aOptions = nullptr;
304 nsRefPtr<nsNavHistoryQueryOptions> options(new nsNavHistoryQueryOptions());
305 if (! options)
306 return NS_ERROR_OUT_OF_MEMORY;
308 nsTArray<QueryKeyValuePair> tokens;
309 rv = TokenizeQueryString(aQueryString, &tokens);
310 NS_ENSURE_SUCCESS(rv, rv);
312 rv = TokensToQueries(tokens, aQueries, options);
313 if (NS_FAILED(rv)) {
314 NS_WARNING("Unable to parse the query string: ");
315 NS_WARNING(PromiseFlatCString(aQueryString).get());
316 return rv;
317 }
319 NS_ADDREF(*aOptions = options);
320 return NS_OK;
321 }
324 // nsNavHistory::QueriesToQueryString
326 NS_IMETHODIMP
327 nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
328 uint32_t aQueryCount,
329 nsINavHistoryQueryOptions* aOptions,
330 nsACString& aQueryString)
331 {
332 NS_ENSURE_ARG(aQueries);
333 NS_ENSURE_ARG(aOptions);
335 nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
336 NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG);
338 nsAutoCString queryString;
339 for (uint32_t queryIndex = 0; queryIndex < aQueryCount; queryIndex ++) {
340 nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface(aQueries[queryIndex]);
341 if (queryIndex > 0) {
342 AppendAmpersandIfNonempty(queryString);
343 queryString += NS_LITERAL_CSTRING(QUERYKEY_SEPARATOR);
344 }
346 bool hasIt;
348 // begin time
349 query->GetHasBeginTime(&hasIt);
350 if (hasIt) {
351 AppendInt64KeyValueIfNonzero(queryString,
352 NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME),
353 query, &nsINavHistoryQuery::GetBeginTime);
354 AppendUint32KeyValueIfNonzero(queryString,
355 NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME_REFERENCE),
356 query, &nsINavHistoryQuery::GetBeginTimeReference);
357 }
359 // end time
360 query->GetHasEndTime(&hasIt);
361 if (hasIt) {
362 AppendInt64KeyValueIfNonzero(queryString,
363 NS_LITERAL_CSTRING(QUERYKEY_END_TIME),
364 query, &nsINavHistoryQuery::GetEndTime);
365 AppendUint32KeyValueIfNonzero(queryString,
366 NS_LITERAL_CSTRING(QUERYKEY_END_TIME_REFERENCE),
367 query, &nsINavHistoryQuery::GetEndTimeReference);
368 }
370 // search terms
371 query->GetHasSearchTerms(&hasIt);
372 if (hasIt) {
373 nsAutoString searchTerms;
374 query->GetSearchTerms(searchTerms);
375 nsCString escapedTerms;
376 if (! NS_Escape(NS_ConvertUTF16toUTF8(searchTerms), escapedTerms,
377 url_XAlphas))
378 return NS_ERROR_OUT_OF_MEMORY;
380 AppendAmpersandIfNonempty(queryString);
381 queryString += NS_LITERAL_CSTRING(QUERYKEY_SEARCH_TERMS "=");
382 queryString += escapedTerms;
383 }
385 // min and max visits
386 int32_t minVisits;
387 if (NS_SUCCEEDED(query->GetMinVisits(&minVisits)) && minVisits >= 0) {
388 AppendAmpersandIfNonempty(queryString);
389 queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_MIN_VISITS "="));
390 AppendInt32(queryString, minVisits);
391 }
393 int32_t maxVisits;
394 if (NS_SUCCEEDED(query->GetMaxVisits(&maxVisits)) && maxVisits >= 0) {
395 AppendAmpersandIfNonempty(queryString);
396 queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_MAX_VISITS "="));
397 AppendInt32(queryString, maxVisits);
398 }
400 // only bookmarked
401 AppendBoolKeyValueIfTrue(queryString,
402 NS_LITERAL_CSTRING(QUERYKEY_ONLY_BOOKMARKED),
403 query, &nsINavHistoryQuery::GetOnlyBookmarked);
405 // domain (+ is host), only call if hasDomain, which means non-IsVoid
406 // this means we may get an empty string for the domain in the result,
407 // which is valid
408 query->GetHasDomain(&hasIt);
409 if (hasIt) {
410 AppendBoolKeyValueIfTrue(queryString,
411 NS_LITERAL_CSTRING(QUERYKEY_DOMAIN_IS_HOST),
412 query, &nsINavHistoryQuery::GetDomainIsHost);
413 nsAutoCString domain;
414 nsresult rv = query->GetDomain(domain);
415 NS_ENSURE_SUCCESS(rv, rv);
416 nsCString escapedDomain;
417 bool success = NS_Escape(domain, escapedDomain, url_XAlphas);
418 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
420 AppendAmpersandIfNonempty(queryString);
421 queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_DOMAIN "="));
422 queryString.Append(escapedDomain);
423 }
425 // uri
426 query->GetHasUri(&hasIt);
427 if (hasIt) {
428 AppendBoolKeyValueIfTrue(aQueryString,
429 NS_LITERAL_CSTRING(QUERYKEY_URIISPREFIX),
430 query, &nsINavHistoryQuery::GetUriIsPrefix);
431 nsCOMPtr<nsIURI> uri;
432 query->GetUri(getter_AddRefs(uri));
433 NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); // hasURI should tell is if invalid
434 nsAutoCString uriSpec;
435 nsresult rv = uri->GetSpec(uriSpec);
436 NS_ENSURE_SUCCESS(rv, rv);
437 nsAutoCString escaped;
438 bool success = NS_Escape(uriSpec, escaped, url_XAlphas);
439 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
441 AppendAmpersandIfNonempty(queryString);
442 queryString.Append(NS_LITERAL_CSTRING(QUERYKEY_URI "="));
443 queryString.Append(escaped);
444 }
446 // annotation
447 query->GetHasAnnotation(&hasIt);
448 if (hasIt) {
449 AppendAmpersandIfNonempty(queryString);
450 bool annotationIsNot;
451 query->GetAnnotationIsNot(&annotationIsNot);
452 if (annotationIsNot)
453 queryString.AppendLiteral(QUERYKEY_NOTANNOTATION "=");
454 else
455 queryString.AppendLiteral(QUERYKEY_ANNOTATION "=");
456 nsAutoCString annot;
457 query->GetAnnotation(annot);
458 nsAutoCString escaped;
459 bool success = NS_Escape(annot, escaped, url_XAlphas);
460 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
461 queryString.Append(escaped);
462 }
464 // folders
465 int64_t *folders = nullptr;
466 uint32_t folderCount = 0;
467 query->GetFolders(&folderCount, &folders);
468 for (uint32_t i = 0; i < folderCount; ++i) {
469 AppendAmpersandIfNonempty(queryString);
470 queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
471 nsresult rv = PlacesFolderConversion::AppendFolder(queryString, folders[i]);
472 NS_ENSURE_SUCCESS(rv, rv);
473 }
474 nsMemory::Free(folders);
476 // tags
477 const nsTArray<nsString> &tags = query->Tags();
478 for (uint32_t i = 0; i < tags.Length(); ++i) {
479 nsAutoCString escapedTag;
480 if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas))
481 return NS_ERROR_OUT_OF_MEMORY;
483 AppendAmpersandIfNonempty(queryString);
484 queryString += NS_LITERAL_CSTRING(QUERYKEY_TAG "=");
485 queryString += escapedTag;
486 }
487 AppendBoolKeyValueIfTrue(queryString,
488 NS_LITERAL_CSTRING(QUERYKEY_NOTTAGS),
489 query,
490 &nsINavHistoryQuery::GetTagsAreNot);
492 // transitions
493 const nsTArray<uint32_t>& transitions = query->Transitions();
494 for (uint32_t i = 0; i < transitions.Length(); ++i) {
495 AppendAmpersandIfNonempty(queryString);
496 queryString += NS_LITERAL_CSTRING(QUERYKEY_TRANSITION "=");
497 AppendInt64(queryString, transitions[i]);
498 }
499 }
501 // sorting
502 if (options->SortingMode() != nsINavHistoryQueryOptions::SORT_BY_NONE) {
503 AppendAmpersandIfNonempty(queryString);
504 queryString += NS_LITERAL_CSTRING(QUERYKEY_SORT "=");
505 AppendInt16(queryString, options->SortingMode());
506 if (options->SortingMode() == nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_DESCENDING ||
507 options->SortingMode() == nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_ASCENDING) {
508 // sortingAnnotation
509 nsAutoCString sortingAnnotation;
510 if (NS_SUCCEEDED(options->GetSortingAnnotation(sortingAnnotation))) {
511 nsCString escaped;
512 if (!NS_Escape(sortingAnnotation, escaped, url_XAlphas))
513 return NS_ERROR_OUT_OF_MEMORY;
514 AppendAmpersandIfNonempty(queryString);
515 queryString += NS_LITERAL_CSTRING(QUERYKEY_SORTING_ANNOTATION "=");
516 queryString.Append(escaped);
517 }
518 }
519 }
521 // result type
522 if (options->ResultType() != nsINavHistoryQueryOptions::RESULTS_AS_URI) {
523 AppendAmpersandIfNonempty(queryString);
524 queryString += NS_LITERAL_CSTRING(QUERYKEY_RESULT_TYPE "=");
525 AppendInt16(queryString, options->ResultType());
526 }
528 // exclude items
529 if (options->ExcludeItems()) {
530 AppendAmpersandIfNonempty(queryString);
531 queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_ITEMS "=1");
532 }
534 // exclude queries
535 if (options->ExcludeQueries()) {
536 AppendAmpersandIfNonempty(queryString);
537 queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_QUERIES "=1");
538 }
540 // exclude read only folders
541 if (options->ExcludeReadOnlyFolders()) {
542 AppendAmpersandIfNonempty(queryString);
543 queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "=1");
544 }
546 // expand queries
547 if (!options->ExpandQueries()) {
548 AppendAmpersandIfNonempty(queryString);
549 queryString += NS_LITERAL_CSTRING(QUERYKEY_EXPAND_QUERIES "=0");
550 }
552 // include hidden
553 if (options->IncludeHidden()) {
554 AppendAmpersandIfNonempty(queryString);
555 queryString += NS_LITERAL_CSTRING(QUERYKEY_INCLUDE_HIDDEN "=1");
556 }
558 // max results
559 if (options->MaxResults()) {
560 AppendAmpersandIfNonempty(queryString);
561 queryString += NS_LITERAL_CSTRING(QUERYKEY_MAX_RESULTS "=");
562 AppendInt32(queryString, options->MaxResults());
563 }
565 // queryType
566 if (options->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY) {
567 AppendAmpersandIfNonempty(queryString);
568 queryString += NS_LITERAL_CSTRING(QUERYKEY_QUERY_TYPE "=");
569 AppendInt16(queryString, options->QueryType());
570 }
572 // async enabled
573 if (options->AsyncEnabled()) {
574 AppendAmpersandIfNonempty(queryString);
575 queryString += NS_LITERAL_CSTRING(QUERYKEY_ASYNC_ENABLED "=1");
576 }
578 aQueryString.Assign(NS_LITERAL_CSTRING("place:") + queryString);
579 return NS_OK;
580 }
583 // TokenizeQueryString
585 nsresult
586 TokenizeQueryString(const nsACString& aQuery,
587 nsTArray<QueryKeyValuePair>* aTokens)
588 {
589 // Strip off the "place:" prefix
590 const uint32_t prefixlen = 6; // = strlen("place:");
591 nsCString query;
592 if (aQuery.Length() >= prefixlen &&
593 Substring(aQuery, 0, prefixlen).EqualsLiteral("place:"))
594 query = Substring(aQuery, prefixlen);
595 else
596 query = aQuery;
598 int32_t keyFirstIndex = 0;
599 int32_t equalsIndex = 0;
600 for (uint32_t i = 0; i < query.Length(); i ++) {
601 if (query[i] == '&') {
602 // new clause, save last one
603 if (i - keyFirstIndex > 1) {
604 if (! aTokens->AppendElement(QueryKeyValuePair(query, keyFirstIndex,
605 equalsIndex, i)))
606 return NS_ERROR_OUT_OF_MEMORY;
607 }
608 keyFirstIndex = equalsIndex = i + 1;
609 } else if (query[i] == '=') {
610 equalsIndex = i;
611 }
612 }
614 // handle last pair, if any
615 if (query.Length() - keyFirstIndex > 1) {
616 if (! aTokens->AppendElement(QueryKeyValuePair(query, keyFirstIndex,
617 equalsIndex, query.Length())))
618 return NS_ERROR_OUT_OF_MEMORY;
619 }
620 return NS_OK;
621 }
623 // nsNavHistory::TokensToQueries
625 nsresult
626 nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
627 nsCOMArray<nsNavHistoryQuery>* aQueries,
628 nsNavHistoryQueryOptions* aOptions)
629 {
630 nsresult rv;
632 nsCOMPtr<nsNavHistoryQuery> query(new nsNavHistoryQuery());
633 if (! query)
634 return NS_ERROR_OUT_OF_MEMORY;
635 if (! aQueries->AppendObject(query))
636 return NS_ERROR_OUT_OF_MEMORY;
638 if (aTokens.Length() == 0)
639 return NS_OK; // nothing to do
641 nsTArray<int64_t> folders;
642 nsTArray<nsString> tags;
643 nsTArray<uint32_t> transitions;
644 for (uint32_t i = 0; i < aTokens.Length(); i ++) {
645 const QueryKeyValuePair& kvp = aTokens[i];
647 // begin time
648 if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME)) {
649 SetQueryKeyInt64(kvp.value, query, &nsINavHistoryQuery::SetBeginTime);
651 // begin time reference
652 } else if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME_REFERENCE)) {
653 SetQueryKeyUint32(kvp.value, query, &nsINavHistoryQuery::SetBeginTimeReference);
655 // end time
656 } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME)) {
657 SetQueryKeyInt64(kvp.value, query, &nsINavHistoryQuery::SetEndTime);
659 // end time reference
660 } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME_REFERENCE)) {
661 SetQueryKeyUint32(kvp.value, query, &nsINavHistoryQuery::SetEndTimeReference);
663 // search terms
664 } else if (kvp.key.EqualsLiteral(QUERYKEY_SEARCH_TERMS)) {
665 nsCString unescapedTerms = kvp.value;
666 NS_UnescapeURL(unescapedTerms); // modifies input
667 rv = query->SetSearchTerms(NS_ConvertUTF8toUTF16(unescapedTerms));
668 NS_ENSURE_SUCCESS(rv, rv);
670 // min visits
671 } else if (kvp.key.EqualsLiteral(QUERYKEY_MIN_VISITS)) {
672 int32_t visits = kvp.value.ToInteger(&rv);
673 if (NS_SUCCEEDED(rv))
674 query->SetMinVisits(visits);
675 else
676 NS_WARNING("Bad number for minVisits in query");
678 // max visits
679 } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_VISITS)) {
680 int32_t visits = kvp.value.ToInteger(&rv);
681 if (NS_SUCCEEDED(rv))
682 query->SetMaxVisits(visits);
683 else
684 NS_WARNING("Bad number for maxVisits in query");
686 // onlyBookmarked flag
687 } else if (kvp.key.EqualsLiteral(QUERYKEY_ONLY_BOOKMARKED)) {
688 SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetOnlyBookmarked);
690 // domainIsHost flag
691 } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN_IS_HOST)) {
692 SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetDomainIsHost);
694 // domain string
695 } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN)) {
696 nsAutoCString unescapedDomain(kvp.value);
697 NS_UnescapeURL(unescapedDomain); // modifies input
698 rv = query->SetDomain(unescapedDomain);
699 NS_ENSURE_SUCCESS(rv, rv);
701 // folders
702 } else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDER)) {
703 int64_t folder;
704 if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) {
705 NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
706 } else {
707 folder = PlacesFolderConversion::DecodeFolder(kvp.value);
708 if (folder != -1)
709 NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
710 else
711 NS_WARNING("folders value in query is invalid, ignoring");
712 }
714 // uri
715 } else if (kvp.key.EqualsLiteral(QUERYKEY_URI)) {
716 nsAutoCString unescapedUri(kvp.value);
717 NS_UnescapeURL(unescapedUri); // modifies input
718 nsCOMPtr<nsIURI> uri;
719 nsresult rv = NS_NewURI(getter_AddRefs(uri), unescapedUri);
720 if (NS_FAILED(rv)) {
721 NS_WARNING("Unable to parse URI");
722 }
723 rv = query->SetUri(uri);
724 NS_ENSURE_SUCCESS(rv, rv);
726 // URI is prefix
727 } else if (kvp.key.EqualsLiteral(QUERYKEY_URIISPREFIX)) {
728 SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetUriIsPrefix);
730 // not annotation
731 } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTANNOTATION)) {
732 nsAutoCString unescaped(kvp.value);
733 NS_UnescapeURL(unescaped); // modifies input
734 query->SetAnnotationIsNot(true);
735 query->SetAnnotation(unescaped);
737 // annotation
738 } else if (kvp.key.EqualsLiteral(QUERYKEY_ANNOTATION)) {
739 nsAutoCString unescaped(kvp.value);
740 NS_UnescapeURL(unescaped); // modifies input
741 query->SetAnnotationIsNot(false);
742 query->SetAnnotation(unescaped);
744 // tag
745 } else if (kvp.key.EqualsLiteral(QUERYKEY_TAG)) {
746 nsAutoCString unescaped(kvp.value);
747 NS_UnescapeURL(unescaped); // modifies input
748 NS_ConvertUTF8toUTF16 tag(unescaped);
749 if (!tags.Contains(tag)) {
750 NS_ENSURE_TRUE(tags.AppendElement(tag), NS_ERROR_OUT_OF_MEMORY);
751 }
753 // not tags
754 } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTTAGS)) {
755 SetQueryKeyBool(kvp.value, query, &nsINavHistoryQuery::SetTagsAreNot);
757 // transition
758 } else if (kvp.key.EqualsLiteral(QUERYKEY_TRANSITION)) {
759 uint32_t transition = kvp.value.ToInteger(&rv);
760 if (NS_SUCCEEDED(rv)) {
761 if (!transitions.Contains(transition))
762 NS_ENSURE_TRUE(transitions.AppendElement(transition),
763 NS_ERROR_OUT_OF_MEMORY);
764 }
765 else {
766 NS_WARNING("Invalid Int32 transition value.");
767 }
769 // new query component
770 } else if (kvp.key.EqualsLiteral(QUERYKEY_SEPARATOR)) {
772 if (folders.Length() != 0) {
773 query->SetFolders(folders.Elements(), folders.Length());
774 folders.Clear();
775 }
777 if (tags.Length() > 0) {
778 rv = query->SetTags(tags);
779 NS_ENSURE_SUCCESS(rv, rv);
780 tags.Clear();
781 }
783 if (transitions.Length() > 0) {
784 rv = query->SetTransitions(transitions);
785 NS_ENSURE_SUCCESS(rv, rv);
786 transitions.Clear();
787 }
789 query = new nsNavHistoryQuery();
790 if (! query)
791 return NS_ERROR_OUT_OF_MEMORY;
792 if (! aQueries->AppendObject(query))
793 return NS_ERROR_OUT_OF_MEMORY;
795 // sorting mode
796 } else if (kvp.key.EqualsLiteral(QUERYKEY_SORT)) {
797 SetOptionsKeyUint16(kvp.value, aOptions,
798 &nsINavHistoryQueryOptions::SetSortingMode);
799 // sorting annotation
800 } else if (kvp.key.EqualsLiteral(QUERYKEY_SORTING_ANNOTATION)) {
801 nsCString sortingAnnotation = kvp.value;
802 NS_UnescapeURL(sortingAnnotation);
803 rv = aOptions->SetSortingAnnotation(sortingAnnotation);
804 NS_ENSURE_SUCCESS(rv, rv);
805 // result type
806 } else if (kvp.key.EqualsLiteral(QUERYKEY_RESULT_TYPE)) {
807 SetOptionsKeyUint16(kvp.value, aOptions,
808 &nsINavHistoryQueryOptions::SetResultType);
810 // exclude items
811 } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_ITEMS)) {
812 SetOptionsKeyBool(kvp.value, aOptions,
813 &nsINavHistoryQueryOptions::SetExcludeItems);
815 // exclude queries
816 } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_QUERIES)) {
817 SetOptionsKeyBool(kvp.value, aOptions,
818 &nsINavHistoryQueryOptions::SetExcludeQueries);
820 // exclude read only folders
821 } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS)) {
822 SetOptionsKeyBool(kvp.value, aOptions,
823 &nsINavHistoryQueryOptions::SetExcludeReadOnlyFolders);
825 // expand queries
826 } else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) {
827 SetOptionsKeyBool(kvp.value, aOptions,
828 &nsINavHistoryQueryOptions::SetExpandQueries);
829 // include hidden
830 } else if (kvp.key.EqualsLiteral(QUERYKEY_INCLUDE_HIDDEN)) {
831 SetOptionsKeyBool(kvp.value, aOptions,
832 &nsINavHistoryQueryOptions::SetIncludeHidden);
833 // max results
834 } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) {
835 SetOptionsKeyUint32(kvp.value, aOptions,
836 &nsINavHistoryQueryOptions::SetMaxResults);
837 // query type
838 } else if (kvp.key.EqualsLiteral(QUERYKEY_QUERY_TYPE)) {
839 SetOptionsKeyUint16(kvp.value, aOptions,
840 &nsINavHistoryQueryOptions::SetQueryType);
841 // async enabled
842 } else if (kvp.key.EqualsLiteral(QUERYKEY_ASYNC_ENABLED)) {
843 SetOptionsKeyBool(kvp.value, aOptions,
844 &nsINavHistoryQueryOptions::SetAsyncEnabled);
845 // unknown key
846 } else {
847 NS_WARNING("TokensToQueries(), ignoring unknown key: ");
848 NS_WARNING(kvp.key.get());
849 }
850 }
852 if (folders.Length() != 0)
853 query->SetFolders(folders.Elements(), folders.Length());
855 if (tags.Length() > 0) {
856 rv = query->SetTags(tags);
857 NS_ENSURE_SUCCESS(rv, rv);
858 }
860 if (transitions.Length() > 0) {
861 rv = query->SetTransitions(transitions);
862 NS_ENSURE_SUCCESS(rv, rv);
863 }
865 return NS_OK;
866 }
869 // ParseQueryBooleanString
870 //
871 // Converts a 0/1 or true/false string into a bool
873 nsresult
874 ParseQueryBooleanString(const nsCString& aString, bool* aValue)
875 {
876 if (aString.EqualsLiteral("1") || aString.EqualsLiteral("true")) {
877 *aValue = true;
878 return NS_OK;
879 } else if (aString.EqualsLiteral("0") || aString.EqualsLiteral("false")) {
880 *aValue = false;
881 return NS_OK;
882 }
883 return NS_ERROR_INVALID_ARG;
884 }
887 // nsINavHistoryQuery **********************************************************
889 NS_IMPL_ISUPPORTS(nsNavHistoryQuery, nsNavHistoryQuery, nsINavHistoryQuery)
891 // nsINavHistoryQuery::nsNavHistoryQuery
892 //
893 // This must initialize the object such that the default values will cause
894 // all history to be returned if this query is used. Then the caller can
895 // just set the things it's interested in.
897 nsNavHistoryQuery::nsNavHistoryQuery()
898 : mMinVisits(-1), mMaxVisits(-1), mBeginTime(0),
899 mBeginTimeReference(TIME_RELATIVE_EPOCH),
900 mEndTime(0), mEndTimeReference(TIME_RELATIVE_EPOCH),
901 mOnlyBookmarked(false),
902 mDomainIsHost(false), mUriIsPrefix(false),
903 mAnnotationIsNot(false),
904 mTagsAreNot(false)
905 {
906 // differentiate not set (IsVoid) from empty string (local files)
907 mDomain.SetIsVoid(true);
908 }
910 /* attribute PRTime beginTime; */
911 NS_IMETHODIMP nsNavHistoryQuery::GetBeginTime(PRTime *aBeginTime)
912 {
913 *aBeginTime = mBeginTime;
914 return NS_OK;
915 }
916 NS_IMETHODIMP nsNavHistoryQuery::SetBeginTime(PRTime aBeginTime)
917 {
918 mBeginTime = aBeginTime;
919 return NS_OK;
920 }
922 /* attribute long beginTimeReference; */
923 NS_IMETHODIMP nsNavHistoryQuery::GetBeginTimeReference(uint32_t* _retval)
924 {
925 *_retval = mBeginTimeReference;
926 return NS_OK;
927 }
928 NS_IMETHODIMP nsNavHistoryQuery::SetBeginTimeReference(uint32_t aReference)
929 {
930 if (aReference > TIME_RELATIVE_NOW)
931 return NS_ERROR_INVALID_ARG;
932 mBeginTimeReference = aReference;
933 return NS_OK;
934 }
936 /* readonly attribute boolean hasBeginTime; */
937 NS_IMETHODIMP nsNavHistoryQuery::GetHasBeginTime(bool* _retval)
938 {
939 *_retval = ! (mBeginTimeReference == TIME_RELATIVE_EPOCH && mBeginTime == 0);
940 return NS_OK;
941 }
943 /* readonly attribute PRTime absoluteBeginTime; */
944 NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteBeginTime(PRTime* _retval)
945 {
946 *_retval = nsNavHistory::NormalizeTime(mBeginTimeReference, mBeginTime);
947 return NS_OK;
948 }
950 /* attribute PRTime endTime; */
951 NS_IMETHODIMP nsNavHistoryQuery::GetEndTime(PRTime *aEndTime)
952 {
953 *aEndTime = mEndTime;
954 return NS_OK;
955 }
956 NS_IMETHODIMP nsNavHistoryQuery::SetEndTime(PRTime aEndTime)
957 {
958 mEndTime = aEndTime;
959 return NS_OK;
960 }
962 /* attribute long endTimeReference; */
963 NS_IMETHODIMP nsNavHistoryQuery::GetEndTimeReference(uint32_t* _retval)
964 {
965 *_retval = mEndTimeReference;
966 return NS_OK;
967 }
968 NS_IMETHODIMP nsNavHistoryQuery::SetEndTimeReference(uint32_t aReference)
969 {
970 if (aReference > TIME_RELATIVE_NOW)
971 return NS_ERROR_INVALID_ARG;
972 mEndTimeReference = aReference;
973 return NS_OK;
974 }
976 /* readonly attribute boolean hasEndTime; */
977 NS_IMETHODIMP nsNavHistoryQuery::GetHasEndTime(bool* _retval)
978 {
979 *_retval = ! (mEndTimeReference == TIME_RELATIVE_EPOCH && mEndTime == 0);
980 return NS_OK;
981 }
983 /* readonly attribute PRTime absoluteEndTime; */
984 NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteEndTime(PRTime* _retval)
985 {
986 *_retval = nsNavHistory::NormalizeTime(mEndTimeReference, mEndTime);
987 return NS_OK;
988 }
990 /* attribute string searchTerms; */
991 NS_IMETHODIMP nsNavHistoryQuery::GetSearchTerms(nsAString& aSearchTerms)
992 {
993 aSearchTerms = mSearchTerms;
994 return NS_OK;
995 }
996 NS_IMETHODIMP nsNavHistoryQuery::SetSearchTerms(const nsAString& aSearchTerms)
997 {
998 mSearchTerms = aSearchTerms;
999 return NS_OK;
1000 }
1001 NS_IMETHODIMP nsNavHistoryQuery::GetHasSearchTerms(bool* _retval)
1002 {
1003 *_retval = (! mSearchTerms.IsEmpty());
1004 return NS_OK;
1005 }
1007 /* attribute int32_t minVisits; */
1008 NS_IMETHODIMP nsNavHistoryQuery::GetMinVisits(int32_t* _retval)
1009 {
1010 NS_ENSURE_ARG_POINTER(_retval);
1011 *_retval = mMinVisits;
1012 return NS_OK;
1013 }
1014 NS_IMETHODIMP nsNavHistoryQuery::SetMinVisits(int32_t aVisits)
1015 {
1016 mMinVisits = aVisits;
1017 return NS_OK;
1018 }
1020 /* attribute PRint32 maxVisits; */
1021 NS_IMETHODIMP nsNavHistoryQuery::GetMaxVisits(int32_t* _retval)
1022 {
1023 NS_ENSURE_ARG_POINTER(_retval);
1024 *_retval = mMaxVisits;
1025 return NS_OK;
1026 }
1027 NS_IMETHODIMP nsNavHistoryQuery::SetMaxVisits(int32_t aVisits)
1028 {
1029 mMaxVisits = aVisits;
1030 return NS_OK;
1031 }
1033 /* attribute boolean onlyBookmarked; */
1034 NS_IMETHODIMP nsNavHistoryQuery::GetOnlyBookmarked(bool *aOnlyBookmarked)
1035 {
1036 *aOnlyBookmarked = mOnlyBookmarked;
1037 return NS_OK;
1038 }
1039 NS_IMETHODIMP nsNavHistoryQuery::SetOnlyBookmarked(bool aOnlyBookmarked)
1040 {
1041 mOnlyBookmarked = aOnlyBookmarked;
1042 return NS_OK;
1043 }
1045 /* attribute boolean domainIsHost; */
1046 NS_IMETHODIMP nsNavHistoryQuery::GetDomainIsHost(bool *aDomainIsHost)
1047 {
1048 *aDomainIsHost = mDomainIsHost;
1049 return NS_OK;
1050 }
1051 NS_IMETHODIMP nsNavHistoryQuery::SetDomainIsHost(bool aDomainIsHost)
1052 {
1053 mDomainIsHost = aDomainIsHost;
1054 return NS_OK;
1055 }
1057 /* attribute AUTF8String domain; */
1058 NS_IMETHODIMP nsNavHistoryQuery::GetDomain(nsACString& aDomain)
1059 {
1060 aDomain = mDomain;
1061 return NS_OK;
1062 }
1063 NS_IMETHODIMP nsNavHistoryQuery::SetDomain(const nsACString& aDomain)
1064 {
1065 mDomain = aDomain;
1066 return NS_OK;
1067 }
1068 NS_IMETHODIMP nsNavHistoryQuery::GetHasDomain(bool* _retval)
1069 {
1070 // note that empty but not void is still a valid query (local files)
1071 *_retval = (! mDomain.IsVoid());
1072 return NS_OK;
1073 }
1075 /* attribute boolean uriIsPrefix; */
1076 NS_IMETHODIMP nsNavHistoryQuery::GetUriIsPrefix(bool* aIsPrefix)
1077 {
1078 *aIsPrefix = mUriIsPrefix;
1079 return NS_OK;
1080 }
1081 NS_IMETHODIMP nsNavHistoryQuery::SetUriIsPrefix(bool aIsPrefix)
1082 {
1083 mUriIsPrefix = aIsPrefix;
1084 return NS_OK;
1085 }
1087 /* attribute nsIURI uri; */
1088 NS_IMETHODIMP nsNavHistoryQuery::GetUri(nsIURI** aUri)
1089 {
1090 NS_IF_ADDREF(*aUri = mUri);
1091 return NS_OK;
1092 }
1093 NS_IMETHODIMP nsNavHistoryQuery::SetUri(nsIURI* aUri)
1094 {
1095 mUri = aUri;
1096 return NS_OK;
1097 }
1098 NS_IMETHODIMP nsNavHistoryQuery::GetHasUri(bool* aHasUri)
1099 {
1100 *aHasUri = (mUri != nullptr);
1101 return NS_OK;
1102 }
1104 /* attribute boolean annotationIsNot; */
1105 NS_IMETHODIMP nsNavHistoryQuery::GetAnnotationIsNot(bool* aIsNot)
1106 {
1107 *aIsNot = mAnnotationIsNot;
1108 return NS_OK;
1109 }
1110 NS_IMETHODIMP nsNavHistoryQuery::SetAnnotationIsNot(bool aIsNot)
1111 {
1112 mAnnotationIsNot = aIsNot;
1113 return NS_OK;
1114 }
1116 /* attribute AUTF8String annotation; */
1117 NS_IMETHODIMP nsNavHistoryQuery::GetAnnotation(nsACString& aAnnotation)
1118 {
1119 aAnnotation = mAnnotation;
1120 return NS_OK;
1121 }
1122 NS_IMETHODIMP nsNavHistoryQuery::SetAnnotation(const nsACString& aAnnotation)
1123 {
1124 mAnnotation = aAnnotation;
1125 return NS_OK;
1126 }
1127 NS_IMETHODIMP nsNavHistoryQuery::GetHasAnnotation(bool* aHasIt)
1128 {
1129 *aHasIt = ! mAnnotation.IsEmpty();
1130 return NS_OK;
1131 }
1133 /* attribute nsIVariant tags; */
1134 NS_IMETHODIMP nsNavHistoryQuery::GetTags(nsIVariant **aTags)
1135 {
1136 NS_ENSURE_ARG_POINTER(aTags);
1138 nsresult rv;
1139 nsCOMPtr<nsIWritableVariant> out = do_CreateInstance(NS_VARIANT_CONTRACTID,
1140 &rv);
1141 NS_ENSURE_SUCCESS(rv, rv);
1143 uint32_t arrayLen = mTags.Length();
1145 if (arrayLen == 0)
1146 rv = out->SetAsEmptyArray();
1147 else {
1148 // Note: The resulting nsIVariant dupes both the array and its elements.
1149 const char16_t **array = reinterpret_cast<const char16_t **>
1150 (NS_Alloc(arrayLen * sizeof(char16_t *)));
1151 NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
1153 for (uint32_t i = 0; i < arrayLen; ++i) {
1154 array[i] = mTags[i].get();
1155 }
1157 rv = out->SetAsArray(nsIDataType::VTYPE_WCHAR_STR,
1158 nullptr,
1159 arrayLen,
1160 reinterpret_cast<void *>(array));
1161 NS_Free(array);
1162 }
1163 NS_ENSURE_SUCCESS(rv, rv);
1165 NS_ADDREF(*aTags = out);
1166 return NS_OK;
1167 }
1169 NS_IMETHODIMP nsNavHistoryQuery::SetTags(nsIVariant *aTags)
1170 {
1171 NS_ENSURE_ARG(aTags);
1173 uint16_t dataType;
1174 aTags->GetDataType(&dataType);
1176 // Caller passed in empty array. Easy -- clear our mTags array and return.
1177 if (dataType == nsIDataType::VTYPE_EMPTY_ARRAY) {
1178 mTags.Clear();
1179 return NS_OK;
1180 }
1182 // Before we go any further, make sure caller passed in an array.
1183 NS_ENSURE_TRUE(dataType == nsIDataType::VTYPE_ARRAY, NS_ERROR_ILLEGAL_VALUE);
1185 uint16_t eltType;
1186 nsIID eltIID;
1187 uint32_t arrayLen;
1188 void *array;
1190 // Convert the nsIVariant to an array. We own the resulting buffer and its
1191 // elements.
1192 nsresult rv = aTags->GetAsArray(&eltType, &eltIID, &arrayLen, &array);
1193 NS_ENSURE_SUCCESS(rv, rv);
1195 // If element type is not wstring, thanks a lot. Your memory die now.
1196 if (eltType != nsIDataType::VTYPE_WCHAR_STR) {
1197 switch (eltType) {
1198 case nsIDataType::VTYPE_ID:
1199 case nsIDataType::VTYPE_CHAR_STR:
1200 {
1201 char **charArray = reinterpret_cast<char **>(array);
1202 for (uint32_t i = 0; i < arrayLen; ++i) {
1203 if (charArray[i])
1204 NS_Free(charArray[i]);
1205 }
1206 }
1207 break;
1208 case nsIDataType::VTYPE_INTERFACE:
1209 case nsIDataType::VTYPE_INTERFACE_IS:
1210 {
1211 nsISupports **supportsArray = reinterpret_cast<nsISupports **>(array);
1212 for (uint32_t i = 0; i < arrayLen; ++i) {
1213 NS_IF_RELEASE(supportsArray[i]);
1214 }
1215 }
1216 break;
1217 // The other types are primitives that do not need to be freed.
1218 }
1219 NS_Free(array);
1220 return NS_ERROR_ILLEGAL_VALUE;
1221 }
1223 char16_t **tags = reinterpret_cast<char16_t **>(array);
1224 mTags.Clear();
1226 // Finally, add each passed-in tag to our mTags array and then sort it.
1227 for (uint32_t i = 0; i < arrayLen; ++i) {
1229 // Don't allow nulls.
1230 if (!tags[i]) {
1231 NS_Free(tags);
1232 return NS_ERROR_ILLEGAL_VALUE;
1233 }
1235 nsDependentString tag(tags[i]);
1237 // Don't store duplicate tags. This isn't just to save memory or to be
1238 // fancy; the SQL that's built from the tags relies on no dupes.
1239 if (!mTags.Contains(tag)) {
1240 if (!mTags.AppendElement(tag)) {
1241 NS_Free(tags[i]);
1242 NS_Free(tags);
1243 return NS_ERROR_OUT_OF_MEMORY;
1244 }
1245 }
1246 NS_Free(tags[i]);
1247 }
1248 NS_Free(tags);
1250 mTags.Sort();
1252 return NS_OK;
1253 }
1255 /* attribute boolean tagsAreNot; */
1256 NS_IMETHODIMP nsNavHistoryQuery::GetTagsAreNot(bool *aTagsAreNot)
1257 {
1258 NS_ENSURE_ARG_POINTER(aTagsAreNot);
1259 *aTagsAreNot = mTagsAreNot;
1260 return NS_OK;
1261 }
1263 NS_IMETHODIMP nsNavHistoryQuery::SetTagsAreNot(bool aTagsAreNot)
1264 {
1265 mTagsAreNot = aTagsAreNot;
1266 return NS_OK;
1267 }
1269 NS_IMETHODIMP nsNavHistoryQuery::GetFolders(uint32_t *aCount,
1270 int64_t **aFolders)
1271 {
1272 uint32_t count = mFolders.Length();
1273 int64_t *folders = nullptr;
1274 if (count > 0) {
1275 folders = static_cast<int64_t*>
1276 (nsMemory::Alloc(count * sizeof(int64_t)));
1277 NS_ENSURE_TRUE(folders, NS_ERROR_OUT_OF_MEMORY);
1279 for (uint32_t i = 0; i < count; ++i) {
1280 folders[i] = mFolders[i];
1281 }
1282 }
1283 *aCount = count;
1284 *aFolders = folders;
1285 return NS_OK;
1286 }
1288 NS_IMETHODIMP nsNavHistoryQuery::GetFolderCount(uint32_t *aCount)
1289 {
1290 *aCount = mFolders.Length();
1291 return NS_OK;
1292 }
1294 NS_IMETHODIMP nsNavHistoryQuery::SetFolders(const int64_t *aFolders,
1295 uint32_t aFolderCount)
1296 {
1297 if (!mFolders.ReplaceElementsAt(0, mFolders.Length(),
1298 aFolders, aFolderCount)) {
1299 return NS_ERROR_OUT_OF_MEMORY;
1300 }
1302 return NS_OK;
1303 }
1305 NS_IMETHODIMP nsNavHistoryQuery::GetTransitions(uint32_t* aCount,
1306 uint32_t** aTransitions)
1307 {
1308 uint32_t count = mTransitions.Length();
1309 uint32_t* transitions = nullptr;
1310 if (count > 0) {
1311 transitions = reinterpret_cast<uint32_t*>
1312 (NS_Alloc(count * sizeof(uint32_t)));
1313 NS_ENSURE_TRUE(transitions, NS_ERROR_OUT_OF_MEMORY);
1314 for (uint32_t i = 0; i < count; ++i) {
1315 transitions[i] = mTransitions[i];
1316 }
1317 }
1318 *aCount = count;
1319 *aTransitions = transitions;
1320 return NS_OK;
1321 }
1323 NS_IMETHODIMP nsNavHistoryQuery::GetTransitionCount(uint32_t* aCount)
1324 {
1325 *aCount = mTransitions.Length();
1326 return NS_OK;
1327 }
1329 NS_IMETHODIMP nsNavHistoryQuery::SetTransitions(const uint32_t* aTransitions,
1330 uint32_t aCount)
1331 {
1332 if (!mTransitions.ReplaceElementsAt(0, mTransitions.Length(), aTransitions,
1333 aCount))
1334 return NS_ERROR_OUT_OF_MEMORY;
1336 return NS_OK;
1337 }
1339 NS_IMETHODIMP nsNavHistoryQuery::Clone(nsINavHistoryQuery** _retval)
1340 {
1341 *_retval = nullptr;
1343 nsNavHistoryQuery *clone = new nsNavHistoryQuery(*this);
1344 NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
1346 clone->mRefCnt = 0; // the clone doesn't inherit our refcount
1347 NS_ADDREF(*_retval = clone);
1348 return NS_OK;
1349 }
1352 // nsNavHistoryQueryOptions
1353 NS_IMPL_ISUPPORTS(nsNavHistoryQueryOptions, nsNavHistoryQueryOptions, nsINavHistoryQueryOptions)
1355 // sortingMode
1356 NS_IMETHODIMP
1357 nsNavHistoryQueryOptions::GetSortingMode(uint16_t* aMode)
1358 {
1359 *aMode = mSort;
1360 return NS_OK;
1361 }
1362 NS_IMETHODIMP
1363 nsNavHistoryQueryOptions::SetSortingMode(uint16_t aMode)
1364 {
1365 if (aMode > SORT_BY_FRECENCY_DESCENDING)
1366 return NS_ERROR_INVALID_ARG;
1367 mSort = aMode;
1368 return NS_OK;
1369 }
1371 // sortingAnnotation
1372 NS_IMETHODIMP
1373 nsNavHistoryQueryOptions::GetSortingAnnotation(nsACString& _result) {
1374 _result.Assign(mSortingAnnotation);
1375 return NS_OK;
1376 }
1378 NS_IMETHODIMP
1379 nsNavHistoryQueryOptions::SetSortingAnnotation(const nsACString& aSortingAnnotation) {
1380 mSortingAnnotation.Assign(aSortingAnnotation);
1381 return NS_OK;
1382 }
1384 // resultType
1385 NS_IMETHODIMP
1386 nsNavHistoryQueryOptions::GetResultType(uint16_t* aType)
1387 {
1388 *aType = mResultType;
1389 return NS_OK;
1390 }
1391 NS_IMETHODIMP
1392 nsNavHistoryQueryOptions::SetResultType(uint16_t aType)
1393 {
1394 if (aType > RESULTS_AS_TAG_CONTENTS)
1395 return NS_ERROR_INVALID_ARG;
1396 // Tag queries and containers are bookmarks related, so we set the QueryType
1397 // accordingly.
1398 if (aType == RESULTS_AS_TAG_QUERY || aType == RESULTS_AS_TAG_CONTENTS)
1399 mQueryType = QUERY_TYPE_BOOKMARKS;
1400 mResultType = aType;
1401 return NS_OK;
1402 }
1404 // excludeItems
1405 NS_IMETHODIMP
1406 nsNavHistoryQueryOptions::GetExcludeItems(bool* aExclude)
1407 {
1408 *aExclude = mExcludeItems;
1409 return NS_OK;
1410 }
1411 NS_IMETHODIMP
1412 nsNavHistoryQueryOptions::SetExcludeItems(bool aExclude)
1413 {
1414 mExcludeItems = aExclude;
1415 return NS_OK;
1416 }
1418 // excludeQueries
1419 NS_IMETHODIMP
1420 nsNavHistoryQueryOptions::GetExcludeQueries(bool* aExclude)
1421 {
1422 *aExclude = mExcludeQueries;
1423 return NS_OK;
1424 }
1425 NS_IMETHODIMP
1426 nsNavHistoryQueryOptions::SetExcludeQueries(bool aExclude)
1427 {
1428 mExcludeQueries = aExclude;
1429 return NS_OK;
1430 }
1432 // excludeReadOnlyFolders
1433 NS_IMETHODIMP
1434 nsNavHistoryQueryOptions::GetExcludeReadOnlyFolders(bool* aExclude)
1435 {
1436 *aExclude = mExcludeReadOnlyFolders;
1437 return NS_OK;
1438 }
1439 NS_IMETHODIMP
1440 nsNavHistoryQueryOptions::SetExcludeReadOnlyFolders(bool aExclude)
1441 {
1442 mExcludeReadOnlyFolders = aExclude;
1443 return NS_OK;
1444 }
1446 // expandQueries
1447 NS_IMETHODIMP
1448 nsNavHistoryQueryOptions::GetExpandQueries(bool* aExpand)
1449 {
1450 *aExpand = mExpandQueries;
1451 return NS_OK;
1452 }
1453 NS_IMETHODIMP
1454 nsNavHistoryQueryOptions::SetExpandQueries(bool aExpand)
1455 {
1456 mExpandQueries = aExpand;
1457 return NS_OK;
1458 }
1460 // includeHidden
1461 NS_IMETHODIMP
1462 nsNavHistoryQueryOptions::GetIncludeHidden(bool* aIncludeHidden)
1463 {
1464 *aIncludeHidden = mIncludeHidden;
1465 return NS_OK;
1466 }
1467 NS_IMETHODIMP
1468 nsNavHistoryQueryOptions::SetIncludeHidden(bool aIncludeHidden)
1469 {
1470 mIncludeHidden = aIncludeHidden;
1471 return NS_OK;
1472 }
1474 // maxResults
1475 NS_IMETHODIMP
1476 nsNavHistoryQueryOptions::GetMaxResults(uint32_t* aMaxResults)
1477 {
1478 *aMaxResults = mMaxResults;
1479 return NS_OK;
1480 }
1481 NS_IMETHODIMP
1482 nsNavHistoryQueryOptions::SetMaxResults(uint32_t aMaxResults)
1483 {
1484 mMaxResults = aMaxResults;
1485 return NS_OK;
1486 }
1488 // queryType
1489 NS_IMETHODIMP
1490 nsNavHistoryQueryOptions::GetQueryType(uint16_t* _retval)
1491 {
1492 *_retval = mQueryType;
1493 return NS_OK;
1494 }
1495 NS_IMETHODIMP
1496 nsNavHistoryQueryOptions::SetQueryType(uint16_t aQueryType)
1497 {
1498 // Tag query and containers are forced to QUERY_TYPE_BOOKMARKS when the
1499 // resultType is set.
1500 if (mResultType == RESULTS_AS_TAG_CONTENTS ||
1501 mResultType == RESULTS_AS_TAG_QUERY)
1502 return NS_OK;
1503 mQueryType = aQueryType;
1504 return NS_OK;
1505 }
1507 // asyncEnabled
1508 NS_IMETHODIMP
1509 nsNavHistoryQueryOptions::GetAsyncEnabled(bool* _asyncEnabled)
1510 {
1511 *_asyncEnabled = mAsyncEnabled;
1512 return NS_OK;
1513 }
1514 NS_IMETHODIMP
1515 nsNavHistoryQueryOptions::SetAsyncEnabled(bool aAsyncEnabled)
1516 {
1517 mAsyncEnabled = aAsyncEnabled;
1518 return NS_OK;
1519 }
1522 NS_IMETHODIMP
1523 nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** aResult)
1524 {
1525 nsNavHistoryQueryOptions *clone = nullptr;
1526 nsresult rv = Clone(&clone);
1527 *aResult = clone;
1528 return rv;
1529 }
1531 nsresult
1532 nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions **aResult)
1533 {
1534 *aResult = nullptr;
1535 nsNavHistoryQueryOptions *result = new nsNavHistoryQueryOptions();
1536 if (! result)
1537 return NS_ERROR_OUT_OF_MEMORY;
1539 nsRefPtr<nsNavHistoryQueryOptions> resultHolder(result);
1540 result->mSort = mSort;
1541 result->mResultType = mResultType;
1542 result->mExcludeItems = mExcludeItems;
1543 result->mExcludeQueries = mExcludeQueries;
1544 result->mExpandQueries = mExpandQueries;
1545 result->mMaxResults = mMaxResults;
1546 result->mQueryType = mQueryType;
1547 result->mParentAnnotationToExclude = mParentAnnotationToExclude;
1548 result->mAsyncEnabled = mAsyncEnabled;
1550 resultHolder.swap(*aResult);
1551 return NS_OK;
1552 }
1555 // AppendBoolKeyValueIfTrue
1557 void // static
1558 AppendBoolKeyValueIfTrue(nsACString& aString, const nsCString& aName,
1559 nsINavHistoryQuery* aQuery,
1560 BoolQueryGetter getter)
1561 {
1562 bool value;
1563 DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1564 NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting boolean value");
1565 if (value) {
1566 AppendAmpersandIfNonempty(aString);
1567 aString += aName;
1568 aString.AppendLiteral("=1");
1569 }
1570 }
1573 // AppendUint32KeyValueIfNonzero
1575 void // static
1576 AppendUint32KeyValueIfNonzero(nsACString& aString,
1577 const nsCString& aName,
1578 nsINavHistoryQuery* aQuery,
1579 Uint32QueryGetter getter)
1580 {
1581 uint32_t value;
1582 DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1583 NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value");
1584 if (value) {
1585 AppendAmpersandIfNonempty(aString);
1586 aString += aName;
1588 // AppendInt requires a concrete string
1589 nsAutoCString appendMe("=");
1590 appendMe.AppendInt(value);
1591 aString.Append(appendMe);
1592 }
1593 }
1596 // AppendInt64KeyValueIfNonzero
1598 void // static
1599 AppendInt64KeyValueIfNonzero(nsACString& aString,
1600 const nsCString& aName,
1601 nsINavHistoryQuery* aQuery,
1602 Int64QueryGetter getter)
1603 {
1604 PRTime value;
1605 DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1606 NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value");
1607 if (value) {
1608 AppendAmpersandIfNonempty(aString);
1609 aString += aName;
1610 nsAutoCString appendMe("=");
1611 appendMe.AppendInt(static_cast<int64_t>(value));
1612 aString.Append(appendMe);
1613 }
1614 }
1617 // SetQuery/OptionsKeyBool
1619 void // static
1620 SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1621 BoolQuerySetter setter)
1622 {
1623 bool value;
1624 nsresult rv = ParseQueryBooleanString(aValue, &value);
1625 if (NS_SUCCEEDED(rv)) {
1626 rv = (aQuery->*setter)(value);
1627 if (NS_FAILED(rv)) {
1628 NS_WARNING("Error setting boolean key value");
1629 }
1630 } else {
1631 NS_WARNING("Invalid boolean key value in query string.");
1632 }
1633 }
1634 void // static
1635 SetOptionsKeyBool(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions,
1636 BoolOptionsSetter setter)
1637 {
1638 bool value;
1639 nsresult rv = ParseQueryBooleanString(aValue, &value);
1640 if (NS_SUCCEEDED(rv)) {
1641 rv = (aOptions->*setter)(value);
1642 if (NS_FAILED(rv)) {
1643 NS_WARNING("Error setting boolean key value");
1644 }
1645 } else {
1646 NS_WARNING("Invalid boolean key value in query string.");
1647 }
1648 }
1651 // SetQuery/OptionsKeyUint32
1653 void // static
1654 SetQueryKeyUint32(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1655 Uint32QuerySetter setter)
1656 {
1657 nsresult rv;
1658 uint32_t value = aValue.ToInteger(&rv);
1659 if (NS_SUCCEEDED(rv)) {
1660 rv = (aQuery->*setter)(value);
1661 if (NS_FAILED(rv)) {
1662 NS_WARNING("Error setting Int32 key value");
1663 }
1664 } else {
1665 NS_WARNING("Invalid Int32 key value in query string.");
1666 }
1667 }
1668 void // static
1669 SetOptionsKeyUint32(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions,
1670 Uint32OptionsSetter setter)
1671 {
1672 nsresult rv;
1673 uint32_t value = aValue.ToInteger(&rv);
1674 if (NS_SUCCEEDED(rv)) {
1675 rv = (aOptions->*setter)(value);
1676 if (NS_FAILED(rv)) {
1677 NS_WARNING("Error setting Int32 key value");
1678 }
1679 } else {
1680 NS_WARNING("Invalid Int32 key value in query string.");
1681 }
1682 }
1684 void // static
1685 SetOptionsKeyUint16(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions,
1686 Uint16OptionsSetter setter)
1687 {
1688 nsresult rv;
1689 uint16_t value = static_cast<uint16_t>(aValue.ToInteger(&rv));
1690 if (NS_SUCCEEDED(rv)) {
1691 rv = (aOptions->*setter)(value);
1692 if (NS_FAILED(rv)) {
1693 NS_WARNING("Error setting Int16 key value");
1694 }
1695 } else {
1696 NS_WARNING("Invalid Int16 key value in query string.");
1697 }
1698 }
1701 // SetQueryKeyInt64
1703 void SetQueryKeyInt64(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1704 Int64QuerySetter setter)
1705 {
1706 nsresult rv;
1707 int64_t value;
1708 if (PR_sscanf(aValue.get(), "%lld", &value) == 1) {
1709 rv = (aQuery->*setter)(value);
1710 if (NS_FAILED(rv)) {
1711 NS_WARNING("Error setting Int64 key value");
1712 }
1713 } else {
1714 NS_WARNING("Invalid Int64 value in query string.");
1715 }
1716 }