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 "nsNavHistory.h"
11 #include "nsToolkitCompsCID.h"
12 #include "nsCategoryCache.h"
13 #include "nsTHashtable.h"
14 #include "nsWeakReference.h"
15 #include "mozilla/Attributes.h"
16 #include "prtime.h"
17 
18 class nsNavBookmarks;
19 
20 namespace mozilla {
21 namespace places {
22 
23 enum BookmarkStatementId {
24   DB_FIND_REDIRECTED_BOOKMARK = 0,
25   DB_GET_BOOKMARKS_FOR_URI
26 };
27 
28 struct BookmarkData {
29   int64_t id = -1;
30   nsCString url;
31   nsCString title;
32   int32_t position = -1;
33   int64_t placeId = -1;
34   int64_t parentId = -1;
35   int64_t grandParentId = -1;
36   int32_t type = 0;
37   int32_t syncStatus = nsINavBookmarksService::SYNC_STATUS_UNKNOWN;
38   nsCString serviceCID;
39   PRTime dateAdded = 0;
40   PRTime lastModified = 0;
41   nsCString guid;
42   nsCString parentGuid;
43 };
44 
45 struct ItemVisitData {
46   BookmarkData bookmark;
47   int64_t visitId;
48   uint32_t transitionType;
49   PRTime time;
50 };
51 
52 struct ItemChangeData {
53   BookmarkData bookmark;
54   bool isAnnotation = false;
55   bool updateLastModified = false;
56   uint16_t source = nsINavBookmarksService::SOURCE_DEFAULT;
57   nsCString property;
58   nsCString newValue;
59   nsCString oldValue;
60 };
61 
62 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 { LAST_MODIFIED };
71 
72 }  // namespace places
73 }  // namespace mozilla
74 
75 class nsNavBookmarks final : public nsINavBookmarksService,
76                              public nsINavHistoryObserver,
77                              public nsIObserver,
78                              public nsSupportsWeakReference {
79  public:
80   NS_DECL_ISUPPORTS
81   NS_DECL_NSINAVBOOKMARKSSERVICE
82   NS_DECL_NSINAVHISTORYOBSERVER
83   NS_DECL_NSIOBSERVER
84 
85   nsNavBookmarks();
86 
87   /**
88    * Obtains the service's object.
89    */
90   static already_AddRefed<nsNavBookmarks> GetSingleton();
91 
92   /**
93    * Initializes the service's object.  This should only be called once.
94    */
95   nsresult Init();
96 
GetBookmarksService()97   static nsNavBookmarks* GetBookmarksService() {
98     if (!gBookmarksService) {
99       nsCOMPtr<nsINavBookmarksService> serv =
100           do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID);
101       NS_ENSURE_TRUE(serv, nullptr);
102       NS_ASSERTION(gBookmarksService,
103                    "Should have static instance pointer now");
104     }
105     return gBookmarksService;
106   }
107 
108   typedef mozilla::places::BookmarkData BookmarkData;
109   typedef mozilla::places::ItemVisitData ItemVisitData;
110   typedef mozilla::places::ItemChangeData ItemChangeData;
111   typedef mozilla::places::BookmarkStatementId BookmarkStatementId;
112 
113   nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
114                    int64_t aSessionId, int64_t aReferringId,
115                    uint32_t aTransitionType, const nsACString& aGUID,
116                    bool aHidden, uint32_t aVisitCount, uint32_t aTyped,
117                    const nsAString& aLastKnownTitle);
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. These are the options used
139    *        to fill the parent node.
140    * @param aChildren
141    *        The children of the parent folder node.
142    * @param aCurrentIndex
143    *        The index of aRow within the results.  When called on the first row,
144    *        this should be set to -1.
145    */
146   nsresult ProcessFolderNodeRow(mozIStorageValueArray* aRow,
147                                 nsNavHistoryQueryOptions* aOptions,
148                                 nsCOMArray<nsNavHistoryResultNode>* aChildren,
149                                 int32_t& aCurrentIndex);
150 
151   /**
152    * The async version of QueryFolderChildren.
153    *
154    * @param aNode
155    *        The folder node that will receive the children.
156    * @param _pendingStmt
157    *        The Storage pending statement that will be used to control async
158    *        execution.
159    */
160   nsresult QueryFolderChildrenAsync(nsNavHistoryFolderResultNode* aNode,
161                                     mozIStoragePendingStatement** _pendingStmt);
162 
163   /**
164    * Fetches information about the specified id from the database.
165    *
166    * @param aItemId
167    *        Id of the item to fetch information for.
168    * @param aBookmark
169    *        BookmarkData to store the information.
170    */
171   nsresult FetchItemInfo(int64_t aItemId, BookmarkData& _bookmark);
172 
173   /**
174    * Notifies that a bookmark has been visited.
175    *
176    * @param aItemId
177    *        The visited item id.
178    * @param aData
179    *        Details about the new visit.
180    */
181   void NotifyItemVisited(const ItemVisitData& aData);
182 
183   /**
184    * Notifies that a bookmark has changed.
185    *
186    * @param aItemId
187    *        The changed item id.
188    * @param aData
189    *        Details about the change.
190    */
191   void NotifyItemChanged(const ItemChangeData& aData);
192 
193   /**
194    * Recursively builds an array of descendant folders inside a given folder.
195    *
196    * @param aFolderId
197    *        The folder to fetch descendants from.
198    * @param aDescendantFoldersArray
199    *        Output array to put descendant folders id.
200    */
201   nsresult GetDescendantFolders(int64_t aFolderId,
202                                 nsTArray<int64_t>& aDescendantFoldersArray);
203 
204   static const int32_t kGetChildrenIndex_Guid;
205   static const int32_t kGetChildrenIndex_Position;
206   static const int32_t kGetChildrenIndex_Type;
207   static const int32_t kGetChildrenIndex_PlaceID;
208   static const int32_t kGetChildrenIndex_SyncStatus;
209 
210   static mozilla::Atomic<int64_t> sLastInsertedItemId;
211   static void StoreLastInsertedId(const nsACString& aTable,
212                                   const int64_t aLastInsertedId);
213 
214  private:
215   static nsNavBookmarks* gBookmarksService;
216 
217   ~nsNavBookmarks();
218 
219   /**
220    * Checks whether or not aFolderId points to a live bookmark.
221    *
222    * @param aFolderId
223    *        the item-id of the folder to check.
224    * @return true if aFolderId points to live bookmarks, false otherwise.
225    */
226   bool IsLivemark(int64_t aFolderId);
227 
228   /**
229    * Locates the root items in the bookmarks folder hierarchy assigning folder
230    * ids to the root properties that are exposed through the service interface.
231    */
232   nsresult EnsureRoots();
233 
234   nsresult AdjustIndices(int64_t aFolder, int32_t aStartIndex,
235                          int32_t aEndIndex, int32_t aDelta);
236 
237   nsresult AdjustSeparatorsSyncCounter(int64_t aFolderId, int32_t aStartIndex,
238                                        int64_t aSyncChangeDelta);
239 
240   /**
241    * Fetches properties of a folder.
242    *
243    * @param aFolderId
244    *        Folder to count children for.
245    * @param _folderCount
246    *        Number of children in the folder.
247    * @param _guid
248    *        Unique id of the folder.
249    * @param _parentId
250    *        Id of the parent of the folder.
251    *
252    * @throws If folder does not exist.
253    */
254   nsresult FetchFolderInfo(int64_t aFolderId, int32_t* _folderCount,
255                            nsACString& _guid, int64_t* _parentId);
256 
257   nsresult AddSyncChangesForBookmarksWithURL(const nsACString& aURL,
258                                              int64_t aSyncChangeDelta);
259 
260   // Bumps the change counter for all bookmarks with |aURI|. This is used to
261   // update tagged bookmarks when adding or changing a tag entry.
262   nsresult AddSyncChangesForBookmarksWithURI(nsIURI* aURI,
263                                              int64_t aSyncChangeDelta);
264 
265   // Bumps the change counter for all bookmarked URLs within |aFolderId|. This
266   // is used to update tagged bookmarks when changing or removing a tag folder.
267   nsresult AddSyncChangesForBookmarksInFolder(int64_t aFolderId,
268                                               int64_t aSyncChangeDelta);
269 
270   // Inserts a tombstone for a removed synced item.
271   nsresult InsertTombstone(const BookmarkData& aBookmark);
272 
273   // Inserts tombstones for removed synced items.
274   nsresult InsertTombstones(const nsTArray<TombstoneData>& aTombstones);
275 
276   // Removes a stale synced bookmark tombstone.
277   nsresult RemoveTombstone(const nsACString& aGUID);
278 
279   nsresult SetItemTitleInternal(BookmarkData& aBookmark,
280                                 const nsACString& aTitle,
281                                 int64_t aSyncChangeDelta);
282 
283   /**
284    * This is an handle to the Places database.
285    */
286   RefPtr<mozilla::places::Database> mDB;
287 
288   nsMaybeWeakPtrArray<nsINavBookmarkObserver> mObservers;
289 
TagsRootId()290   int64_t TagsRootId() {
291     nsresult rv = EnsureRoots();
292     NS_ENSURE_SUCCESS(rv, -1);
293     return mTagsRoot;
294   }
295 
296   // These are lazy loaded, so never access them directly, always use the
297   // XPIDL getters or TagsRootId().
298   int64_t mRoot;
299   int64_t mMenuRoot;
300   int64_t mTagsRoot;
301   int64_t mUnfiledRoot;
302   int64_t mToolbarRoot;
303   int64_t mMobileRoot;
304 
IsRoot(int64_t aFolderId)305   inline bool IsRoot(int64_t aFolderId) {
306     return aFolderId == mRoot || aFolderId == mMenuRoot ||
307            aFolderId == mTagsRoot || aFolderId == mUnfiledRoot ||
308            aFolderId == mToolbarRoot || aFolderId == mMobileRoot;
309   }
310 
311   nsresult SetItemDateInternal(enum mozilla::places::BookmarkDate aDateType,
312                                int64_t aSyncChangeDelta, int64_t aItemId,
313                                PRTime aValue);
314 
315   nsresult RemoveFolderChildren(int64_t aFolderId, uint16_t aSource);
316 
317   // Recursive method to build an array of folder's children
318   nsresult GetDescendantChildren(int64_t aFolderId,
319                                  const nsACString& aFolderGuid,
320                                  int64_t aGrandParentId,
321                                  nsTArray<BookmarkData>& aFolderChildrenArray);
322 
323   enum ItemType {
324     BOOKMARK = TYPE_BOOKMARK,
325     FOLDER = TYPE_FOLDER,
326     SEPARATOR = TYPE_SEPARATOR,
327   };
328 
329   /**
330    * Helper to insert a bookmark in the database.
331    *
332    *  @param aItemId
333    *         The itemId to insert, pass -1 to generate a new one.
334    *  @param aPlaceId
335    *         The placeId to which this bookmark refers to, pass nullptr for
336    *         items that don't refer to an URI (eg. folders, separators, ...).
337    *  @param aItemType
338    *         The type of the new bookmark, see TYPE_* constants.
339    *  @param aParentId
340    *         The itemId of the parent folder.
341    *  @param aIndex
342    *         The position inside the parent folder.
343    *  @param aTitle
344    *         The title for the new bookmark.
345    *         Pass a void string to set a NULL title.
346    *  @param aDateAdded
347    *         The date for the insertion.
348    *  @param [optional] aLastModified
349    *         The last modified date for the insertion.
350    *         It defaults to aDateAdded.
351    *
352    *  @return The new item id that has been inserted.
353    *
354    *  @note This will also update last modified date of the parent folder.
355    */
356   nsresult InsertBookmarkInDB(int64_t aPlaceId, enum ItemType aItemType,
357                               int64_t aParentId, int32_t aIndex,
358                               const nsACString& aTitle, PRTime aDateAdded,
359                               PRTime aLastModified,
360                               const nsACString& aParentGuid,
361                               int64_t aGrandParentId, nsIURI* aURI,
362                               uint16_t aSource, int64_t* _itemId,
363                               nsACString& _guid);
364 
365   nsresult GetBookmarksForURI(nsIURI* aURI, nsTArray<BookmarkData>& _bookmarks);
366 
367   // Used to enable and disable the observer notifications.
368   bool mCanNotify;
369 
370   // Tracks whether we are in batch mode.
371   // Note: this is only tracking bookmarks batches, not history ones.
372   bool mBatching;
373 };
374 
375 #endif  // nsNavBookmarks_h_
376