Line data Source code
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 : #ifndef nsNavBookmarks_h_
7 : #define nsNavBookmarks_h_
8 :
9 : #include "nsINavBookmarksService.h"
10 : #include "nsIAnnotationService.h"
11 : #include "nsITransaction.h"
12 : #include "nsNavHistory.h"
13 : #include "nsToolkitCompsCID.h"
14 : #include "nsCategoryCache.h"
15 : #include "nsTHashtable.h"
16 : #include "nsWeakReference.h"
17 : #include "mozilla/Attributes.h"
18 : #include "prtime.h"
19 :
20 : class nsNavBookmarks;
21 :
22 : namespace mozilla {
23 : namespace places {
24 :
25 : enum BookmarkStatementId {
26 : DB_FIND_REDIRECTED_BOOKMARK = 0
27 : , DB_GET_BOOKMARKS_FOR_URI
28 : };
29 :
30 4 : struct BookmarkData {
31 : int64_t id;
32 : nsCString url;
33 : nsCString title;
34 : int32_t position;
35 : int64_t placeId;
36 : int64_t parentId;
37 : int64_t grandParentId;
38 : int32_t type;
39 : int32_t syncStatus;
40 : nsCString serviceCID;
41 : PRTime dateAdded;
42 : PRTime lastModified;
43 : nsCString guid;
44 : nsCString parentGuid;
45 : };
46 :
47 4 : struct ItemVisitData {
48 : BookmarkData bookmark;
49 : int64_t visitId;
50 : uint32_t transitionType;
51 : PRTime time;
52 : };
53 :
54 0 : struct ItemChangeData {
55 : BookmarkData bookmark;
56 : nsCString property;
57 : bool isAnnotation;
58 : nsCString newValue;
59 : nsCString oldValue;
60 : };
61 :
62 0 : struct TombstoneData {
63 : nsCString guid;
64 : PRTime dateRemoved;
65 : };
66 :
67 : typedef void (nsNavBookmarks::*ItemVisitMethod)(const ItemVisitData&);
68 : typedef void (nsNavBookmarks::*ItemChangeMethod)(const ItemChangeData&);
69 :
70 : enum BookmarkDate {
71 : DATE_ADDED = 0
72 : , LAST_MODIFIED
73 : };
74 :
75 : } // namespace places
76 : } // namespace mozilla
77 :
78 : class nsNavBookmarks final : public nsINavBookmarksService
79 : , public nsINavHistoryObserver
80 : , public nsIAnnotationObserver
81 : , public nsIObserver
82 : , public nsSupportsWeakReference
83 : {
84 : public:
85 : NS_DECL_ISUPPORTS
86 : NS_DECL_NSINAVBOOKMARKSSERVICE
87 : NS_DECL_NSINAVHISTORYOBSERVER
88 : NS_DECL_NSIANNOTATIONOBSERVER
89 : NS_DECL_NSIOBSERVER
90 :
91 : nsNavBookmarks();
92 :
93 : /**
94 : * Obtains the service's object.
95 : */
96 : static already_AddRefed<nsNavBookmarks> GetSingleton();
97 :
98 : /**
99 : * Initializes the service's object. This should only be called once.
100 : */
101 : nsresult Init();
102 :
103 0 : static nsNavBookmarks* GetBookmarksService() {
104 0 : if (!gBookmarksService) {
105 : nsCOMPtr<nsINavBookmarksService> serv =
106 0 : do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID);
107 0 : NS_ENSURE_TRUE(serv, nullptr);
108 0 : NS_ASSERTION(gBookmarksService,
109 : "Should have static instance pointer now");
110 : }
111 0 : return gBookmarksService;
112 : }
113 :
114 : typedef mozilla::places::BookmarkData BookmarkData;
115 : typedef mozilla::places::ItemVisitData ItemVisitData;
116 : typedef mozilla::places::ItemChangeData ItemChangeData;
117 : typedef mozilla::places::BookmarkStatementId BookmarkStatementId;
118 :
119 : nsresult ResultNodeForContainer(int64_t aID,
120 : nsNavHistoryQueryOptions* aOptions,
121 : nsNavHistoryResultNode** aNode);
122 :
123 : // Find all the children of a folder, using the given query and options.
124 : // For each child, a ResultNode is created and added to |children|.
125 : // The results are ordered by folder position.
126 : nsresult QueryFolderChildren(int64_t aFolderId,
127 : nsNavHistoryQueryOptions* aOptions,
128 : nsCOMArray<nsNavHistoryResultNode>* children);
129 :
130 : /**
131 : * Turns aRow into a node and appends it to aChildren if it is appropriate to
132 : * do so.
133 : *
134 : * @param aRow
135 : * A Storage statement (in the case of synchronous execution) or row of
136 : * a result set (in the case of asynchronous execution).
137 : * @param aOptions
138 : * The options of the parent folder node.
139 : * @param aChildren
140 : * The children of the parent folder node.
141 : * @param aCurrentIndex
142 : * The index of aRow within the results. When called on the first row,
143 : * this should be set to -1.
144 : */
145 : nsresult ProcessFolderNodeRow(mozIStorageValueArray* aRow,
146 : nsNavHistoryQueryOptions* aOptions,
147 : nsCOMArray<nsNavHistoryResultNode>* aChildren,
148 : int32_t& aCurrentIndex);
149 :
150 : /**
151 : * The async version of QueryFolderChildren.
152 : *
153 : * @param aNode
154 : * The folder node that will receive the children.
155 : * @param _pendingStmt
156 : * The Storage pending statement that will be used to control async
157 : * execution.
158 : */
159 : nsresult QueryFolderChildrenAsync(nsNavHistoryFolderResultNode* aNode,
160 : int64_t aFolderId,
161 : mozIStoragePendingStatement** _pendingStmt);
162 :
163 : /**
164 : * @return index of the new folder in aIndex, whether it was passed in or
165 : * generated by autoincrement.
166 : *
167 : * @note If aFolder is -1, uses the autoincrement id for folder index.
168 : * @note aTitle will be truncated to TITLE_LENGTH_MAX
169 : */
170 : nsresult CreateContainerWithID(int64_t aId, int64_t aParent,
171 : const nsACString& aTitle,
172 : bool aIsBookmarkFolder,
173 : int32_t* aIndex,
174 : const nsACString& aGUID,
175 : uint16_t aSource,
176 : int64_t* aNewFolder);
177 :
178 : /**
179 : * Fetches information about the specified id from the database.
180 : *
181 : * @param aItemId
182 : * Id of the item to fetch information for.
183 : * @param aBookmark
184 : * BookmarkData to store the information.
185 : */
186 : nsresult FetchItemInfo(int64_t aItemId,
187 : BookmarkData& _bookmark);
188 :
189 : /**
190 : * Notifies that a bookmark has been visited.
191 : *
192 : * @param aItemId
193 : * The visited item id.
194 : * @param aData
195 : * Details about the new visit.
196 : */
197 : void NotifyItemVisited(const ItemVisitData& aData);
198 :
199 : /**
200 : * Notifies that a bookmark has changed.
201 : *
202 : * @param aItemId
203 : * The changed item id.
204 : * @param aData
205 : * Details about the change.
206 : */
207 : void NotifyItemChanged(const ItemChangeData& aData);
208 :
209 : /**
210 : * Recursively builds an array of descendant folders inside a given folder.
211 : *
212 : * @param aFolderId
213 : * The folder to fetch descendants from.
214 : * @param aDescendantFoldersArray
215 : * Output array to put descendant folders id.
216 : */
217 : nsresult GetDescendantFolders(int64_t aFolderId,
218 : nsTArray<int64_t>& aDescendantFoldersArray);
219 :
220 : static const int32_t kGetChildrenIndex_Guid;
221 : static const int32_t kGetChildrenIndex_Position;
222 : static const int32_t kGetChildrenIndex_Type;
223 : static const int32_t kGetChildrenIndex_PlaceID;
224 : static const int32_t kGetChildrenIndex_SyncStatus;
225 :
226 : static mozilla::Atomic<int64_t> sLastInsertedItemId;
227 : static void StoreLastInsertedId(const nsACString& aTable,
228 : const int64_t aLastInsertedId);
229 :
230 : private:
231 : static nsNavBookmarks* gBookmarksService;
232 :
233 : ~nsNavBookmarks();
234 :
235 : /**
236 : * Checks whether or not aFolderId points to a live bookmark.
237 : *
238 : * @param aFolderId
239 : * the item-id of the folder to check.
240 : * @return true if aFolderId points to live bookmarks, false otherwise.
241 : */
242 : bool IsLivemark(int64_t aFolderId);
243 :
244 : /**
245 : * Locates the root items in the bookmarks folder hierarchy assigning folder
246 : * ids to the root properties that are exposed through the service interface.
247 : */
248 : nsresult EnsureRoots();
249 :
250 : nsresult AdjustIndices(int64_t aFolder,
251 : int32_t aStartIndex,
252 : int32_t aEndIndex,
253 : int32_t aDelta);
254 :
255 : nsresult AdjustSeparatorsSyncCounter(int64_t aFolderId,
256 : int32_t aStartIndex,
257 : int64_t aSyncChangeDelta);
258 :
259 : /**
260 : * Fetches properties of a folder.
261 : *
262 : * @param aFolderId
263 : * Folder to count children for.
264 : * @param _folderCount
265 : * Number of children in the folder.
266 : * @param _guid
267 : * Unique id of the folder.
268 : * @param _parentId
269 : * Id of the parent of the folder.
270 : *
271 : * @throws If folder does not exist.
272 : */
273 : nsresult FetchFolderInfo(int64_t aFolderId,
274 : int32_t* _folderCount,
275 : nsACString& _guid,
276 : int64_t* _parentId);
277 :
278 : nsresult GetLastChildId(int64_t aFolder, int64_t* aItemId);
279 :
280 : nsresult AddSyncChangesForBookmarksWithURL(const nsACString& aURL,
281 : int64_t aSyncChangeDelta);
282 :
283 : // Bumps the change counter for all bookmarks with |aURI|. This is used to
284 : // update tagged bookmarks when adding or changing a tag entry.
285 : nsresult AddSyncChangesForBookmarksWithURI(nsIURI* aURI,
286 : int64_t aSyncChangeDelta);
287 :
288 : // Bumps the change counter for all bookmarked URLs within |aFolderId|. This
289 : // is used to update tagged bookmarks when changing or removing a tag folder.
290 : nsresult AddSyncChangesForBookmarksInFolder(int64_t aFolderId,
291 : int64_t aSyncChangeDelta);
292 :
293 : // Inserts a tombstone for a removed synced item.
294 : nsresult InsertTombstone(const BookmarkData& aBookmark);
295 :
296 : // Inserts tombstones for removed synced items.
297 : nsresult InsertTombstones(const nsTArray<TombstoneData>& aTombstones);
298 :
299 : // Removes a stale synced bookmark tombstone.
300 : nsresult RemoveTombstone(const nsACString& aGUID);
301 :
302 : // Removes the Sync orphan annotation from a synced item, so that Sync doesn't
303 : // try to reparent the item once it sees the original parent. Only synced
304 : // bookmarks should have this anno, but we do this for all bookmarks because
305 : // the anno may be backed up and restored.
306 : nsresult PreventSyncReparenting(const BookmarkData& aBookmark);
307 :
308 : nsresult SetItemTitleInternal(BookmarkData& aBookmark,
309 : const nsACString& aTitle,
310 : int64_t aSyncChangeDelta);
311 :
312 : /**
313 : * This is an handle to the Places database.
314 : */
315 : RefPtr<mozilla::places::Database> mDB;
316 :
317 : int32_t mItemCount;
318 :
319 : nsMaybeWeakPtrArray<nsINavBookmarkObserver> mObservers;
320 :
321 0 : int64_t TagsRootId() {
322 0 : nsresult rv = EnsureRoots();
323 0 : NS_ENSURE_SUCCESS(rv, -1);
324 0 : return mTagsRoot;
325 : }
326 :
327 : // These are lazy loaded, so never access them directly, always use the
328 : // XPIDL getters or TagsRootId().
329 : int64_t mRoot;
330 : int64_t mMenuRoot;
331 : int64_t mTagsRoot;
332 : int64_t mUnfiledRoot;
333 : int64_t mToolbarRoot;
334 : int64_t mMobileRoot;
335 :
336 0 : inline bool IsRoot(int64_t aFolderId) {
337 0 : return aFolderId == mRoot || aFolderId == mMenuRoot ||
338 0 : aFolderId == mTagsRoot || aFolderId == mUnfiledRoot ||
339 0 : aFolderId == mToolbarRoot || aFolderId == mMobileRoot;
340 : }
341 :
342 : nsresult IsBookmarkedInDatabase(int64_t aBookmarkID, bool* aIsBookmarked);
343 :
344 : nsresult SetItemDateInternal(enum mozilla::places::BookmarkDate aDateType,
345 : int64_t aSyncChangeDelta,
346 : int64_t aItemId,
347 : PRTime aValue);
348 :
349 : // Recursive method to build an array of folder's children
350 : nsresult GetDescendantChildren(int64_t aFolderId,
351 : const nsACString& aFolderGuid,
352 : int64_t aGrandParentId,
353 : nsTArray<BookmarkData>& aFolderChildrenArray);
354 :
355 : enum ItemType {
356 : BOOKMARK = TYPE_BOOKMARK,
357 : FOLDER = TYPE_FOLDER,
358 : SEPARATOR = TYPE_SEPARATOR,
359 : };
360 :
361 : /**
362 : * Helper to insert a bookmark in the database.
363 : *
364 : * @param aItemId
365 : * The itemId to insert, pass -1 to generate a new one.
366 : * @param aPlaceId
367 : * The placeId to which this bookmark refers to, pass nullptr for
368 : * items that don't refer to an URI (eg. folders, separators, ...).
369 : * @param aItemType
370 : * The type of the new bookmark, see TYPE_* constants.
371 : * @param aParentId
372 : * The itemId of the parent folder.
373 : * @param aIndex
374 : * The position inside the parent folder.
375 : * @param aTitle
376 : * The title for the new bookmark.
377 : * Pass a void string to set a NULL title.
378 : * @param aDateAdded
379 : * The date for the insertion.
380 : * @param [optional] aLastModified
381 : * The last modified date for the insertion.
382 : * It defaults to aDateAdded.
383 : *
384 : * @return The new item id that has been inserted.
385 : *
386 : * @note This will also update last modified date of the parent folder.
387 : */
388 : nsresult InsertBookmarkInDB(int64_t aPlaceId,
389 : enum ItemType aItemType,
390 : int64_t aParentId,
391 : int32_t aIndex,
392 : const nsACString& aTitle,
393 : PRTime aDateAdded,
394 : PRTime aLastModified,
395 : const nsACString& aParentGuid,
396 : int64_t aGrandParentId,
397 : nsIURI* aURI,
398 : uint16_t aSource,
399 : int64_t* _itemId,
400 : nsACString& _guid);
401 :
402 : /**
403 : * TArray version of getBookmarksIdForURI for ease of use in C++ code.
404 : * Pass in a reference to a TArray; it will get filled with the
405 : * resulting list of bookmark IDs.
406 : *
407 : * @param aURI
408 : * URI to get bookmarks for.
409 : * @param aResult
410 : * Array of bookmark ids.
411 : */
412 : nsresult GetBookmarkIdsForURITArray(nsIURI* aURI,
413 : nsTArray<int64_t>& aResult);
414 :
415 : nsresult GetBookmarksForURI(nsIURI* aURI,
416 : nsTArray<BookmarkData>& _bookmarks);
417 :
418 : int64_t RecursiveFindRedirectedBookmark(int64_t aPlaceId);
419 :
420 : class RemoveFolderTransaction final : public nsITransaction {
421 : public:
422 0 : RemoveFolderTransaction(int64_t aID, uint16_t aSource)
423 0 : : mID(aID)
424 0 : , mSource(aSource)
425 0 : {}
426 :
427 : NS_DECL_ISUPPORTS
428 :
429 0 : NS_IMETHOD DoTransaction() override {
430 0 : nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
431 0 : NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
432 0 : BookmarkData folder;
433 0 : nsresult rv = bookmarks->FetchItemInfo(mID, folder);
434 : // TODO (Bug 656935): store the BookmarkData struct instead.
435 0 : mParent = folder.parentId;
436 0 : mIndex = folder.position;
437 :
438 0 : rv = bookmarks->GetItemTitle(mID, mTitle);
439 0 : NS_ENSURE_SUCCESS(rv, rv);
440 :
441 0 : return bookmarks->RemoveItem(mID, mSource);
442 : }
443 :
444 0 : NS_IMETHOD UndoTransaction() override {
445 0 : nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
446 0 : NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
447 : int64_t newFolder;
448 0 : return bookmarks->CreateContainerWithID(mID, mParent, mTitle, true,
449 0 : &mIndex, EmptyCString(),
450 0 : mSource, &newFolder);
451 : }
452 :
453 0 : NS_IMETHOD RedoTransaction() override {
454 0 : return DoTransaction();
455 : }
456 :
457 0 : NS_IMETHOD GetIsTransient(bool* aResult) override {
458 0 : *aResult = false;
459 0 : return NS_OK;
460 : }
461 :
462 0 : NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aResult) override {
463 0 : *aResult = false;
464 0 : return NS_OK;
465 : }
466 :
467 : private:
468 0 : ~RemoveFolderTransaction() {}
469 :
470 : int64_t mID;
471 : uint16_t mSource;
472 : MOZ_INIT_OUTSIDE_CTOR int64_t mParent;
473 : nsCString mTitle;
474 : MOZ_INIT_OUTSIDE_CTOR int32_t mIndex;
475 : };
476 :
477 : // Used to enable and disable the observer notifications.
478 : bool mCanNotify;
479 : nsCategoryCache<nsINavBookmarkObserver> mCacheObservers;
480 :
481 : // Tracks whether we are in batch mode.
482 : // Note: this is only tracking bookmarks batches, not history ones.
483 : bool mBatching;
484 :
485 : /**
486 : * This function must be called every time a bookmark is removed.
487 : *
488 : * @param aURI
489 : * Uri to test.
490 : */
491 : nsresult UpdateKeywordsForRemovedBookmark(const BookmarkData& aBookmark);
492 : };
493 :
494 : #endif // nsNavBookmarks_h_
|