~ubuntu-branches/ubuntu/oneiric/weave/oneiric

« back to all changes in this revision

Viewing changes to services/sync/modules/engines/history.js

  • Committer: Bazaar Package Importer
  • Author(s): Micah Gersten
  • Date: 2010-08-11 00:35:15 UTC
  • mfrom: (3.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100811003515-o3jbh826bnd1syjv
Tags: 1.4.3-1ubuntu1
* Add -fshort-wchar to CXXFLAGS to fix FTBFS in Ubuntu
  - update debian/rules 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
4
 * The contents of this file are subject to the Mozilla Public License Version
 
5
 * 1.1 (the "License"); you may not use this file except in compliance with
 
6
 * the License. You may obtain a copy of the License at
 
7
 * http://www.mozilla.org/MPL/
 
8
 *
 
9
 * Software distributed under the License is distributed on an "AS IS" basis,
 
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
11
 * for the specific language governing rights and limitations under the
 
12
 * License.
 
13
 *
 
14
 * The Original Code is Weave
 
15
 *
 
16
 * The Initial Developer of the Original Code is Mozilla.
 
17
 * Portions created by the Initial Developer are Copyright (C) 2008
 
18
 * the Initial Developer. All Rights Reserved.
 
19
 *
 
20
 * Contributor(s):
 
21
 *  Dan Mills <thunder@mozilla.com>
 
22
 *
 
23
 * Alternatively, the contents of this file may be used under the terms of
 
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
27
 * of those above. If you wish to allow use of your version of this file only
 
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
29
 * use your version of this file under the terms of the MPL, indicate your
 
30
 * decision by deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
32
 * the provisions above, a recipient may use your version of this file under
 
33
 * the terms of any one of the MPL, the GPL or the LGPL.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
const EXPORTED_SYMBOLS = ['HistoryEngine'];
 
38
 
 
39
const Cc = Components.classes;
 
40
const Ci = Components.interfaces;
 
41
const Cu = Components.utils;
 
42
 
 
43
const GUID_ANNO = "weave/guid";
 
44
 
 
45
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
46
Cu.import("resource://services-sync/engines.js");
 
47
Cu.import("resource://services-sync/stores.js");
 
48
Cu.import("resource://services-sync/trackers.js");
 
49
Cu.import("resource://services-sync/type_records/history.js");
 
50
Cu.import("resource://services-sync/util.js");
 
51
 
 
52
// Create some helper functions to handle GUIDs
 
53
function setGUID(uri, guid) {
 
54
  if (arguments.length == 1)
 
55
    guid = Utils.makeGUID();
 
56
  Utils.anno(uri, GUID_ANNO, guid, "WITH_HISTORY");
 
57
  return guid;
 
58
}
 
59
function GUIDForUri(uri, create) {
 
60
  try {
 
61
    // Use the existing GUID if it exists
 
62
    return Utils.anno(uri, GUID_ANNO);
 
63
  }
 
64
  catch (ex) {
 
65
    // Give the uri a GUID if it doesn't have one
 
66
    if (create)
 
67
      return setGUID(uri);
 
68
  }
 
69
}
 
70
 
 
71
function HistoryEngine() {
 
72
  SyncEngine.call(this, "History");
 
73
}
 
74
HistoryEngine.prototype = {
 
75
  __proto__: SyncEngine.prototype,
 
76
  _recordObj: HistoryRec,
 
77
  _storeObj: HistoryStore,
 
78
  _trackerObj: HistoryTracker,
 
79
 
 
80
  _sync: Utils.batchSync("History", SyncEngine),
 
81
 
 
82
  _findDupe: function _findDupe(item) {
 
83
    return GUIDForUri(item.histUri);
 
84
  }
 
85
};
 
86
 
 
87
function HistoryStore(name) {
 
88
  Store.call(this, name);
 
89
}
 
90
HistoryStore.prototype = {
 
91
  __proto__: Store.prototype,
 
92
 
 
93
  get _hsvc() {
 
94
    let hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
 
95
      getService(Ci.nsINavHistoryService);
 
96
    hsvc.QueryInterface(Ci.nsIGlobalHistory2);
 
97
    hsvc.QueryInterface(Ci.nsIBrowserHistory);
 
98
    hsvc.QueryInterface(Ci.nsPIPlacesDatabase);
 
99
    this.__defineGetter__("_hsvc", function() hsvc);
 
100
    return hsvc;
 
101
  },
 
102
 
 
103
  get _db() {
 
104
    return this._hsvc.DBConnection;
 
105
  },
 
106
 
 
107
  get _visitStm() {
 
108
    this._log.trace("Creating SQL statement: _visitStm");
 
109
    let stm = this._db.createStatement(
 
110
      "SELECT visit_type type, visit_date date " +
 
111
      "FROM moz_historyvisits_view " +
 
112
      "WHERE place_id = (" +
 
113
        "SELECT id " +
 
114
        "FROM moz_places_view " +
 
115
        "WHERE url = :url) " +
 
116
      "ORDER BY date DESC LIMIT 10");
 
117
    this.__defineGetter__("_visitStm", function() stm);
 
118
    return stm;
 
119
  },
 
120
 
 
121
  get _urlStm() {
 
122
    this._log.trace("Creating SQL statement: _urlStm");
 
123
    let stm = this._db.createStatement(
 
124
      "SELECT url, title, frecency " +
 
125
      "FROM moz_places_view " +
 
126
      "WHERE id = (" +
 
127
        "SELECT place_id " +
 
128
        "FROM moz_annos " +
 
129
        "WHERE content = :guid AND anno_attribute_id = (" +
 
130
          "SELECT id " +
 
131
          "FROM moz_anno_attributes " +
 
132
          "WHERE name = '" + GUID_ANNO + "'))");
 
133
    this.__defineGetter__("_urlStm", function() stm);
 
134
    return stm;
 
135
  },
 
136
 
 
137
  get _allUrlStm() {
 
138
    this._log.trace("Creating SQL statement: _allUrlStm");
 
139
    let stm = this._db.createStatement(
 
140
      "SELECT url " +
 
141
      "FROM moz_places_view " +
 
142
      "WHERE last_visit_date > :cutoff_date " +
 
143
      "ORDER BY frecency DESC " +
 
144
      "LIMIT :max_results");
 
145
    this.__defineGetter__("_allUrlStm", function() stm);
 
146
    return stm;
 
147
  },
 
148
 
 
149
  // See bug 320831 for why we use SQL here
 
150
  _getVisits: function HistStore__getVisits(uri) {
 
151
    this._visitStm.params.url = uri;
 
152
    return Utils.queryAsync(this._visitStm, ["date", "type"]);
 
153
  },
 
154
 
 
155
  // See bug 468732 for why we use SQL here
 
156
  _findURLByGUID: function HistStore__findURLByGUID(guid) {
 
157
    this._urlStm.params.guid = guid;
 
158
    return Utils.queryAsync(this._urlStm, ["url", "title", "frecency"])[0];
 
159
  },
 
160
 
 
161
  changeItemID: function HStore_changeItemID(oldID, newID) {
 
162
    setGUID(this._findURLByGUID(oldID).url, newID);
 
163
  },
 
164
 
 
165
 
 
166
  getAllIDs: function HistStore_getAllIDs() {
 
167
    // Only get places visited within the last 30 days (30*24*60*60*1000ms)
 
168
    this._allUrlStm.params.cutoff_date = (Date.now() - 2592000000) * 1000;
 
169
    this._allUrlStm.params.max_results = 5000;
 
170
 
 
171
    let urls = Utils.queryAsync(this._allUrlStm, "url");
 
172
    return urls.reduce(function(ids, item) {
 
173
      ids[GUIDForUri(item.url, true)] = item.url;
 
174
      return ids;
 
175
    }, {});
 
176
  },
 
177
 
 
178
  create: function HistStore_create(record) {
 
179
    // Add the url and set the GUID
 
180
    this.update(record);
 
181
    setGUID(record.histUri, record.id);
 
182
  },
 
183
 
 
184
  remove: function HistStore_remove(record) {
 
185
    let page = this._findURLByGUID(record.id)
 
186
    if (page == null) {
 
187
      this._log.debug("Page already removed: " + record.id);
 
188
      return;
 
189
    }
 
190
 
 
191
    let uri = Utils.makeURI(page.url);
 
192
    Svc.History.removePage(uri);
 
193
    this._log.trace("Removed page: " + [record.id, page.url, page.title]);
 
194
  },
 
195
 
 
196
  update: function HistStore_update(record) {
 
197
    this._log.trace("  -> processing history entry: " + record.histUri);
 
198
 
 
199
    let uri = Utils.makeURI(record.histUri);
 
200
    if (!uri) {
 
201
      this._log.warn("Attempted to process invalid URI, skipping");
 
202
      throw "invalid URI in record";
 
203
    }
 
204
    let curvisits = [];
 
205
    if (this.urlExists(uri))
 
206
      curvisits = this._getVisits(record.histUri);
 
207
 
 
208
    // Add visits if there's no local visit with the same date
 
209
    for each (let {date, type} in record.visits)
 
210
      if (curvisits.every(function(cur) cur.date != date))
 
211
        Svc.History.addVisit(uri, date, null, type, type == 5 || type == 6, 0);
 
212
 
 
213
    this._hsvc.setPageTitle(uri, record.title);
 
214
  },
 
215
 
 
216
  itemExists: function HistStore_itemExists(id) {
 
217
    if (this._findURLByGUID(id))
 
218
      return true;
 
219
    return false;
 
220
  },
 
221
 
 
222
  urlExists: function HistStore_urlExists(url) {
 
223
    if (typeof(url) == "string")
 
224
      url = Utils.makeURI(url);
 
225
    // Don't call isVisited on a null URL to work around crasher bug 492442.
 
226
    return url ? this._hsvc.isVisited(url) : false;
 
227
  },
 
228
 
 
229
  createRecord: function createRecord(guid) {
 
230
    let foo = this._findURLByGUID(guid);
 
231
    let record = new HistoryRec();
 
232
    if (foo) {
 
233
      record.histUri = foo.url;
 
234
      record.title = foo.title;
 
235
      record.sortindex = foo.frecency;
 
236
      record.visits = this._getVisits(record.histUri);
 
237
    }
 
238
    else
 
239
      record.deleted = true;
 
240
 
 
241
    return record;
 
242
  },
 
243
 
 
244
  wipe: function HistStore_wipe() {
 
245
    this._hsvc.removeAllPages();
 
246
  }
 
247
};
 
248
 
 
249
function HistoryTracker(name) {
 
250
  Tracker.call(this, name);
 
251
  Svc.History.addObserver(this, false);
 
252
}
 
253
HistoryTracker.prototype = {
 
254
  __proto__: Tracker.prototype,
 
255
 
 
256
  QueryInterface: XPCOMUtils.generateQI([
 
257
    Ci.nsINavHistoryObserver,
 
258
    Ci.nsINavHistoryObserver_MOZILLA_1_9_1_ADDITIONS
 
259
  ]),
 
260
 
 
261
  onBeginUpdateBatch: function HT_onBeginUpdateBatch() {},
 
262
  onEndUpdateBatch: function HT_onEndUpdateBatch() {},
 
263
  onPageChanged: function HT_onPageChanged() {},
 
264
  onTitleChanged: function HT_onTitleChanged() {},
 
265
 
 
266
  /* Every add or remove is worth 1 point.
 
267
   * Clearing the whole history is worth 50 points (see below)
 
268
   */
 
269
  _upScore: function BMT__upScore() {
 
270
    this.score += 1;
 
271
  },
 
272
 
 
273
  onVisit: function HT_onVisit(uri, vid, time, session, referrer, trans) {
 
274
    if (this.ignoreAll)
 
275
      return;
 
276
    this._log.trace("onVisit: " + uri.spec);
 
277
    if (this.addChangedID(GUIDForUri(uri, true)))
 
278
      this._upScore();
 
279
  },
 
280
  onDeleteVisits: function onDeleteVisits() {
 
281
  },
 
282
  onPageExpired: function HT_onPageExpired(uri, time, entry) {
 
283
  },
 
284
  onBeforeDeleteURI: function onBeforeDeleteURI(uri) {
 
285
    if (this.ignoreAll)
 
286
      return;
 
287
    this._log.trace("onBeforeDeleteURI: " + uri.spec);
 
288
    if (this.addChangedID(GUIDForUri(uri, true)))
 
289
      this._upScore();
 
290
  },
 
291
  onDeleteURI: function HT_onDeleteURI(uri) {
 
292
  },
 
293
  onClearHistory: function HT_onClearHistory() {
 
294
    this._log.trace("onClearHistory");
 
295
    this.score += 500;
 
296
  }
 
297
};