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/. */
5 
6 /**
7  * This file contains the definitions of nsNavHistoryQuery,
8  * nsNavHistoryQueryOptions, and those functions in nsINavHistory that directly
9  * support queries (specifically QueryStringToQuery and QueryToQueryString).
10  */
11 
12 #include "mozilla/DebugOnly.h"
13 
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"
21 #include "nsVariant.h"
22 
23 using namespace mozilla;
24 using namespace mozilla::places;
25 
26 static nsresult ParseQueryBooleanString(const nsCString& aString, bool* aValue);
27 
28 // query getters
29 typedef decltype(&nsINavHistoryQuery::GetOnlyBookmarked) BoolQueryGetter;
30 typedef decltype(&nsINavHistoryQuery::GetBeginTimeReference) Uint32QueryGetter;
31 typedef decltype(&nsINavHistoryQuery::GetBeginTime) Int64QueryGetter;
32 static void AppendBoolKeyValueIfTrue(nsACString& aString,
33                                      const nsCString& aName,
34                                      nsINavHistoryQuery* aQuery,
35                                      BoolQueryGetter getter);
36 static void AppendUint32KeyValueIfNonzero(nsACString& aString,
37                                           const nsCString& aName,
38                                           nsINavHistoryQuery* aQuery,
39                                           Uint32QueryGetter getter);
40 static void AppendInt64KeyValueIfNonzero(nsACString& aString,
41                                          const nsCString& aName,
42                                          nsINavHistoryQuery* aQuery,
43                                          Int64QueryGetter getter);
44 
45 // query setters
46 typedef decltype(&nsINavHistoryQuery::SetOnlyBookmarked) BoolQuerySetter;
47 typedef decltype(&nsINavHistoryQuery::SetBeginTimeReference) Uint32QuerySetter;
48 typedef decltype(&nsINavHistoryQuery::SetBeginTime) Int64QuerySetter;
49 static void SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery,
50                             BoolQuerySetter setter);
51 static void SetQueryKeyUint32(const nsCString& aValue,
52                               nsINavHistoryQuery* aQuery,
53                               Uint32QuerySetter setter);
54 static void SetQueryKeyInt64(const nsCString& aValue,
55                              nsINavHistoryQuery* aQuery,
56                              Int64QuerySetter setter);
57 
58 // options setters
59 typedef decltype(&nsINavHistoryQueryOptions::SetExpandQueries)
60     BoolOptionsSetter;
61 typedef decltype(&nsINavHistoryQueryOptions::SetMaxResults) Uint32OptionsSetter;
62 typedef decltype(&nsINavHistoryQueryOptions::SetResultType) Uint16OptionsSetter;
63 static void SetOptionsKeyBool(const nsCString& aValue,
64                               nsINavHistoryQueryOptions* aOptions,
65                               BoolOptionsSetter setter);
66 static void SetOptionsKeyUint16(const nsCString& aValue,
67                                 nsINavHistoryQueryOptions* aOptions,
68                                 Uint16OptionsSetter setter);
69 static void SetOptionsKeyUint32(const nsCString& aValue,
70                                 nsINavHistoryQueryOptions* aOptions,
71                                 Uint32OptionsSetter setter);
72 
73 // Components of a query string.
74 // Note that query strings are also generated in nsNavBookmarks::GetFolderURI
75 // for performance reasons, so if you change these values, change that, too.
76 #define QUERYKEY_BEGIN_TIME "beginTime"
77 #define QUERYKEY_BEGIN_TIME_REFERENCE "beginTimeRef"
78 #define QUERYKEY_END_TIME "endTime"
79 #define QUERYKEY_END_TIME_REFERENCE "endTimeRef"
80 #define QUERYKEY_SEARCH_TERMS "terms"
81 #define QUERYKEY_MIN_VISITS "minVisits"
82 #define QUERYKEY_MAX_VISITS "maxVisits"
83 #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked"
84 #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost"
85 #define QUERYKEY_DOMAIN "domain"
86 #define QUERYKEY_PARENT "parent"
87 #define QUERYKEY_NOTANNOTATION "!annotation"
88 #define QUERYKEY_ANNOTATION "annotation"
89 #define QUERYKEY_URI "uri"
90 #define QUERYKEY_GROUP "group"
91 #define QUERYKEY_SORT "sort"
92 #define QUERYKEY_RESULT_TYPE "type"
93 #define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
94 #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries"
95 #define QUERYKEY_EXPAND_QUERIES "expandQueries"
96 #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle"
97 #define QUERYKEY_INCLUDE_HIDDEN "includeHidden"
98 #define QUERYKEY_MAX_RESULTS "maxResults"
99 #define QUERYKEY_QUERY_TYPE "queryType"
100 #define QUERYKEY_TAG "tag"
101 #define QUERYKEY_NOTTAGS "!tags"
102 #define QUERYKEY_ASYNC_ENABLED "asyncEnabled"
103 #define QUERYKEY_TRANSITION "transition"
104 
AppendAmpersandIfNonempty(nsACString & aString)105 inline void AppendAmpersandIfNonempty(nsACString& aString) {
106   if (!aString.IsEmpty()) aString.Append('&');
107 }
AppendInt16(nsACString & str,int16_t i)108 inline void AppendInt16(nsACString& str, int16_t i) {
109   nsAutoCString tmp;
110   tmp.AppendInt(i);
111   str.Append(tmp);
112 }
AppendInt32(nsACString & str,int32_t i)113 inline void AppendInt32(nsACString& str, int32_t i) {
114   nsAutoCString tmp;
115   tmp.AppendInt(i);
116   str.Append(tmp);
117 }
AppendInt64(nsACString & str,int64_t i)118 inline void AppendInt64(nsACString& str, int64_t i) {
119   nsCString tmp;
120   tmp.AppendInt(i);
121   str.Append(tmp);
122 }
123 
124 NS_IMETHODIMP
QueryStringToQuery(const nsACString & aQueryString,nsINavHistoryQuery ** _query,nsINavHistoryQueryOptions ** _options)125 nsNavHistory::QueryStringToQuery(const nsACString& aQueryString,
126                                  nsINavHistoryQuery** _query,
127                                  nsINavHistoryQueryOptions** _options) {
128   NS_ENSURE_ARG_POINTER(_query);
129   NS_ENSURE_ARG_POINTER(_options);
130 
131   nsTArray<QueryKeyValuePair> tokens;
132   nsresult rv = TokenizeQueryString(aQueryString, &tokens);
133   NS_ENSURE_SUCCESS(rv, rv);
134 
135   RefPtr<nsNavHistoryQueryOptions> options = new nsNavHistoryQueryOptions();
136   RefPtr<nsNavHistoryQuery> query = new nsNavHistoryQuery();
137   rv = TokensToQuery(tokens, query, options);
138   MOZ_ASSERT(NS_SUCCEEDED(rv), "The query string should be valid");
139   if (NS_FAILED(rv)) {
140     NS_WARNING("Unable to parse the query string: ");
141     NS_WARNING(PromiseFlatCString(aQueryString).get());
142   }
143 
144   options.forget(_options);
145   query.forget(_query);
146   return NS_OK;
147 }
148 
149 NS_IMETHODIMP
QueryToQueryString(nsINavHistoryQuery * aQuery,nsINavHistoryQueryOptions * aOptions,nsACString & aQueryString)150 nsNavHistory::QueryToQueryString(nsINavHistoryQuery* aQuery,
151                                  nsINavHistoryQueryOptions* aOptions,
152                                  nsACString& aQueryString) {
153   NS_ENSURE_ARG(aQuery);
154   NS_ENSURE_ARG(aOptions);
155 
156   RefPtr<nsNavHistoryQuery> query = do_QueryObject(aQuery);
157   NS_ENSURE_STATE(query);
158   RefPtr<nsNavHistoryQueryOptions> options = do_QueryObject(aOptions);
159   NS_ENSURE_STATE(options);
160 
161   nsAutoCString queryString;
162   bool hasIt;
163 
164   // begin time
165   query->GetHasBeginTime(&hasIt);
166   if (hasIt) {
167     AppendInt64KeyValueIfNonzero(queryString,
168                                  nsLiteralCString(QUERYKEY_BEGIN_TIME), query,
169                                  &nsINavHistoryQuery::GetBeginTime);
170     AppendUint32KeyValueIfNonzero(
171         queryString, nsLiteralCString(QUERYKEY_BEGIN_TIME_REFERENCE), query,
172         &nsINavHistoryQuery::GetBeginTimeReference);
173   }
174 
175   // end time
176   query->GetHasEndTime(&hasIt);
177   if (hasIt) {
178     AppendInt64KeyValueIfNonzero(queryString,
179                                  nsLiteralCString(QUERYKEY_END_TIME), query,
180                                  &nsINavHistoryQuery::GetEndTime);
181     AppendUint32KeyValueIfNonzero(
182         queryString, nsLiteralCString(QUERYKEY_END_TIME_REFERENCE), query,
183         &nsINavHistoryQuery::GetEndTimeReference);
184   }
185 
186   // search terms
187   if (!query->SearchTerms().IsEmpty()) {
188     const nsString& searchTerms = query->SearchTerms();
189     nsCString escapedTerms;
190     if (!NS_Escape(NS_ConvertUTF16toUTF8(searchTerms), escapedTerms,
191                    url_XAlphas))
192       return NS_ERROR_OUT_OF_MEMORY;
193 
194     AppendAmpersandIfNonempty(queryString);
195     queryString += nsLiteralCString(QUERYKEY_SEARCH_TERMS "=");
196     queryString += escapedTerms;
197   }
198 
199   // min and max visits
200   int32_t minVisits;
201   if (NS_SUCCEEDED(query->GetMinVisits(&minVisits)) && minVisits >= 0) {
202     AppendAmpersandIfNonempty(queryString);
203     queryString.AppendLiteral(QUERYKEY_MIN_VISITS "=");
204     AppendInt32(queryString, minVisits);
205   }
206 
207   int32_t maxVisits;
208   if (NS_SUCCEEDED(query->GetMaxVisits(&maxVisits)) && maxVisits >= 0) {
209     AppendAmpersandIfNonempty(queryString);
210     queryString.AppendLiteral(QUERYKEY_MAX_VISITS "=");
211     AppendInt32(queryString, maxVisits);
212   }
213 
214   // only bookmarked
215   AppendBoolKeyValueIfTrue(queryString,
216                            nsLiteralCString(QUERYKEY_ONLY_BOOKMARKED), query,
217                            &nsINavHistoryQuery::GetOnlyBookmarked);
218 
219   // domain (+ is host), only call if hasDomain, which means non-IsVoid
220   // this means we may get an empty string for the domain in the result,
221   // which is valid
222   if (!query->Domain().IsVoid()) {
223     AppendBoolKeyValueIfTrue(queryString,
224                              nsLiteralCString(QUERYKEY_DOMAIN_IS_HOST), query,
225                              &nsINavHistoryQuery::GetDomainIsHost);
226     const nsCString& domain = query->Domain();
227     nsCString escapedDomain;
228     bool success = NS_Escape(domain, escapedDomain, url_XAlphas);
229     NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
230 
231     AppendAmpersandIfNonempty(queryString);
232     queryString.AppendLiteral(QUERYKEY_DOMAIN "=");
233     queryString.Append(escapedDomain);
234   }
235 
236   // uri
237   if (query->Uri()) {
238     nsCOMPtr<nsIURI> uri = query->Uri();
239     nsAutoCString uriSpec;
240     nsresult rv = uri->GetSpec(uriSpec);
241     NS_ENSURE_SUCCESS(rv, rv);
242     nsAutoCString escaped;
243     bool success = NS_Escape(uriSpec, escaped, url_XAlphas);
244     NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
245 
246     AppendAmpersandIfNonempty(queryString);
247     queryString.AppendLiteral(QUERYKEY_URI "=");
248     queryString.Append(escaped);
249   }
250 
251   // annotation
252   if (!query->Annotation().IsEmpty()) {
253     AppendAmpersandIfNonempty(queryString);
254     if (query->AnnotationIsNot()) {
255       queryString.AppendLiteral(QUERYKEY_NOTANNOTATION "=");
256     } else {
257       queryString.AppendLiteral(QUERYKEY_ANNOTATION "=");
258     }
259     const nsCString& annot = query->Annotation();
260     nsAutoCString escaped;
261     bool success = NS_Escape(annot, escaped, url_XAlphas);
262     NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
263     queryString.Append(escaped);
264   }
265 
266   // parents
267   const nsTArray<nsCString>& parents = query->Parents();
268   for (uint32_t i = 0; i < parents.Length(); ++i) {
269     AppendAmpersandIfNonempty(queryString);
270     queryString += nsLiteralCString(QUERYKEY_PARENT "=");
271     queryString += parents[i];
272   }
273 
274   // tags
275   const nsTArray<nsString>& tags = query->Tags();
276   for (uint32_t i = 0; i < tags.Length(); ++i) {
277     nsAutoCString escapedTag;
278     if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas))
279       return NS_ERROR_OUT_OF_MEMORY;
280 
281     AppendAmpersandIfNonempty(queryString);
282     queryString += nsLiteralCString(QUERYKEY_TAG "=");
283     queryString += escapedTag;
284   }
285   AppendBoolKeyValueIfTrue(queryString, nsLiteralCString(QUERYKEY_NOTTAGS),
286                            query, &nsINavHistoryQuery::GetTagsAreNot);
287 
288   // transitions
289   const nsTArray<uint32_t>& transitions = query->Transitions();
290   for (uint32_t i = 0; i < transitions.Length(); ++i) {
291     AppendAmpersandIfNonempty(queryString);
292     queryString += nsLiteralCString(QUERYKEY_TRANSITION "=");
293     AppendInt64(queryString, transitions[i]);
294   }
295 
296   // sorting
297   if (options->SortingMode() != nsINavHistoryQueryOptions::SORT_BY_NONE) {
298     AppendAmpersandIfNonempty(queryString);
299     queryString += nsLiteralCString(QUERYKEY_SORT "=");
300     AppendInt16(queryString, options->SortingMode());
301   }
302 
303   // result type
304   if (options->ResultType() != nsINavHistoryQueryOptions::RESULTS_AS_URI) {
305     AppendAmpersandIfNonempty(queryString);
306     queryString += nsLiteralCString(QUERYKEY_RESULT_TYPE "=");
307     AppendInt16(queryString, options->ResultType());
308   }
309 
310   // exclude items
311   if (options->ExcludeItems()) {
312     AppendAmpersandIfNonempty(queryString);
313     queryString += nsLiteralCString(QUERYKEY_EXCLUDE_ITEMS "=1");
314   }
315 
316   // exclude queries
317   if (options->ExcludeQueries()) {
318     AppendAmpersandIfNonempty(queryString);
319     queryString += nsLiteralCString(QUERYKEY_EXCLUDE_QUERIES "=1");
320   }
321 
322   // expand queries
323   if (!options->ExpandQueries()) {
324     AppendAmpersandIfNonempty(queryString);
325     queryString += nsLiteralCString(QUERYKEY_EXPAND_QUERIES "=0");
326   }
327 
328   // include hidden
329   if (options->IncludeHidden()) {
330     AppendAmpersandIfNonempty(queryString);
331     queryString += nsLiteralCString(QUERYKEY_INCLUDE_HIDDEN "=1");
332   }
333 
334   // max results
335   if (options->MaxResults()) {
336     AppendAmpersandIfNonempty(queryString);
337     queryString += nsLiteralCString(QUERYKEY_MAX_RESULTS "=");
338     AppendInt32(queryString, options->MaxResults());
339   }
340 
341   // queryType
342   if (options->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY) {
343     AppendAmpersandIfNonempty(queryString);
344     queryString += nsLiteralCString(QUERYKEY_QUERY_TYPE "=");
345     AppendInt16(queryString, options->QueryType());
346   }
347 
348   // async enabled
349   if (options->AsyncEnabled()) {
350     AppendAmpersandIfNonempty(queryString);
351     queryString += nsLiteralCString(QUERYKEY_ASYNC_ENABLED "=1");
352   }
353 
354   aQueryString.AssignLiteral("place:");
355   aQueryString.Append(queryString);
356   return NS_OK;
357 }
358 
TokensToQuery(const nsTArray<QueryKeyValuePair> & aTokens,nsNavHistoryQuery * aQuery,nsNavHistoryQueryOptions * aOptions)359 nsresult nsNavHistory::TokensToQuery(const nsTArray<QueryKeyValuePair>& aTokens,
360                                      nsNavHistoryQuery* aQuery,
361                                      nsNavHistoryQueryOptions* aOptions) {
362   nsresult rv;
363 
364   if (aTokens.Length() == 0) return NS_OK;
365 
366   nsTArray<nsCString> parents;
367   nsTArray<nsString> tags;
368   nsTArray<uint32_t> transitions;
369   for (uint32_t i = 0; i < aTokens.Length(); i++) {
370     const QueryKeyValuePair& kvp = aTokens[i];
371 
372     // begin time
373     if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME)) {
374       SetQueryKeyInt64(kvp.value, aQuery, &nsINavHistoryQuery::SetBeginTime);
375 
376       // begin time reference
377     } else if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME_REFERENCE)) {
378       SetQueryKeyUint32(kvp.value, aQuery,
379                         &nsINavHistoryQuery::SetBeginTimeReference);
380 
381       // end time
382     } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME)) {
383       SetQueryKeyInt64(kvp.value, aQuery, &nsINavHistoryQuery::SetEndTime);
384 
385       // end time reference
386     } else if (kvp.key.EqualsLiteral(QUERYKEY_END_TIME_REFERENCE)) {
387       SetQueryKeyUint32(kvp.value, aQuery,
388                         &nsINavHistoryQuery::SetEndTimeReference);
389 
390       // search terms
391     } else if (kvp.key.EqualsLiteral(QUERYKEY_SEARCH_TERMS)) {
392       nsCString unescapedTerms = kvp.value;
393       NS_UnescapeURL(unescapedTerms);  // modifies input
394       rv = aQuery->SetSearchTerms(NS_ConvertUTF8toUTF16(unescapedTerms));
395       NS_ENSURE_SUCCESS(rv, rv);
396 
397       // min visits
398     } else if (kvp.key.EqualsLiteral(QUERYKEY_MIN_VISITS)) {
399       int32_t visits = kvp.value.ToInteger(&rv);
400       if (NS_SUCCEEDED(rv))
401         aQuery->SetMinVisits(visits);
402       else
403         NS_WARNING("Bad number for minVisits in query");
404 
405       // max visits
406     } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_VISITS)) {
407       int32_t visits = kvp.value.ToInteger(&rv);
408       if (NS_SUCCEEDED(rv))
409         aQuery->SetMaxVisits(visits);
410       else
411         NS_WARNING("Bad number for maxVisits in query");
412 
413       // onlyBookmarked flag
414     } else if (kvp.key.EqualsLiteral(QUERYKEY_ONLY_BOOKMARKED)) {
415       SetQueryKeyBool(kvp.value, aQuery,
416                       &nsINavHistoryQuery::SetOnlyBookmarked);
417 
418       // domainIsHost flag
419     } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN_IS_HOST)) {
420       SetQueryKeyBool(kvp.value, aQuery, &nsINavHistoryQuery::SetDomainIsHost);
421 
422       // domain string
423     } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN)) {
424       nsAutoCString unescapedDomain(kvp.value);
425       NS_UnescapeURL(unescapedDomain);  // modifies input
426       rv = aQuery->SetDomain(unescapedDomain);
427       NS_ENSURE_SUCCESS(rv, rv);
428 
429       // parent folders (guids)
430     } else if (kvp.key.EqualsLiteral(QUERYKEY_PARENT)) {
431       parents.AppendElement(kvp.value);
432 
433       // uri
434     } else if (kvp.key.EqualsLiteral(QUERYKEY_URI)) {
435       nsAutoCString unescapedUri(kvp.value);
436       NS_UnescapeURL(unescapedUri);  // modifies input
437       nsCOMPtr<nsIURI> uri;
438       nsresult rv = NS_NewURI(getter_AddRefs(uri), unescapedUri);
439       if (NS_FAILED(rv)) {
440         NS_WARNING("Unable to parse URI");
441       }
442       rv = aQuery->SetUri(uri);
443       NS_ENSURE_SUCCESS(rv, rv);
444 
445       // not annotation
446     } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTANNOTATION)) {
447       nsAutoCString unescaped(kvp.value);
448       NS_UnescapeURL(unescaped);  // modifies input
449       aQuery->SetAnnotationIsNot(true);
450       aQuery->SetAnnotation(unescaped);
451 
452       // annotation
453     } else if (kvp.key.EqualsLiteral(QUERYKEY_ANNOTATION)) {
454       nsAutoCString unescaped(kvp.value);
455       NS_UnescapeURL(unescaped);  // modifies input
456       aQuery->SetAnnotationIsNot(false);
457       aQuery->SetAnnotation(unescaped);
458 
459       // tag
460     } else if (kvp.key.EqualsLiteral(QUERYKEY_TAG)) {
461       nsAutoCString unescaped(kvp.value);
462       NS_UnescapeURL(unescaped);  // modifies input
463       NS_ConvertUTF8toUTF16 tag(unescaped);
464       if (!tags.Contains(tag)) {
465         tags.AppendElement(tag);
466       }
467 
468       // not tags
469     } else if (kvp.key.EqualsLiteral(QUERYKEY_NOTTAGS)) {
470       SetQueryKeyBool(kvp.value, aQuery, &nsINavHistoryQuery::SetTagsAreNot);
471 
472       // transition
473     } else if (kvp.key.EqualsLiteral(QUERYKEY_TRANSITION)) {
474       uint32_t transition = kvp.value.ToInteger(&rv);
475       if (NS_SUCCEEDED(rv)) {
476         if (!transitions.Contains(transition))
477           transitions.AppendElement(transition);
478       } else {
479         NS_WARNING("Invalid Int32 transition value.");
480       }
481 
482       // sorting mode
483     } else if (kvp.key.EqualsLiteral(QUERYKEY_SORT)) {
484       SetOptionsKeyUint16(kvp.value, aOptions,
485                           &nsINavHistoryQueryOptions::SetSortingMode);
486       // result type
487     } else if (kvp.key.EqualsLiteral(QUERYKEY_RESULT_TYPE)) {
488       SetOptionsKeyUint16(kvp.value, aOptions,
489                           &nsINavHistoryQueryOptions::SetResultType);
490 
491       // exclude items
492     } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_ITEMS)) {
493       SetOptionsKeyBool(kvp.value, aOptions,
494                         &nsINavHistoryQueryOptions::SetExcludeItems);
495 
496       // exclude queries
497     } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_QUERIES)) {
498       SetOptionsKeyBool(kvp.value, aOptions,
499                         &nsINavHistoryQueryOptions::SetExcludeQueries);
500 
501       // expand queries
502     } else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) {
503       SetOptionsKeyBool(kvp.value, aOptions,
504                         &nsINavHistoryQueryOptions::SetExpandQueries);
505       // include hidden
506     } else if (kvp.key.EqualsLiteral(QUERYKEY_INCLUDE_HIDDEN)) {
507       SetOptionsKeyBool(kvp.value, aOptions,
508                         &nsINavHistoryQueryOptions::SetIncludeHidden);
509       // max results
510     } else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) {
511       SetOptionsKeyUint32(kvp.value, aOptions,
512                           &nsINavHistoryQueryOptions::SetMaxResults);
513       // query type
514     } else if (kvp.key.EqualsLiteral(QUERYKEY_QUERY_TYPE)) {
515       SetOptionsKeyUint16(kvp.value, aOptions,
516                           &nsINavHistoryQueryOptions::SetQueryType);
517       // async enabled
518     } else if (kvp.key.EqualsLiteral(QUERYKEY_ASYNC_ENABLED)) {
519       SetOptionsKeyBool(kvp.value, aOptions,
520                         &nsINavHistoryQueryOptions::SetAsyncEnabled);
521       // unknown key
522     } else {
523       NS_WARNING("TokensToQueries(), ignoring unknown key: ");
524       NS_WARNING(kvp.key.get());
525     }
526   }
527 
528   if (parents.Length() != 0) {
529     rv = aQuery->SetParents(parents);
530     NS_ENSURE_SUCCESS(rv, rv);
531   }
532 
533   if (tags.Length() > 0) {
534     aQuery->SetTags(std::move(tags));
535   }
536 
537   if (transitions.Length() > 0) {
538     rv = aQuery->SetTransitions(transitions);
539     NS_ENSURE_SUCCESS(rv, rv);
540   }
541 
542   return NS_OK;
543 }
544 
545 // ParseQueryBooleanString
546 //
547 //    Converts a 0/1 or true/false string into a bool
548 
ParseQueryBooleanString(const nsCString & aString,bool * aValue)549 nsresult ParseQueryBooleanString(const nsCString& aString, bool* aValue) {
550   if (aString.EqualsLiteral("1") || aString.EqualsLiteral("true")) {
551     *aValue = true;
552     return NS_OK;
553   }
554   if (aString.EqualsLiteral("0") || aString.EqualsLiteral("false")) {
555     *aValue = false;
556     return NS_OK;
557   }
558   return NS_ERROR_INVALID_ARG;
559 }
560 
561 // nsINavHistoryQuery **********************************************************
562 
NS_IMPL_ISUPPORTS(nsNavHistoryQuery,nsNavHistoryQuery,nsINavHistoryQuery)563 NS_IMPL_ISUPPORTS(nsNavHistoryQuery, nsNavHistoryQuery, nsINavHistoryQuery)
564 
565 // nsINavHistoryQuery::nsNavHistoryQuery
566 //
567 //    This must initialize the object such that the default values will cause
568 //    all history to be returned if this query is used. Then the caller can
569 //    just set the things it's interested in.
570 
571 nsNavHistoryQuery::nsNavHistoryQuery()
572     : mMinVisits(-1),
573       mMaxVisits(-1),
574       mBeginTime(0),
575       mBeginTimeReference(TIME_RELATIVE_EPOCH),
576       mEndTime(0),
577       mEndTimeReference(TIME_RELATIVE_EPOCH),
578       mOnlyBookmarked(false),
579       mDomainIsHost(false),
580       mAnnotationIsNot(false),
581       mTagsAreNot(false) {
582   // differentiate not set (IsVoid) from empty string (local files)
583   mDomain.SetIsVoid(true);
584 }
585 
nsNavHistoryQuery(const nsNavHistoryQuery & aOther)586 nsNavHistoryQuery::nsNavHistoryQuery(const nsNavHistoryQuery& aOther)
587     : mMinVisits(aOther.mMinVisits),
588       mMaxVisits(aOther.mMaxVisits),
589       mBeginTime(aOther.mBeginTime),
590       mBeginTimeReference(aOther.mBeginTimeReference),
591       mEndTime(aOther.mEndTime),
592       mEndTimeReference(aOther.mEndTimeReference),
593       mSearchTerms(aOther.mSearchTerms),
594       mOnlyBookmarked(aOther.mOnlyBookmarked),
595       mDomainIsHost(aOther.mDomainIsHost),
596       mDomain(aOther.mDomain),
597       mUri(aOther.mUri),
598       mAnnotationIsNot(aOther.mAnnotationIsNot),
599       mAnnotation(aOther.mAnnotation),
600       mParents(aOther.mParents.Clone()),
601       mTags(aOther.mTags.Clone()),
602       mTagsAreNot(aOther.mTagsAreNot),
603       mTransitions(aOther.mTransitions.Clone()) {}
604 
GetBeginTime(PRTime * aBeginTime)605 NS_IMETHODIMP nsNavHistoryQuery::GetBeginTime(PRTime* aBeginTime) {
606   *aBeginTime = mBeginTime;
607   return NS_OK;
608 }
SetBeginTime(PRTime aBeginTime)609 NS_IMETHODIMP nsNavHistoryQuery::SetBeginTime(PRTime aBeginTime) {
610   mBeginTime = aBeginTime;
611   return NS_OK;
612 }
613 
GetBeginTimeReference(uint32_t * _retval)614 NS_IMETHODIMP nsNavHistoryQuery::GetBeginTimeReference(uint32_t* _retval) {
615   *_retval = mBeginTimeReference;
616   return NS_OK;
617 }
SetBeginTimeReference(uint32_t aReference)618 NS_IMETHODIMP nsNavHistoryQuery::SetBeginTimeReference(uint32_t aReference) {
619   if (aReference > TIME_RELATIVE_NOW) return NS_ERROR_INVALID_ARG;
620   mBeginTimeReference = aReference;
621   return NS_OK;
622 }
623 
GetHasBeginTime(bool * _retval)624 NS_IMETHODIMP nsNavHistoryQuery::GetHasBeginTime(bool* _retval) {
625   *_retval = !(mBeginTimeReference == TIME_RELATIVE_EPOCH && mBeginTime == 0);
626   return NS_OK;
627 }
628 
GetAbsoluteBeginTime(PRTime * _retval)629 NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteBeginTime(PRTime* _retval) {
630   *_retval = nsNavHistory::NormalizeTime(mBeginTimeReference, mBeginTime);
631   return NS_OK;
632 }
633 
GetEndTime(PRTime * aEndTime)634 NS_IMETHODIMP nsNavHistoryQuery::GetEndTime(PRTime* aEndTime) {
635   *aEndTime = mEndTime;
636   return NS_OK;
637 }
SetEndTime(PRTime aEndTime)638 NS_IMETHODIMP nsNavHistoryQuery::SetEndTime(PRTime aEndTime) {
639   mEndTime = aEndTime;
640   return NS_OK;
641 }
642 
GetEndTimeReference(uint32_t * _retval)643 NS_IMETHODIMP nsNavHistoryQuery::GetEndTimeReference(uint32_t* _retval) {
644   *_retval = mEndTimeReference;
645   return NS_OK;
646 }
SetEndTimeReference(uint32_t aReference)647 NS_IMETHODIMP nsNavHistoryQuery::SetEndTimeReference(uint32_t aReference) {
648   if (aReference > TIME_RELATIVE_NOW) return NS_ERROR_INVALID_ARG;
649   mEndTimeReference = aReference;
650   return NS_OK;
651 }
652 
GetHasEndTime(bool * _retval)653 NS_IMETHODIMP nsNavHistoryQuery::GetHasEndTime(bool* _retval) {
654   *_retval = !(mEndTimeReference == TIME_RELATIVE_EPOCH && mEndTime == 0);
655   return NS_OK;
656 }
657 
GetAbsoluteEndTime(PRTime * _retval)658 NS_IMETHODIMP nsNavHistoryQuery::GetAbsoluteEndTime(PRTime* _retval) {
659   *_retval = nsNavHistory::NormalizeTime(mEndTimeReference, mEndTime);
660   return NS_OK;
661 }
662 
GetSearchTerms(nsAString & aSearchTerms)663 NS_IMETHODIMP nsNavHistoryQuery::GetSearchTerms(nsAString& aSearchTerms) {
664   aSearchTerms = mSearchTerms;
665   return NS_OK;
666 }
SetSearchTerms(const nsAString & aSearchTerms)667 NS_IMETHODIMP nsNavHistoryQuery::SetSearchTerms(const nsAString& aSearchTerms) {
668   mSearchTerms = aSearchTerms;
669   return NS_OK;
670 }
GetHasSearchTerms(bool * _retval)671 NS_IMETHODIMP nsNavHistoryQuery::GetHasSearchTerms(bool* _retval) {
672   *_retval = (!mSearchTerms.IsEmpty());
673   return NS_OK;
674 }
675 
GetMinVisits(int32_t * _retval)676 NS_IMETHODIMP nsNavHistoryQuery::GetMinVisits(int32_t* _retval) {
677   NS_ENSURE_ARG_POINTER(_retval);
678   *_retval = mMinVisits;
679   return NS_OK;
680 }
SetMinVisits(int32_t aVisits)681 NS_IMETHODIMP nsNavHistoryQuery::SetMinVisits(int32_t aVisits) {
682   mMinVisits = aVisits;
683   return NS_OK;
684 }
685 
GetMaxVisits(int32_t * _retval)686 NS_IMETHODIMP nsNavHistoryQuery::GetMaxVisits(int32_t* _retval) {
687   NS_ENSURE_ARG_POINTER(_retval);
688   *_retval = mMaxVisits;
689   return NS_OK;
690 }
SetMaxVisits(int32_t aVisits)691 NS_IMETHODIMP nsNavHistoryQuery::SetMaxVisits(int32_t aVisits) {
692   mMaxVisits = aVisits;
693   return NS_OK;
694 }
695 
GetOnlyBookmarked(bool * aOnlyBookmarked)696 NS_IMETHODIMP nsNavHistoryQuery::GetOnlyBookmarked(bool* aOnlyBookmarked) {
697   *aOnlyBookmarked = mOnlyBookmarked;
698   return NS_OK;
699 }
SetOnlyBookmarked(bool aOnlyBookmarked)700 NS_IMETHODIMP nsNavHistoryQuery::SetOnlyBookmarked(bool aOnlyBookmarked) {
701   mOnlyBookmarked = aOnlyBookmarked;
702   return NS_OK;
703 }
704 
GetDomainIsHost(bool * aDomainIsHost)705 NS_IMETHODIMP nsNavHistoryQuery::GetDomainIsHost(bool* aDomainIsHost) {
706   *aDomainIsHost = mDomainIsHost;
707   return NS_OK;
708 }
SetDomainIsHost(bool aDomainIsHost)709 NS_IMETHODIMP nsNavHistoryQuery::SetDomainIsHost(bool aDomainIsHost) {
710   mDomainIsHost = aDomainIsHost;
711   return NS_OK;
712 }
713 
GetDomain(nsACString & aDomain)714 NS_IMETHODIMP nsNavHistoryQuery::GetDomain(nsACString& aDomain) {
715   aDomain = mDomain;
716   return NS_OK;
717 }
SetDomain(const nsACString & aDomain)718 NS_IMETHODIMP nsNavHistoryQuery::SetDomain(const nsACString& aDomain) {
719   mDomain = aDomain;
720   return NS_OK;
721 }
GetHasDomain(bool * _retval)722 NS_IMETHODIMP nsNavHistoryQuery::GetHasDomain(bool* _retval) {
723   // note that empty but not void is still a valid query (local files)
724   *_retval = (!mDomain.IsVoid());
725   return NS_OK;
726 }
727 
GetUri(nsIURI ** aUri)728 NS_IMETHODIMP nsNavHistoryQuery::GetUri(nsIURI** aUri) {
729   NS_IF_ADDREF(*aUri = mUri);
730   return NS_OK;
731 }
SetUri(nsIURI * aUri)732 NS_IMETHODIMP nsNavHistoryQuery::SetUri(nsIURI* aUri) {
733   mUri = aUri;
734   return NS_OK;
735 }
GetHasUri(bool * aHasUri)736 NS_IMETHODIMP nsNavHistoryQuery::GetHasUri(bool* aHasUri) {
737   *aHasUri = (mUri != nullptr);
738   return NS_OK;
739 }
740 
GetAnnotationIsNot(bool * aIsNot)741 NS_IMETHODIMP nsNavHistoryQuery::GetAnnotationIsNot(bool* aIsNot) {
742   *aIsNot = mAnnotationIsNot;
743   return NS_OK;
744 }
SetAnnotationIsNot(bool aIsNot)745 NS_IMETHODIMP nsNavHistoryQuery::SetAnnotationIsNot(bool aIsNot) {
746   mAnnotationIsNot = aIsNot;
747   return NS_OK;
748 }
749 
GetAnnotation(nsACString & aAnnotation)750 NS_IMETHODIMP nsNavHistoryQuery::GetAnnotation(nsACString& aAnnotation) {
751   aAnnotation = mAnnotation;
752   return NS_OK;
753 }
SetAnnotation(const nsACString & aAnnotation)754 NS_IMETHODIMP nsNavHistoryQuery::SetAnnotation(const nsACString& aAnnotation) {
755   mAnnotation = aAnnotation;
756   return NS_OK;
757 }
GetHasAnnotation(bool * aHasIt)758 NS_IMETHODIMP nsNavHistoryQuery::GetHasAnnotation(bool* aHasIt) {
759   *aHasIt = !mAnnotation.IsEmpty();
760   return NS_OK;
761 }
762 
GetTags(nsIVariant ** aTags)763 NS_IMETHODIMP nsNavHistoryQuery::GetTags(nsIVariant** aTags) {
764   NS_ENSURE_ARG_POINTER(aTags);
765 
766   RefPtr<nsVariant> out = new nsVariant();
767 
768   uint32_t arrayLen = mTags.Length();
769 
770   nsresult rv;
771   if (arrayLen == 0)
772     rv = out->SetAsEmptyArray();
773   else {
774     // Note: The resulting nsIVariant dupes both the array and its elements.
775     const char16_t** array = reinterpret_cast<const char16_t**>(
776         moz_xmalloc(arrayLen * sizeof(char16_t*)));
777     for (uint32_t i = 0; i < arrayLen; ++i) {
778       array[i] = mTags[i].get();
779     }
780 
781     rv = out->SetAsArray(nsIDataType::VTYPE_WCHAR_STR, nullptr, arrayLen,
782                          reinterpret_cast<void*>(array));
783     free(array);
784   }
785   NS_ENSURE_SUCCESS(rv, rv);
786 
787   out.forget(aTags);
788   return NS_OK;
789 }
790 
SetTags(nsIVariant * aTags)791 NS_IMETHODIMP nsNavHistoryQuery::SetTags(nsIVariant* aTags) {
792   NS_ENSURE_ARG(aTags);
793 
794   uint16_t dataType = aTags->GetDataType();
795 
796   // Caller passed in empty array.  Easy -- clear our mTags array and return.
797   if (dataType == nsIDataType::VTYPE_EMPTY_ARRAY) {
798     mTags.Clear();
799     return NS_OK;
800   }
801 
802   // Before we go any further, make sure caller passed in an array.
803   NS_ENSURE_TRUE(dataType == nsIDataType::VTYPE_ARRAY, NS_ERROR_ILLEGAL_VALUE);
804 
805   uint16_t eltType;
806   nsIID eltIID;
807   uint32_t arrayLen;
808   void* array;
809 
810   // Convert the nsIVariant to an array.  We own the resulting buffer and its
811   // elements.
812   nsresult rv = aTags->GetAsArray(&eltType, &eltIID, &arrayLen, &array);
813   NS_ENSURE_SUCCESS(rv, rv);
814 
815   // If element type is not wstring, thanks a lot.  Your memory die now.
816   if (eltType != nsIDataType::VTYPE_WCHAR_STR) {
817     switch (eltType) {
818       case nsIDataType::VTYPE_ID:
819       case nsIDataType::VTYPE_CHAR_STR: {
820         char** charArray = reinterpret_cast<char**>(array);
821         for (uint32_t i = 0; i < arrayLen; ++i) {
822           if (charArray[i]) free(charArray[i]);
823         }
824       } break;
825       case nsIDataType::VTYPE_INTERFACE:
826       case nsIDataType::VTYPE_INTERFACE_IS: {
827         nsISupports** supportsArray = reinterpret_cast<nsISupports**>(array);
828         for (uint32_t i = 0; i < arrayLen; ++i) {
829           NS_IF_RELEASE(supportsArray[i]);
830         }
831       } break;
832         // The other types are primitives that do not need to be freed.
833     }
834     free(array);
835     return NS_ERROR_ILLEGAL_VALUE;
836   }
837 
838   char16_t** tags = reinterpret_cast<char16_t**>(array);
839   mTags.Clear();
840 
841   // Finally, add each passed-in tag to our mTags array and then sort it.
842   for (uint32_t i = 0; i < arrayLen; ++i) {
843     // Don't allow nulls.
844     if (!tags[i]) {
845       free(tags);
846       return NS_ERROR_ILLEGAL_VALUE;
847     }
848 
849     nsDependentString tag(tags[i]);
850 
851     // Don't store duplicate tags.  This isn't just to save memory or to be
852     // fancy; the SQL that's built from the tags relies on no dupes.
853     if (!mTags.Contains(tag)) {
854       // XXX(Bug 1631371) Check if this should use a fallible operation as it
855       // pretended earlier.
856       mTags.AppendElement(tag);
857     }
858     free(tags[i]);
859   }
860   free(tags);
861 
862   mTags.Sort();
863 
864   return NS_OK;
865 }
866 
GetTagsAreNot(bool * aTagsAreNot)867 NS_IMETHODIMP nsNavHistoryQuery::GetTagsAreNot(bool* aTagsAreNot) {
868   NS_ENSURE_ARG_POINTER(aTagsAreNot);
869   *aTagsAreNot = mTagsAreNot;
870   return NS_OK;
871 }
872 
SetTagsAreNot(bool aTagsAreNot)873 NS_IMETHODIMP nsNavHistoryQuery::SetTagsAreNot(bool aTagsAreNot) {
874   mTagsAreNot = aTagsAreNot;
875   return NS_OK;
876 }
877 
GetParents(nsTArray<nsCString> & aGuids)878 NS_IMETHODIMP nsNavHistoryQuery::GetParents(nsTArray<nsCString>& aGuids) {
879   aGuids = mParents.Clone();
880   return NS_OK;
881 }
882 
GetParentCount(uint32_t * aGuidCount)883 NS_IMETHODIMP nsNavHistoryQuery::GetParentCount(uint32_t* aGuidCount) {
884   *aGuidCount = mParents.Length();
885   return NS_OK;
886 }
887 
SetParents(const nsTArray<nsCString> & aGuids)888 NS_IMETHODIMP nsNavHistoryQuery::SetParents(const nsTArray<nsCString>& aGuids) {
889   mParents.Clear();
890   if (!mParents.Assign(aGuids, fallible)) {
891     return NS_ERROR_OUT_OF_MEMORY;
892   }
893 
894   return NS_OK;
895 }
896 
GetTransitions(nsTArray<uint32_t> & aTransitions)897 NS_IMETHODIMP nsNavHistoryQuery::GetTransitions(
898     nsTArray<uint32_t>& aTransitions) {
899   aTransitions = mTransitions.Clone();
900   return NS_OK;
901 }
902 
GetTransitionCount(uint32_t * aCount)903 NS_IMETHODIMP nsNavHistoryQuery::GetTransitionCount(uint32_t* aCount) {
904   *aCount = mTransitions.Length();
905   return NS_OK;
906 }
907 
SetTransitions(const nsTArray<uint32_t> & aTransitions)908 NS_IMETHODIMP nsNavHistoryQuery::SetTransitions(
909     const nsTArray<uint32_t>& aTransitions) {
910   if (!mTransitions.Assign(aTransitions, fallible)) {
911     return NS_ERROR_OUT_OF_MEMORY;
912   }
913   return NS_OK;
914 }
915 
916 NS_IMETHODIMP
Clone(nsINavHistoryQuery ** _clone)917 nsNavHistoryQuery::Clone(nsINavHistoryQuery** _clone) {
918   nsNavHistoryQuery* clone = nullptr;
919   Unused << Clone(&clone);
920   *_clone = clone;
921   return NS_OK;
922 }
923 
Clone(nsNavHistoryQuery ** _clone)924 nsresult nsNavHistoryQuery::Clone(nsNavHistoryQuery** _clone) {
925   *_clone = nullptr;
926   RefPtr<nsNavHistoryQuery> clone = new nsNavHistoryQuery(*this);
927   clone.forget(_clone);
928   return NS_OK;
929 }
930 
931 // nsNavHistoryQueryOptions
NS_IMPL_ISUPPORTS(nsNavHistoryQueryOptions,nsNavHistoryQueryOptions,nsINavHistoryQueryOptions)932 NS_IMPL_ISUPPORTS(nsNavHistoryQueryOptions, nsNavHistoryQueryOptions,
933                   nsINavHistoryQueryOptions)
934 
935 nsNavHistoryQueryOptions::nsNavHistoryQueryOptions()
936     : mSort(0),
937       mResultType(0),
938       mExcludeItems(false),
939       mExcludeQueries(false),
940       mExpandQueries(true),
941       mIncludeHidden(false),
942       mMaxResults(0),
943       mQueryType(nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY),
944       mAsyncEnabled(false) {}
945 
nsNavHistoryQueryOptions(const nsNavHistoryQueryOptions & other)946 nsNavHistoryQueryOptions::nsNavHistoryQueryOptions(
947     const nsNavHistoryQueryOptions& other)
948     : mSort(other.mSort),
949       mResultType(other.mResultType),
950       mExcludeItems(other.mExcludeItems),
951       mExcludeQueries(other.mExcludeQueries),
952       mExpandQueries(other.mExpandQueries),
953       mIncludeHidden(other.mIncludeHidden),
954       mMaxResults(other.mMaxResults),
955       mQueryType(other.mQueryType),
956       mAsyncEnabled(other.mAsyncEnabled) {}
957 
958 // sortingMode
959 NS_IMETHODIMP
GetSortingMode(uint16_t * aMode)960 nsNavHistoryQueryOptions::GetSortingMode(uint16_t* aMode) {
961   *aMode = mSort;
962   return NS_OK;
963 }
964 NS_IMETHODIMP
SetSortingMode(uint16_t aMode)965 nsNavHistoryQueryOptions::SetSortingMode(uint16_t aMode) {
966   if (aMode > SORT_BY_FRECENCY_DESCENDING) return NS_ERROR_INVALID_ARG;
967   mSort = aMode;
968   return NS_OK;
969 }
970 
971 // resultType
972 NS_IMETHODIMP
GetResultType(uint16_t * aType)973 nsNavHistoryQueryOptions::GetResultType(uint16_t* aType) {
974   *aType = mResultType;
975   return NS_OK;
976 }
977 NS_IMETHODIMP
SetResultType(uint16_t aType)978 nsNavHistoryQueryOptions::SetResultType(uint16_t aType) {
979   if (aType > RESULTS_AS_LEFT_PANE_QUERY) return NS_ERROR_INVALID_ARG;
980   // Tag queries, containers and the roots query are bookmarks related, so we
981   // set the QueryType accordingly.
982   if (aType == RESULTS_AS_TAGS_ROOT || aType == RESULTS_AS_ROOTS_QUERY ||
983       aType == RESULTS_AS_LEFT_PANE_QUERY) {
984     mQueryType = QUERY_TYPE_BOOKMARKS;
985   }
986   mResultType = aType;
987   return NS_OK;
988 }
989 
990 // excludeItems
991 NS_IMETHODIMP
GetExcludeItems(bool * aExclude)992 nsNavHistoryQueryOptions::GetExcludeItems(bool* aExclude) {
993   *aExclude = mExcludeItems;
994   return NS_OK;
995 }
996 NS_IMETHODIMP
SetExcludeItems(bool aExclude)997 nsNavHistoryQueryOptions::SetExcludeItems(bool aExclude) {
998   mExcludeItems = aExclude;
999   return NS_OK;
1000 }
1001 
1002 // excludeQueries
1003 NS_IMETHODIMP
GetExcludeQueries(bool * aExclude)1004 nsNavHistoryQueryOptions::GetExcludeQueries(bool* aExclude) {
1005   *aExclude = mExcludeQueries;
1006   return NS_OK;
1007 }
1008 NS_IMETHODIMP
SetExcludeQueries(bool aExclude)1009 nsNavHistoryQueryOptions::SetExcludeQueries(bool aExclude) {
1010   mExcludeQueries = aExclude;
1011   return NS_OK;
1012 }
1013 // expandQueries
1014 NS_IMETHODIMP
GetExpandQueries(bool * aExpand)1015 nsNavHistoryQueryOptions::GetExpandQueries(bool* aExpand) {
1016   *aExpand = mExpandQueries;
1017   return NS_OK;
1018 }
1019 NS_IMETHODIMP
SetExpandQueries(bool aExpand)1020 nsNavHistoryQueryOptions::SetExpandQueries(bool aExpand) {
1021   mExpandQueries = aExpand;
1022   return NS_OK;
1023 }
1024 
1025 // includeHidden
1026 NS_IMETHODIMP
GetIncludeHidden(bool * aIncludeHidden)1027 nsNavHistoryQueryOptions::GetIncludeHidden(bool* aIncludeHidden) {
1028   *aIncludeHidden = mIncludeHidden;
1029   return NS_OK;
1030 }
1031 NS_IMETHODIMP
SetIncludeHidden(bool aIncludeHidden)1032 nsNavHistoryQueryOptions::SetIncludeHidden(bool aIncludeHidden) {
1033   mIncludeHidden = aIncludeHidden;
1034   return NS_OK;
1035 }
1036 
1037 // maxResults
1038 NS_IMETHODIMP
GetMaxResults(uint32_t * aMaxResults)1039 nsNavHistoryQueryOptions::GetMaxResults(uint32_t* aMaxResults) {
1040   *aMaxResults = mMaxResults;
1041   return NS_OK;
1042 }
1043 NS_IMETHODIMP
SetMaxResults(uint32_t aMaxResults)1044 nsNavHistoryQueryOptions::SetMaxResults(uint32_t aMaxResults) {
1045   mMaxResults = aMaxResults;
1046   return NS_OK;
1047 }
1048 
1049 // queryType
1050 NS_IMETHODIMP
GetQueryType(uint16_t * _retval)1051 nsNavHistoryQueryOptions::GetQueryType(uint16_t* _retval) {
1052   *_retval = mQueryType;
1053   return NS_OK;
1054 }
1055 NS_IMETHODIMP
SetQueryType(uint16_t aQueryType)1056 nsNavHistoryQueryOptions::SetQueryType(uint16_t aQueryType) {
1057   // Tag query and containers are forced to QUERY_TYPE_BOOKMARKS when the
1058   // resultType is set.
1059   if (mResultType == RESULTS_AS_TAGS_ROOT ||
1060       mResultType == RESULTS_AS_LEFT_PANE_QUERY ||
1061       mResultType == RESULTS_AS_ROOTS_QUERY)
1062     return NS_OK;
1063   mQueryType = aQueryType;
1064   return NS_OK;
1065 }
1066 
1067 // asyncEnabled
1068 NS_IMETHODIMP
GetAsyncEnabled(bool * _asyncEnabled)1069 nsNavHistoryQueryOptions::GetAsyncEnabled(bool* _asyncEnabled) {
1070   *_asyncEnabled = mAsyncEnabled;
1071   return NS_OK;
1072 }
1073 NS_IMETHODIMP
SetAsyncEnabled(bool aAsyncEnabled)1074 nsNavHistoryQueryOptions::SetAsyncEnabled(bool aAsyncEnabled) {
1075   mAsyncEnabled = aAsyncEnabled;
1076   return NS_OK;
1077 }
1078 
1079 NS_IMETHODIMP
Clone(nsINavHistoryQueryOptions ** _clone)1080 nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** _clone) {
1081   nsNavHistoryQueryOptions* clone = nullptr;
1082   Unused << Clone(&clone);
1083   *_clone = clone;
1084   return NS_OK;
1085 }
1086 
Clone(nsNavHistoryQueryOptions ** _clone)1087 nsresult nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions** _clone) {
1088   *_clone = nullptr;
1089   RefPtr<nsNavHistoryQueryOptions> clone = new nsNavHistoryQueryOptions(*this);
1090   clone.forget(_clone);
1091   return NS_OK;
1092 }
1093 
1094 // AppendBoolKeyValueIfTrue
1095 
1096 void  // static
AppendBoolKeyValueIfTrue(nsACString & aString,const nsCString & aName,nsINavHistoryQuery * aQuery,BoolQueryGetter getter)1097 AppendBoolKeyValueIfTrue(nsACString& aString, const nsCString& aName,
1098                          nsINavHistoryQuery* aQuery, BoolQueryGetter getter) {
1099   bool value;
1100   DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1101   NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting boolean value");
1102   if (value) {
1103     AppendAmpersandIfNonempty(aString);
1104     aString += aName;
1105     aString.AppendLiteral("=1");
1106   }
1107 }
1108 
1109 // AppendUint32KeyValueIfNonzero
1110 
1111 void  // static
AppendUint32KeyValueIfNonzero(nsACString & aString,const nsCString & aName,nsINavHistoryQuery * aQuery,Uint32QueryGetter getter)1112 AppendUint32KeyValueIfNonzero(nsACString& aString, const nsCString& aName,
1113                               nsINavHistoryQuery* aQuery,
1114                               Uint32QueryGetter getter) {
1115   uint32_t value;
1116   DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1117   NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value");
1118   if (value) {
1119     AppendAmpersandIfNonempty(aString);
1120     aString += aName;
1121 
1122     // AppendInt requires a concrete string
1123     nsAutoCString appendMe("=");
1124     appendMe.AppendInt(value);
1125     aString.Append(appendMe);
1126   }
1127 }
1128 
1129 // AppendInt64KeyValueIfNonzero
1130 
1131 void  // static
AppendInt64KeyValueIfNonzero(nsACString & aString,const nsCString & aName,nsINavHistoryQuery * aQuery,Int64QueryGetter getter)1132 AppendInt64KeyValueIfNonzero(nsACString& aString, const nsCString& aName,
1133                              nsINavHistoryQuery* aQuery,
1134                              Int64QueryGetter getter) {
1135   PRTime value;
1136   DebugOnly<nsresult> rv = (aQuery->*getter)(&value);
1137   NS_ASSERTION(NS_SUCCEEDED(rv), "Failure getting value");
1138   if (value) {
1139     AppendAmpersandIfNonempty(aString);
1140     aString += aName;
1141     nsAutoCString appendMe("=");
1142     appendMe.AppendInt(static_cast<int64_t>(value));
1143     aString.Append(appendMe);
1144   }
1145 }
1146 
1147 // SetQuery/OptionsKeyBool
1148 
1149 void  // static
SetQueryKeyBool(const nsCString & aValue,nsINavHistoryQuery * aQuery,BoolQuerySetter setter)1150 SetQueryKeyBool(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1151                 BoolQuerySetter setter) {
1152   bool value;
1153   nsresult rv = ParseQueryBooleanString(aValue, &value);
1154   if (NS_SUCCEEDED(rv)) {
1155     rv = (aQuery->*setter)(value);
1156     if (NS_FAILED(rv)) {
1157       NS_WARNING("Error setting boolean key value");
1158     }
1159   } else {
1160     NS_WARNING("Invalid boolean key value in query string.");
1161   }
1162 }
1163 void  // static
SetOptionsKeyBool(const nsCString & aValue,nsINavHistoryQueryOptions * aOptions,BoolOptionsSetter setter)1164 SetOptionsKeyBool(const nsCString& aValue, nsINavHistoryQueryOptions* aOptions,
1165                   BoolOptionsSetter setter) {
1166   bool value = false;
1167   nsresult rv = ParseQueryBooleanString(aValue, &value);
1168   if (NS_SUCCEEDED(rv)) {
1169     rv = (aOptions->*setter)(value);
1170     if (NS_FAILED(rv)) {
1171       NS_WARNING("Error setting boolean key value");
1172     }
1173   } else {
1174     NS_WARNING("Invalid boolean key value in query string.");
1175   }
1176 }
1177 
1178 // SetQuery/OptionsKeyUint32
1179 
1180 void  // static
SetQueryKeyUint32(const nsCString & aValue,nsINavHistoryQuery * aQuery,Uint32QuerySetter setter)1181 SetQueryKeyUint32(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1182                   Uint32QuerySetter setter) {
1183   nsresult rv;
1184   uint32_t value = aValue.ToInteger(&rv);
1185   if (NS_SUCCEEDED(rv)) {
1186     rv = (aQuery->*setter)(value);
1187     if (NS_FAILED(rv)) {
1188       NS_WARNING("Error setting Int32 key value");
1189     }
1190   } else {
1191     NS_WARNING("Invalid Int32 key value in query string.");
1192   }
1193 }
1194 void  // static
SetOptionsKeyUint32(const nsCString & aValue,nsINavHistoryQueryOptions * aOptions,Uint32OptionsSetter setter)1195 SetOptionsKeyUint32(const nsCString& aValue,
1196                     nsINavHistoryQueryOptions* aOptions,
1197                     Uint32OptionsSetter setter) {
1198   nsresult rv;
1199   uint32_t value = aValue.ToInteger(&rv);
1200   if (NS_SUCCEEDED(rv)) {
1201     rv = (aOptions->*setter)(value);
1202     if (NS_FAILED(rv)) {
1203       NS_WARNING("Error setting Int32 key value");
1204     }
1205   } else {
1206     NS_WARNING("Invalid Int32 key value in query string.");
1207   }
1208 }
1209 
1210 void  // static
SetOptionsKeyUint16(const nsCString & aValue,nsINavHistoryQueryOptions * aOptions,Uint16OptionsSetter setter)1211 SetOptionsKeyUint16(const nsCString& aValue,
1212                     nsINavHistoryQueryOptions* aOptions,
1213                     Uint16OptionsSetter setter) {
1214   nsresult rv;
1215   uint16_t value = static_cast<uint16_t>(aValue.ToInteger(&rv));
1216   if (NS_SUCCEEDED(rv)) {
1217     rv = (aOptions->*setter)(value);
1218     if (NS_FAILED(rv)) {
1219       NS_WARNING("Error setting Int16 key value");
1220     }
1221   } else {
1222     NS_WARNING("Invalid Int16 key value in query string.");
1223   }
1224 }
1225 
1226 // SetQueryKeyInt64
1227 
SetQueryKeyInt64(const nsCString & aValue,nsINavHistoryQuery * aQuery,Int64QuerySetter setter)1228 void SetQueryKeyInt64(const nsCString& aValue, nsINavHistoryQuery* aQuery,
1229                       Int64QuerySetter setter) {
1230   nsresult rv;
1231   int64_t value;
1232   if (PR_sscanf(aValue.get(), "%lld", &value) == 1) {
1233     rv = (aQuery->*setter)(value);
1234     if (NS_FAILED(rv)) {
1235       NS_WARNING("Error setting Int64 key value");
1236     }
1237   } else {
1238     NS_WARNING("Invalid Int64 value in query string.");
1239   }
1240 }
1241