1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Annotation Service
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Google Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 2005
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Brett Wilson <brettw@gmail.com> (original author)
24 : * Asaf Romano <mano@mozilla.com>
25 : * Ehsan Akhgari <ehsan.akhgari@gmail.com>
26 : * Marco Bonardo <mak77@bonardo.net>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "mozilla/Util.h"
43 :
44 : #include "nsAnnotationService.h"
45 : #include "nsNavHistory.h"
46 : #include "nsPlacesTables.h"
47 : #include "nsPlacesIndexes.h"
48 : #include "nsPlacesMacros.h"
49 : #include "Helpers.h"
50 :
51 : #include "nsNetUtil.h"
52 : #include "nsIVariant.h"
53 : #include "nsString.h"
54 : #include "nsVariant.h"
55 : #include "mozilla/storage.h"
56 :
57 : #include "sampler.h"
58 :
59 : using namespace mozilla;
60 :
61 : #define ENSURE_ANNO_TYPE(_type, _statement) \
62 : PR_BEGIN_MACRO \
63 : PRInt32 type = _statement->AsInt32(kAnnoIndex_Type); \
64 : NS_ENSURE_TRUE(type == nsIAnnotationService::_type, NS_ERROR_INVALID_ARG); \
65 : PR_END_MACRO
66 :
67 : #define NOTIFY_ANNOS_OBSERVERS(_notification) \
68 : PR_BEGIN_MACRO \
69 : for (PRInt32 i = 0; i < mObservers.Count(); i++) \
70 : mObservers[i]->_notification; \
71 : PR_END_MACRO
72 :
73 : const PRInt32 nsAnnotationService::kAnnoIndex_ID = 0;
74 : const PRInt32 nsAnnotationService::kAnnoIndex_PageOrItem = 1;
75 : const PRInt32 nsAnnotationService::kAnnoIndex_NameID = 2;
76 : const PRInt32 nsAnnotationService::kAnnoIndex_MimeType = 3;
77 : const PRInt32 nsAnnotationService::kAnnoIndex_Content = 4;
78 : const PRInt32 nsAnnotationService::kAnnoIndex_Flags = 5;
79 : const PRInt32 nsAnnotationService::kAnnoIndex_Expiration = 6;
80 : const PRInt32 nsAnnotationService::kAnnoIndex_Type = 7;
81 : const PRInt32 nsAnnotationService::kAnnoIndex_DateAdded = 8;
82 : const PRInt32 nsAnnotationService::kAnnoIndex_LastModified = 9;
83 :
84 : using namespace mozilla::places;
85 :
86 414 : PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsAnnotationService, gAnnotationService)
87 :
88 5940 : NS_IMPL_ISUPPORTS3(nsAnnotationService
89 : , nsIAnnotationService
90 : , nsIObserver
91 : , nsISupportsWeakReference
92 : )
93 :
94 :
95 207 : nsAnnotationService::nsAnnotationService()
96 207 : : mHasSessionAnnotations(false)
97 : {
98 207 : NS_ASSERTION(!gAnnotationService,
99 : "Attempting to create two instances of the service!");
100 207 : gAnnotationService = this;
101 207 : }
102 :
103 :
104 414 : nsAnnotationService::~nsAnnotationService()
105 : {
106 207 : NS_ASSERTION(gAnnotationService == this,
107 : "Deleting a non-singleton instance of the service");
108 207 : if (gAnnotationService == this)
109 207 : gAnnotationService = nsnull;
110 207 : }
111 :
112 :
113 : nsresult
114 207 : nsAnnotationService::Init()
115 : {
116 207 : mDB = Database::GetDatabase();
117 207 : NS_ENSURE_STATE(mDB);
118 :
119 414 : nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
120 207 : if (obsSvc) {
121 207 : (void)obsSvc->AddObserver(this, TOPIC_PLACES_SHUTDOWN, true);
122 : }
123 :
124 207 : return NS_OK;
125 : }
126 :
127 : nsresult
128 693 : nsAnnotationService::SetAnnotationStringInternal(nsIURI* aURI,
129 : PRInt64 aItemId,
130 : const nsACString& aName,
131 : const nsAString& aValue,
132 : PRInt32 aFlags,
133 : PRUint16 aExpiration)
134 : {
135 1386 : mozStorageTransaction transaction(mDB->MainConn(), false);
136 1386 : nsCOMPtr<mozIStorageStatement> statement;
137 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
138 : nsIAnnotationService::TYPE_STRING,
139 693 : statement);
140 693 : NS_ENSURE_SUCCESS(rv, rv);
141 1378 : mozStorageStatementScoper scoper(statement);
142 :
143 689 : rv = statement->BindStringByName(NS_LITERAL_CSTRING("content"), aValue);
144 689 : NS_ENSURE_SUCCESS(rv, rv);
145 689 : rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
146 689 : NS_ENSURE_SUCCESS(rv, rv);
147 :
148 689 : rv = statement->Execute();
149 689 : NS_ENSURE_SUCCESS(rv, rv);
150 :
151 689 : rv = transaction.Commit();
152 689 : NS_ENSURE_SUCCESS(rv, rv);
153 :
154 689 : return NS_OK;
155 : }
156 :
157 :
158 : NS_IMETHODIMP
159 257 : nsAnnotationService::SetPageAnnotation(nsIURI* aURI,
160 : const nsACString& aName,
161 : nsIVariant* aValue,
162 : PRInt32 aFlags,
163 : PRUint16 aExpiration)
164 : {
165 257 : NS_ENSURE_ARG(aURI);
166 256 : NS_ENSURE_ARG(aValue);
167 :
168 : PRUint16 dataType;
169 256 : nsresult rv = aValue->GetDataType(&dataType);
170 256 : NS_ENSURE_SUCCESS(rv, rv);
171 :
172 256 : switch (dataType) {
173 : case nsIDataType::VTYPE_INT8:
174 : case nsIDataType::VTYPE_UINT8:
175 : case nsIDataType::VTYPE_INT16:
176 : case nsIDataType::VTYPE_UINT16:
177 : case nsIDataType::VTYPE_INT32:
178 : case nsIDataType::VTYPE_UINT32:
179 : case nsIDataType::VTYPE_BOOL: {
180 : PRInt32 valueInt;
181 8 : rv = aValue->GetAsInt32(&valueInt);
182 8 : if (NS_SUCCEEDED(rv)) {
183 8 : NS_ENSURE_SUCCESS(rv, rv);
184 8 : rv = SetPageAnnotationInt32(aURI, aName, valueInt, aFlags, aExpiration);
185 8 : NS_ENSURE_SUCCESS(rv, rv);
186 8 : return NS_OK;
187 : }
188 : // Fall through PRInt64 case otherwise.
189 : }
190 : case nsIDataType::VTYPE_INT64:
191 : case nsIDataType::VTYPE_UINT64: {
192 : PRInt64 valueLong;
193 0 : rv = aValue->GetAsInt64(&valueLong);
194 0 : if (NS_SUCCEEDED(rv)) {
195 0 : NS_ENSURE_SUCCESS(rv, rv);
196 0 : rv = SetPageAnnotationInt64(aURI, aName, valueLong, aFlags, aExpiration);
197 0 : NS_ENSURE_SUCCESS(rv, rv);
198 0 : return NS_OK;
199 : }
200 : // Fall through double case otherwise.
201 : }
202 : case nsIDataType::VTYPE_FLOAT:
203 : case nsIDataType::VTYPE_DOUBLE: {
204 : double valueDouble;
205 8 : rv = aValue->GetAsDouble(&valueDouble);
206 8 : NS_ENSURE_SUCCESS(rv, rv);
207 8 : rv = SetPageAnnotationDouble(aURI, aName, valueDouble, aFlags, aExpiration);
208 8 : NS_ENSURE_SUCCESS(rv, rv);
209 8 : return NS_OK;
210 : }
211 : case nsIDataType::VTYPE_CHAR:
212 : case nsIDataType::VTYPE_WCHAR:
213 : case nsIDataType::VTYPE_DOMSTRING:
214 : case nsIDataType::VTYPE_CHAR_STR:
215 : case nsIDataType::VTYPE_WCHAR_STR:
216 : case nsIDataType::VTYPE_STRING_SIZE_IS:
217 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
218 : case nsIDataType::VTYPE_UTF8STRING:
219 : case nsIDataType::VTYPE_CSTRING:
220 : case nsIDataType::VTYPE_ASTRING: {
221 480 : nsAutoString stringValue;
222 240 : rv = aValue->GetAsAString(stringValue);
223 240 : NS_ENSURE_SUCCESS(rv, rv);
224 240 : rv = SetPageAnnotationString(aURI, aName, stringValue, aFlags, aExpiration);
225 240 : NS_ENSURE_SUCCESS(rv, rv);
226 240 : return NS_OK;
227 : }
228 : }
229 :
230 0 : return NS_ERROR_NOT_IMPLEMENTED;
231 : }
232 :
233 :
234 : NS_IMETHODIMP
235 433 : nsAnnotationService::SetItemAnnotation(PRInt64 aItemId,
236 : const nsACString& aName,
237 : nsIVariant* aValue,
238 : PRInt32 aFlags,
239 : PRUint16 aExpiration)
240 : {
241 866 : SAMPLE_LABEL("AnnotationService", "SetItemAnnotation");
242 433 : NS_ENSURE_ARG_MIN(aItemId, 1);
243 430 : NS_ENSURE_ARG(aValue);
244 :
245 430 : if (aExpiration == EXPIRE_WITH_HISTORY)
246 1 : return NS_ERROR_INVALID_ARG;
247 :
248 : PRUint16 dataType;
249 429 : nsresult rv = aValue->GetDataType(&dataType);
250 429 : NS_ENSURE_SUCCESS(rv, rv);
251 :
252 429 : switch (dataType) {
253 : case nsIDataType::VTYPE_INT8:
254 : case nsIDataType::VTYPE_UINT8:
255 : case nsIDataType::VTYPE_INT16:
256 : case nsIDataType::VTYPE_UINT16:
257 : case nsIDataType::VTYPE_INT32:
258 : case nsIDataType::VTYPE_UINT32:
259 : case nsIDataType::VTYPE_BOOL: {
260 : PRInt32 valueInt;
261 86 : rv = aValue->GetAsInt32(&valueInt);
262 86 : if (NS_SUCCEEDED(rv)) {
263 86 : NS_ENSURE_SUCCESS(rv, rv);
264 86 : rv = SetItemAnnotationInt32(aItemId, aName, valueInt, aFlags, aExpiration);
265 86 : NS_ENSURE_SUCCESS(rv, rv);
266 86 : return NS_OK;
267 : }
268 : // Fall through PRInt64 case otherwise.
269 : }
270 : case nsIDataType::VTYPE_INT64:
271 : case nsIDataType::VTYPE_UINT64: {
272 : PRInt64 valueLong;
273 0 : rv = aValue->GetAsInt64(&valueLong);
274 0 : if (NS_SUCCEEDED(rv)) {
275 0 : NS_ENSURE_SUCCESS(rv, rv);
276 0 : rv = SetItemAnnotationInt64(aItemId, aName, valueLong, aFlags, aExpiration);
277 0 : NS_ENSURE_SUCCESS(rv, rv);
278 0 : return NS_OK;
279 : }
280 : // Fall through double case otherwise.
281 : }
282 : case nsIDataType::VTYPE_FLOAT:
283 : case nsIDataType::VTYPE_DOUBLE: {
284 : double valueDouble;
285 2 : rv = aValue->GetAsDouble(&valueDouble);
286 2 : NS_ENSURE_SUCCESS(rv, rv);
287 2 : rv = SetItemAnnotationDouble(aItemId, aName, valueDouble, aFlags, aExpiration);
288 2 : NS_ENSURE_SUCCESS(rv, rv);
289 2 : return NS_OK;
290 : }
291 : case nsIDataType::VTYPE_CHAR:
292 : case nsIDataType::VTYPE_WCHAR:
293 : case nsIDataType::VTYPE_DOMSTRING:
294 : case nsIDataType::VTYPE_CHAR_STR:
295 : case nsIDataType::VTYPE_WCHAR_STR:
296 : case nsIDataType::VTYPE_STRING_SIZE_IS:
297 : case nsIDataType::VTYPE_WSTRING_SIZE_IS:
298 : case nsIDataType::VTYPE_UTF8STRING:
299 : case nsIDataType::VTYPE_CSTRING:
300 : case nsIDataType::VTYPE_ASTRING: {
301 682 : nsAutoString stringValue;
302 341 : rv = aValue->GetAsAString(stringValue);
303 341 : NS_ENSURE_SUCCESS(rv, rv);
304 341 : rv = SetItemAnnotationString(aItemId, aName, stringValue, aFlags, aExpiration);
305 341 : NS_ENSURE_SUCCESS(rv, rv);
306 340 : return NS_OK;
307 : }
308 : }
309 :
310 0 : return NS_ERROR_NOT_IMPLEMENTED;
311 : }
312 :
313 :
314 : NS_IMETHODIMP
315 288 : nsAnnotationService::SetPageAnnotationString(nsIURI* aURI,
316 : const nsACString& aName,
317 : const nsAString& aValue,
318 : PRInt32 aFlags,
319 : PRUint16 aExpiration)
320 : {
321 288 : NS_ENSURE_ARG(aURI);
322 :
323 288 : if (InPrivateBrowsingMode())
324 2 : return NS_OK;
325 :
326 : nsresult rv = SetAnnotationStringInternal(aURI, 0, aName, aValue,
327 286 : aFlags, aExpiration);
328 286 : NS_ENSURE_SUCCESS(rv, rv);
329 :
330 286 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
331 :
332 286 : return NS_OK;
333 : }
334 :
335 :
336 : NS_IMETHODIMP
337 407 : nsAnnotationService::SetItemAnnotationString(PRInt64 aItemId,
338 : const nsACString& aName,
339 : const nsAString& aValue,
340 : PRInt32 aFlags,
341 : PRUint16 aExpiration)
342 : {
343 407 : NS_ENSURE_ARG_MIN(aItemId, 1);
344 :
345 407 : if (aExpiration == EXPIRE_WITH_HISTORY)
346 0 : return NS_ERROR_INVALID_ARG;
347 :
348 : nsresult rv = SetAnnotationStringInternal(nsnull, aItemId, aName, aValue,
349 407 : aFlags, aExpiration);
350 407 : NS_ENSURE_SUCCESS(rv, rv);
351 :
352 403 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
353 :
354 403 : return NS_OK;
355 : }
356 :
357 :
358 : nsresult
359 157 : nsAnnotationService::SetAnnotationInt32Internal(nsIURI* aURI,
360 : PRInt64 aItemId,
361 : const nsACString& aName,
362 : PRInt32 aValue,
363 : PRInt32 aFlags,
364 : PRUint16 aExpiration)
365 : {
366 314 : mozStorageTransaction transaction(mDB->MainConn(), false);
367 314 : nsCOMPtr<mozIStorageStatement> statement;
368 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
369 : nsIAnnotationService::TYPE_INT32,
370 157 : statement);
371 157 : NS_ENSURE_SUCCESS(rv, rv);
372 314 : mozStorageStatementScoper scoper(statement);
373 :
374 157 : rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("content"), aValue);
375 157 : NS_ENSURE_SUCCESS(rv, rv);
376 157 : rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
377 157 : NS_ENSURE_SUCCESS(rv, rv);
378 :
379 157 : rv = statement->Execute();
380 157 : NS_ENSURE_SUCCESS(rv, rv);
381 :
382 157 : rv = transaction.Commit();
383 157 : NS_ENSURE_SUCCESS(rv, rv);
384 :
385 157 : return NS_OK;
386 : }
387 :
388 :
389 : NS_IMETHODIMP
390 8 : nsAnnotationService::SetPageAnnotationInt32(nsIURI* aURI,
391 : const nsACString& aName,
392 : PRInt32 aValue,
393 : PRInt32 aFlags,
394 : PRUint16 aExpiration)
395 : {
396 8 : NS_ENSURE_ARG(aURI);
397 :
398 8 : if (InPrivateBrowsingMode())
399 0 : return NS_OK;
400 :
401 : nsresult rv = SetAnnotationInt32Internal(aURI, 0, aName, aValue,
402 8 : aFlags, aExpiration);
403 8 : NS_ENSURE_SUCCESS(rv, rv);
404 :
405 8 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
406 :
407 8 : return NS_OK;
408 : }
409 :
410 :
411 : NS_IMETHODIMP
412 149 : nsAnnotationService::SetItemAnnotationInt32(PRInt64 aItemId,
413 : const nsACString& aName,
414 : PRInt32 aValue,
415 : PRInt32 aFlags,
416 : PRUint16 aExpiration)
417 : {
418 149 : NS_ENSURE_ARG_MIN(aItemId, 1);
419 :
420 149 : if (aExpiration == EXPIRE_WITH_HISTORY)
421 0 : return NS_ERROR_INVALID_ARG;
422 :
423 : nsresult rv = SetAnnotationInt32Internal(nsnull, aItemId, aName, aValue,
424 149 : aFlags, aExpiration);
425 149 : NS_ENSURE_SUCCESS(rv, rv);
426 :
427 149 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
428 :
429 149 : return NS_OK;
430 : }
431 :
432 :
433 : nsresult
434 0 : nsAnnotationService::SetAnnotationInt64Internal(nsIURI* aURI,
435 : PRInt64 aItemId,
436 : const nsACString& aName,
437 : PRInt64 aValue,
438 : PRInt32 aFlags,
439 : PRUint16 aExpiration)
440 : {
441 0 : mozStorageTransaction transaction(mDB->MainConn(), false);
442 0 : nsCOMPtr<mozIStorageStatement> statement;
443 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
444 : nsIAnnotationService::TYPE_INT64,
445 0 : statement);
446 0 : NS_ENSURE_SUCCESS(rv, rv);
447 0 : mozStorageStatementScoper scoper(statement);
448 :
449 0 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("content"), aValue);
450 0 : NS_ENSURE_SUCCESS(rv, rv);
451 0 : rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
452 0 : NS_ENSURE_SUCCESS(rv, rv);
453 :
454 0 : rv = statement->Execute();
455 0 : NS_ENSURE_SUCCESS(rv, rv);
456 :
457 0 : rv = transaction.Commit();
458 0 : NS_ENSURE_SUCCESS(rv, rv);
459 :
460 0 : return NS_OK;
461 : }
462 :
463 :
464 : NS_IMETHODIMP
465 0 : nsAnnotationService::SetPageAnnotationInt64(nsIURI* aURI,
466 : const nsACString& aName,
467 : PRInt64 aValue,
468 : PRInt32 aFlags,
469 : PRUint16 aExpiration)
470 : {
471 0 : NS_ENSURE_ARG(aURI);
472 :
473 0 : if (InPrivateBrowsingMode())
474 0 : return NS_OK;
475 :
476 : nsresult rv = SetAnnotationInt64Internal(aURI, 0, aName, aValue,
477 0 : aFlags, aExpiration);
478 0 : NS_ENSURE_SUCCESS(rv, rv);
479 :
480 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
481 :
482 0 : return NS_OK;
483 : }
484 :
485 :
486 : NS_IMETHODIMP
487 0 : nsAnnotationService::SetItemAnnotationInt64(PRInt64 aItemId,
488 : const nsACString& aName,
489 : PRInt64 aValue,
490 : PRInt32 aFlags,
491 : PRUint16 aExpiration)
492 : {
493 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
494 :
495 0 : if (aExpiration == EXPIRE_WITH_HISTORY)
496 0 : return NS_ERROR_INVALID_ARG;
497 :
498 : nsresult rv = SetAnnotationInt64Internal(nsnull, aItemId, aName, aValue,
499 0 : aFlags, aExpiration);
500 0 : NS_ENSURE_SUCCESS(rv, rv);
501 :
502 0 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
503 :
504 0 : return NS_OK;
505 : }
506 :
507 :
508 : nsresult
509 10 : nsAnnotationService::SetAnnotationDoubleInternal(nsIURI* aURI,
510 : PRInt64 aItemId,
511 : const nsACString& aName,
512 : double aValue,
513 : PRInt32 aFlags,
514 : PRUint16 aExpiration)
515 : {
516 20 : mozStorageTransaction transaction(mDB->MainConn(), false);
517 20 : nsCOMPtr<mozIStorageStatement> statement;
518 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
519 : nsIAnnotationService::TYPE_DOUBLE,
520 10 : statement);
521 10 : NS_ENSURE_SUCCESS(rv, rv);
522 20 : mozStorageStatementScoper scoper(statement);
523 :
524 10 : rv = statement->BindDoubleByName(NS_LITERAL_CSTRING("content"), aValue);
525 10 : NS_ENSURE_SUCCESS(rv, rv);
526 10 : rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
527 10 : NS_ENSURE_SUCCESS(rv, rv);
528 :
529 10 : rv = statement->Execute();
530 10 : NS_ENSURE_SUCCESS(rv, rv);
531 :
532 10 : rv = transaction.Commit();
533 10 : NS_ENSURE_SUCCESS(rv, rv);
534 :
535 10 : return NS_OK;
536 : }
537 :
538 :
539 : NS_IMETHODIMP
540 8 : nsAnnotationService::SetPageAnnotationDouble(nsIURI* aURI,
541 : const nsACString& aName,
542 : double aValue,
543 : PRInt32 aFlags,
544 : PRUint16 aExpiration)
545 : {
546 8 : NS_ENSURE_ARG(aURI);
547 :
548 8 : if (InPrivateBrowsingMode())
549 0 : return NS_OK;
550 :
551 : nsresult rv = SetAnnotationDoubleInternal(aURI, 0, aName, aValue,
552 8 : aFlags, aExpiration);
553 8 : NS_ENSURE_SUCCESS(rv, rv);
554 :
555 8 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
556 :
557 8 : return NS_OK;
558 : }
559 :
560 :
561 : NS_IMETHODIMP
562 2 : nsAnnotationService::SetItemAnnotationDouble(PRInt64 aItemId,
563 : const nsACString& aName,
564 : double aValue,
565 : PRInt32 aFlags,
566 : PRUint16 aExpiration)
567 : {
568 2 : NS_ENSURE_ARG_MIN(aItemId, 1);
569 :
570 2 : if (aExpiration == EXPIRE_WITH_HISTORY)
571 0 : return NS_ERROR_INVALID_ARG;
572 :
573 : nsresult rv = SetAnnotationDoubleInternal(nsnull, aItemId, aName, aValue,
574 2 : aFlags, aExpiration);
575 2 : NS_ENSURE_SUCCESS(rv, rv);
576 :
577 2 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
578 :
579 2 : return NS_OK;
580 : }
581 :
582 :
583 : nsresult
584 2 : nsAnnotationService::SetAnnotationBinaryInternal(nsIURI* aURI,
585 : PRInt64 aItemId,
586 : const nsACString& aName,
587 : const PRUint8* aData,
588 : PRUint32 aDataLen,
589 : const nsACString& aMimeType,
590 : PRInt32 aFlags,
591 : PRUint16 aExpiration)
592 : {
593 2 : if (aMimeType.Length() == 0)
594 0 : return NS_ERROR_INVALID_ARG;
595 :
596 4 : mozStorageTransaction transaction(mDB->MainConn(), false);
597 4 : nsCOMPtr<mozIStorageStatement> statement;
598 : nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
599 : nsIAnnotationService::TYPE_BINARY,
600 2 : statement);
601 2 : NS_ENSURE_SUCCESS(rv, rv);
602 4 : mozStorageStatementScoper scoper(statement);
603 :
604 2 : rv = statement->BindBlobByName(NS_LITERAL_CSTRING("content"), aData, aDataLen);
605 2 : NS_ENSURE_SUCCESS(rv, rv);
606 2 : rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), aMimeType);
607 2 : NS_ENSURE_SUCCESS(rv, rv);
608 :
609 2 : rv = statement->Execute();
610 2 : NS_ENSURE_SUCCESS(rv, rv);
611 :
612 2 : rv = transaction.Commit();
613 2 : NS_ENSURE_SUCCESS(rv, rv);
614 :
615 2 : return NS_OK;
616 : }
617 :
618 :
619 : NS_IMETHODIMP
620 2 : nsAnnotationService::SetPageAnnotationBinary(nsIURI* aURI,
621 : const nsACString& aName,
622 : const PRUint8* aData,
623 : PRUint32 aDataLen,
624 : const nsACString& aMimeType,
625 : PRInt32 aFlags,
626 : PRUint16 aExpiration)
627 : {
628 2 : NS_ENSURE_ARG(aURI);
629 :
630 1 : if (InPrivateBrowsingMode())
631 0 : return NS_OK;
632 :
633 : nsresult rv = SetAnnotationBinaryInternal(aURI, 0, aName, aData, aDataLen,
634 1 : aMimeType, aFlags, aExpiration);
635 1 : NS_ENSURE_SUCCESS(rv, rv);
636 :
637 1 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aURI, aName));
638 :
639 1 : return NS_OK;
640 : }
641 :
642 :
643 : NS_IMETHODIMP
644 2 : nsAnnotationService::SetItemAnnotationBinary(PRInt64 aItemId,
645 : const nsACString& aName,
646 : const PRUint8* aData,
647 : PRUint32 aDataLen,
648 : const nsACString& aMimeType,
649 : PRInt32 aFlags,
650 : PRUint16 aExpiration)
651 : {
652 2 : NS_ENSURE_ARG_MIN(aItemId, 1);
653 :
654 1 : if (aExpiration == EXPIRE_WITH_HISTORY)
655 0 : return NS_ERROR_INVALID_ARG;
656 :
657 : nsresult rv = SetAnnotationBinaryInternal(nsnull, aItemId, aName, aData,
658 : aDataLen, aMimeType, aFlags,
659 1 : aExpiration);
660 1 : NS_ENSURE_SUCCESS(rv, rv);
661 :
662 1 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aItemId, aName));
663 :
664 1 : return NS_OK;
665 : }
666 :
667 :
668 : NS_IMETHODIMP
669 185 : nsAnnotationService::GetPageAnnotationString(nsIURI* aURI,
670 : const nsACString& aName,
671 : nsAString& _retval)
672 : {
673 185 : NS_ENSURE_ARG(aURI);
674 :
675 370 : nsCOMPtr<mozIStorageStatement> statement;
676 185 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
677 185 : if (NS_FAILED(rv))
678 156 : return rv;
679 :
680 58 : mozStorageStatementScoper scoper(statement);
681 29 : ENSURE_ANNO_TYPE(TYPE_STRING, statement);
682 29 : rv = statement->GetString(kAnnoIndex_Content, _retval);
683 29 : NS_ENSURE_SUCCESS(rv, rv);
684 :
685 29 : return NS_OK;
686 : }
687 :
688 :
689 : NS_IMETHODIMP
690 74 : nsAnnotationService::GetItemAnnotationString(PRInt64 aItemId,
691 : const nsACString& aName,
692 : nsAString& _retval)
693 : {
694 74 : NS_ENSURE_ARG_MIN(aItemId, 1);
695 :
696 148 : nsCOMPtr<mozIStorageStatement> statement;
697 74 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
698 74 : if (NS_FAILED(rv))
699 12 : return rv;
700 :
701 124 : mozStorageStatementScoper scoper(statement);
702 62 : ENSURE_ANNO_TYPE(TYPE_STRING, statement);
703 62 : rv = statement->GetString(kAnnoIndex_Content, _retval);
704 62 : NS_ENSURE_SUCCESS(rv, rv);
705 :
706 62 : return NS_OK;
707 : }
708 :
709 :
710 : NS_IMETHODIMP
711 19 : nsAnnotationService::GetPageAnnotation(nsIURI* aURI,
712 : const nsACString& aName,
713 : nsIVariant** _retval)
714 : {
715 19 : NS_ENSURE_ARG(aURI);
716 18 : NS_ENSURE_ARG_POINTER(_retval);
717 :
718 36 : nsCOMPtr<mozIStorageStatement> statement;
719 18 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
720 18 : if (NS_FAILED(rv))
721 3 : return rv;
722 :
723 30 : mozStorageStatementScoper scoper(statement);
724 :
725 30 : nsCOMPtr<nsIWritableVariant> value = new nsVariant();
726 15 : PRInt32 type = statement->AsInt32(kAnnoIndex_Type);
727 15 : switch (type) {
728 : case nsIAnnotationService::TYPE_INT32:
729 : case nsIAnnotationService::TYPE_INT64:
730 : case nsIAnnotationService::TYPE_DOUBLE: {
731 3 : rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
732 3 : break;
733 : }
734 : case nsIAnnotationService::TYPE_STRING: {
735 24 : nsAutoString valueString;
736 12 : rv = statement->GetString(kAnnoIndex_Content, valueString);
737 12 : if (NS_SUCCEEDED(rv))
738 12 : rv = value->SetAsAString(valueString);
739 : break;
740 : }
741 : case nsIAnnotationService::TYPE_BINARY: {
742 0 : rv = NS_ERROR_INVALID_ARG;
743 0 : break;
744 : }
745 : default: {
746 0 : rv = NS_ERROR_UNEXPECTED;
747 0 : break;
748 : }
749 : }
750 :
751 15 : if (NS_SUCCEEDED(rv))
752 15 : NS_ADDREF(*_retval = value);
753 :
754 15 : return rv;
755 : }
756 :
757 :
758 : NS_IMETHODIMP
759 445 : nsAnnotationService::GetItemAnnotation(PRInt64 aItemId,
760 : const nsACString& aName,
761 : nsIVariant** _retval)
762 : {
763 445 : NS_ENSURE_ARG_MIN(aItemId, 1);
764 443 : NS_ENSURE_ARG_POINTER(_retval);
765 :
766 886 : nsCOMPtr<mozIStorageStatement> statement;
767 443 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
768 443 : if (NS_FAILED(rv))
769 61 : return rv;
770 :
771 764 : mozStorageStatementScoper scoper(statement);
772 :
773 764 : nsCOMPtr<nsIWritableVariant> value = new nsVariant();
774 382 : PRInt32 type = statement->AsInt32(kAnnoIndex_Type);
775 382 : switch (type) {
776 : case nsIAnnotationService::TYPE_INT32:
777 : case nsIAnnotationService::TYPE_INT64:
778 : case nsIAnnotationService::TYPE_DOUBLE: {
779 124 : rv = value->SetAsDouble(statement->AsDouble(kAnnoIndex_Content));
780 124 : break;
781 : }
782 : case nsIAnnotationService::TYPE_STRING: {
783 516 : nsAutoString valueString;
784 258 : rv = statement->GetString(kAnnoIndex_Content, valueString);
785 258 : if (NS_SUCCEEDED(rv))
786 258 : rv = value->SetAsAString(valueString);
787 : break;
788 : }
789 : case nsIAnnotationService::TYPE_BINARY: {
790 0 : rv = NS_ERROR_INVALID_ARG;
791 0 : break;
792 : }
793 : default: {
794 0 : rv = NS_ERROR_UNEXPECTED;
795 0 : break;
796 : }
797 : }
798 :
799 382 : if (NS_SUCCEEDED(rv))
800 382 : NS_ADDREF(*_retval = value);
801 :
802 382 : return rv;
803 : }
804 :
805 :
806 : NS_IMETHODIMP
807 20 : nsAnnotationService::GetPageAnnotationInt32(nsIURI* aURI,
808 : const nsACString& aName,
809 : PRInt32* _retval)
810 : {
811 20 : NS_ENSURE_ARG(aURI);
812 20 : NS_ENSURE_ARG_POINTER(_retval);
813 :
814 40 : nsCOMPtr<mozIStorageStatement> statement;
815 20 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
816 20 : if (NS_FAILED(rv))
817 0 : return rv;
818 :
819 40 : mozStorageStatementScoper scoper(statement);
820 20 : ENSURE_ANNO_TYPE(TYPE_INT32, statement);
821 20 : *_retval = statement->AsInt32(kAnnoIndex_Content);
822 20 : NS_ENSURE_SUCCESS(rv, rv);
823 :
824 20 : return NS_OK;
825 : }
826 :
827 :
828 : NS_IMETHODIMP
829 0 : nsAnnotationService::GetItemAnnotationInt32(PRInt64 aItemId,
830 : const nsACString& aName,
831 : PRInt32* _retval)
832 : {
833 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
834 0 : NS_ENSURE_ARG_POINTER(_retval);
835 :
836 0 : nsCOMPtr<mozIStorageStatement> statement;
837 0 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
838 0 : if (NS_FAILED(rv))
839 0 : return rv;
840 :
841 0 : mozStorageStatementScoper scoper(statement);
842 0 : ENSURE_ANNO_TYPE(TYPE_INT32, statement);
843 0 : *_retval = statement->AsInt32(kAnnoIndex_Content);
844 :
845 0 : return NS_OK;
846 : }
847 :
848 :
849 : NS_IMETHODIMP
850 0 : nsAnnotationService::GetPageAnnotationInt64(nsIURI* aURI,
851 : const nsACString& aName,
852 : PRInt64* _retval)
853 : {
854 0 : NS_ENSURE_ARG(aURI);
855 0 : NS_ENSURE_ARG_POINTER(_retval);
856 :
857 0 : nsCOMPtr<mozIStorageStatement> statement;
858 0 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
859 0 : if (NS_FAILED(rv))
860 0 : return rv;
861 :
862 0 : mozStorageStatementScoper scoper(statement);
863 0 : ENSURE_ANNO_TYPE(TYPE_INT64, statement);
864 0 : *_retval = statement->AsInt64(kAnnoIndex_Content);
865 :
866 0 : return NS_OK;
867 : }
868 :
869 :
870 : NS_IMETHODIMP
871 0 : nsAnnotationService::GetItemAnnotationInt64(PRInt64 aItemId,
872 : const nsACString& aName,
873 : PRInt64* _retval)
874 : {
875 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
876 0 : NS_ENSURE_ARG_POINTER(_retval);
877 :
878 0 : nsCOMPtr<mozIStorageStatement> statement;
879 0 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
880 0 : if (NS_FAILED(rv))
881 0 : return rv;
882 :
883 0 : mozStorageStatementScoper scoper(statement);
884 0 : ENSURE_ANNO_TYPE(TYPE_INT64, statement);
885 0 : *_retval = statement->AsInt64(kAnnoIndex_Content);
886 :
887 0 : return NS_OK;
888 : }
889 :
890 :
891 : NS_IMETHODIMP
892 51 : nsAnnotationService::GetPageAnnotationType(nsIURI* aURI,
893 : const nsACString& aName,
894 : PRUint16* _retval)
895 : {
896 51 : NS_ENSURE_ARG(aURI);
897 50 : NS_ENSURE_ARG_POINTER(_retval);
898 :
899 100 : nsCOMPtr<mozIStorageStatement> statement;
900 50 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
901 50 : if (NS_FAILED(rv))
902 0 : return rv;
903 :
904 100 : mozStorageStatementScoper scoper(statement);
905 50 : *_retval = statement->AsInt32(kAnnoIndex_Type);
906 :
907 50 : return NS_OK;
908 : }
909 :
910 :
911 : NS_IMETHODIMP
912 8 : nsAnnotationService::GetItemAnnotationType(PRInt64 aItemId,
913 : const nsACString& aName,
914 : PRUint16* _retval)
915 : {
916 8 : NS_ENSURE_ARG_MIN(aItemId, 1);
917 7 : NS_ENSURE_ARG_POINTER(_retval);
918 :
919 14 : nsCOMPtr<mozIStorageStatement> statement;
920 7 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
921 7 : if (NS_FAILED(rv))
922 0 : return rv;
923 :
924 14 : mozStorageStatementScoper scoper(statement);
925 7 : *_retval = statement->AsInt32(kAnnoIndex_Type);
926 :
927 7 : return NS_OK;
928 : }
929 :
930 :
931 : NS_IMETHODIMP
932 20 : nsAnnotationService::GetPageAnnotationDouble(nsIURI* aURI,
933 : const nsACString& aName,
934 : double* _retval)
935 : {
936 20 : NS_ENSURE_ARG(aURI);
937 20 : NS_ENSURE_ARG_POINTER(_retval);
938 :
939 40 : nsCOMPtr<mozIStorageStatement> statement;
940 20 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
941 20 : if (NS_FAILED(rv))
942 0 : return rv;
943 :
944 40 : mozStorageStatementScoper scoper(statement);
945 20 : ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
946 20 : *_retval = statement->AsDouble(kAnnoIndex_Content);
947 :
948 20 : return NS_OK;
949 : }
950 :
951 :
952 : NS_IMETHODIMP
953 0 : nsAnnotationService::GetItemAnnotationDouble(PRInt64 aItemId,
954 : const nsACString& aName,
955 : double* _retval)
956 : {
957 0 : NS_ENSURE_ARG_MIN(aItemId, 1);
958 :
959 0 : nsCOMPtr<mozIStorageStatement> statement;
960 0 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
961 0 : if (NS_FAILED(rv))
962 0 : return rv;
963 :
964 0 : mozStorageStatementScoper scoper(statement);
965 0 : ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
966 0 : *_retval = statement->AsDouble(kAnnoIndex_Content);
967 :
968 0 : return NS_OK;
969 : }
970 :
971 :
972 : NS_IMETHODIMP
973 3 : nsAnnotationService::GetPageAnnotationBinary(nsIURI* aURI,
974 : const nsACString& aName,
975 : PRUint8** _data,
976 : PRUint32* _dataLen,
977 : nsACString& _mimeType)
978 : {
979 3 : NS_ENSURE_ARG(aURI);
980 2 : NS_ENSURE_ARG_POINTER(_data);
981 2 : NS_ENSURE_ARG_POINTER(_dataLen);
982 :
983 4 : nsCOMPtr<mozIStorageStatement> statement;
984 2 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
985 2 : if (NS_FAILED(rv))
986 0 : return rv;
987 :
988 4 : mozStorageStatementScoper scoper(statement);
989 2 : ENSURE_ANNO_TYPE(TYPE_BINARY, statement);
990 1 : rv = statement->GetBlob(kAnnoIndex_Content, _dataLen, _data);
991 1 : NS_ENSURE_SUCCESS(rv, rv);
992 1 : rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
993 1 : NS_ENSURE_SUCCESS(rv, rv);
994 :
995 1 : return NS_OK;
996 : }
997 :
998 :
999 : NS_IMETHODIMP
1000 2 : nsAnnotationService::GetItemAnnotationBinary(PRInt64 aItemId,
1001 : const nsACString& aName,
1002 : PRUint8** _data,
1003 : PRUint32* _dataLen,
1004 : nsACString& _mimeType)
1005 : {
1006 2 : NS_ENSURE_ARG_MIN(aItemId, 1);
1007 1 : NS_ENSURE_ARG_POINTER(_data);
1008 1 : NS_ENSURE_ARG_POINTER(_dataLen);
1009 :
1010 2 : nsCOMPtr<mozIStorageStatement> statement;
1011 1 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
1012 1 : if (NS_FAILED(rv))
1013 0 : return rv;
1014 :
1015 2 : mozStorageStatementScoper scoper(statement);
1016 1 : ENSURE_ANNO_TYPE(TYPE_BINARY, statement);
1017 1 : rv = statement->GetBlob(kAnnoIndex_Content, _dataLen, _data);
1018 1 : NS_ENSURE_SUCCESS(rv, rv);
1019 1 : rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
1020 1 : NS_ENSURE_SUCCESS(rv, rv);
1021 :
1022 1 : return NS_OK;
1023 : }
1024 :
1025 :
1026 : NS_IMETHODIMP
1027 6 : nsAnnotationService::GetPageAnnotationInfo(nsIURI* aURI,
1028 : const nsACString& aName,
1029 : PRInt32* _flags,
1030 : PRUint16* _expiration,
1031 : nsACString& _mimeType,
1032 : PRUint16* _storageType)
1033 : {
1034 6 : NS_ENSURE_ARG(aURI);
1035 5 : NS_ENSURE_ARG_POINTER(_flags);
1036 5 : NS_ENSURE_ARG_POINTER(_expiration);
1037 5 : NS_ENSURE_ARG_POINTER(_storageType);
1038 :
1039 10 : nsCOMPtr<mozIStorageStatement> statement;
1040 5 : nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
1041 5 : if (NS_FAILED(rv))
1042 0 : return rv;
1043 :
1044 10 : mozStorageStatementScoper scoper(statement);
1045 5 : *_flags = statement->AsInt32(kAnnoIndex_Flags);
1046 5 : *_expiration = (PRUint16)statement->AsInt32(kAnnoIndex_Expiration);
1047 5 : rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
1048 5 : NS_ENSURE_SUCCESS(rv, rv);
1049 5 : PRInt32 type = (PRUint16)statement->AsInt32(kAnnoIndex_Type);
1050 5 : if (type == 0) {
1051 : // For annotations created before explicit typing,
1052 : // we can't determine type, just return as string type.
1053 0 : *_storageType = nsIAnnotationService::TYPE_STRING;
1054 : }
1055 : else
1056 5 : *_storageType = type;
1057 :
1058 5 : return NS_OK;
1059 : }
1060 :
1061 :
1062 : NS_IMETHODIMP
1063 232 : nsAnnotationService::GetItemAnnotationInfo(PRInt64 aItemId,
1064 : const nsACString& aName,
1065 : PRInt32* _flags,
1066 : PRUint16* _expiration,
1067 : nsACString& _mimeType,
1068 : PRUint16* _storageType)
1069 : {
1070 232 : NS_ENSURE_ARG_MIN(aItemId, 1);
1071 231 : NS_ENSURE_ARG_POINTER(_flags);
1072 231 : NS_ENSURE_ARG_POINTER(_expiration);
1073 231 : NS_ENSURE_ARG_POINTER(_storageType);
1074 :
1075 462 : nsCOMPtr<mozIStorageStatement> statement;
1076 231 : nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
1077 231 : if (NS_FAILED(rv))
1078 0 : return rv;
1079 :
1080 462 : mozStorageStatementScoper scoper(statement);
1081 231 : *_flags = statement->AsInt32(kAnnoIndex_Flags);
1082 231 : *_expiration = (PRUint16)statement->AsInt32(kAnnoIndex_Expiration);
1083 231 : rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
1084 231 : NS_ENSURE_SUCCESS(rv, rv);
1085 231 : PRInt32 type = (PRUint16)statement->AsInt32(kAnnoIndex_Type);
1086 231 : if (type == 0) {
1087 : // For annotations created before explicit typing,
1088 : // we can't determine type, just return as string type.
1089 0 : *_storageType = nsIAnnotationService::TYPE_STRING;
1090 : }
1091 : else {
1092 231 : *_storageType = type;
1093 : }
1094 :
1095 231 : return NS_OK;
1096 : }
1097 :
1098 :
1099 : NS_IMETHODIMP
1100 38 : nsAnnotationService::GetPagesWithAnnotation(const nsACString& aName,
1101 : PRUint32* _resultCount,
1102 : nsIURI*** _results)
1103 : {
1104 38 : NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
1105 37 : NS_ENSURE_ARG_POINTER(_resultCount);
1106 37 : NS_ENSURE_ARG_POINTER(_results);
1107 :
1108 37 : *_resultCount = 0;
1109 37 : *_results = nsnull;
1110 74 : nsCOMArray<nsIURI> results;
1111 :
1112 37 : nsresult rv = GetPagesWithAnnotationCOMArray(aName, &results);
1113 37 : NS_ENSURE_SUCCESS(rv, rv);
1114 :
1115 : // Convert to raw array.
1116 37 : if (results.Count() == 0)
1117 13 : return NS_OK;
1118 :
1119 : *_results = static_cast<nsIURI**>
1120 24 : (nsMemory::Alloc(results.Count() * sizeof(nsIURI*)));
1121 24 : NS_ENSURE_TRUE(*_results, NS_ERROR_OUT_OF_MEMORY);
1122 :
1123 24 : *_resultCount = results.Count();
1124 181 : for (PRUint32 i = 0; i < *_resultCount; i ++) {
1125 157 : (*_results)[i] = results[i];
1126 157 : NS_ADDREF((*_results)[i]);
1127 : }
1128 :
1129 24 : return NS_OK;
1130 : }
1131 :
1132 :
1133 : nsresult
1134 37 : nsAnnotationService::GetPagesWithAnnotationCOMArray(const nsACString& aName,
1135 : nsCOMArray<nsIURI>* _results)
1136 : {
1137 : nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
1138 : "SELECT h.url "
1139 : "FROM moz_anno_attributes n "
1140 : "JOIN moz_annos a ON n.id = a.anno_attribute_id "
1141 : "JOIN moz_places h ON h.id = a.place_id "
1142 : "WHERE n.name = :anno_name"
1143 74 : );
1144 37 : NS_ENSURE_STATE(stmt);
1145 74 : mozStorageStatementScoper scoper(stmt);
1146 :
1147 37 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1148 37 : NS_ENSURE_SUCCESS(rv, rv);
1149 :
1150 37 : bool hasMore = false;
1151 231 : while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) &&
1152 : hasMore) {
1153 314 : nsCAutoString uristring;
1154 157 : rv = stmt->GetUTF8String(0, uristring);
1155 157 : NS_ENSURE_SUCCESS(rv, rv);
1156 :
1157 : // convert to a URI, in case of some invalid URI, just ignore this row
1158 : // so we can mostly continue.
1159 314 : nsCOMPtr<nsIURI> uri;
1160 157 : rv = NS_NewURI(getter_AddRefs(uri), uristring);
1161 157 : if (NS_FAILED(rv))
1162 0 : continue;
1163 :
1164 157 : bool added = _results->AppendObject(uri);
1165 157 : NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
1166 : }
1167 :
1168 37 : return NS_OK;
1169 : }
1170 :
1171 :
1172 : NS_IMETHODIMP
1173 410 : nsAnnotationService::GetItemsWithAnnotation(const nsACString& aName,
1174 : PRUint32* _resultCount,
1175 : PRInt64** _results)
1176 : {
1177 410 : NS_ENSURE_TRUE(!aName.IsEmpty(), NS_ERROR_INVALID_ARG);
1178 409 : NS_ENSURE_ARG_POINTER(_resultCount);
1179 409 : NS_ENSURE_ARG_POINTER(_results);
1180 :
1181 409 : *_resultCount = 0;
1182 409 : *_results = nsnull;
1183 818 : nsTArray<PRInt64> results;
1184 :
1185 409 : nsresult rv = GetItemsWithAnnotationTArray(aName, &results);
1186 409 : NS_ENSURE_SUCCESS(rv, rv);
1187 :
1188 : // Convert to raw array.
1189 409 : if (results.Length() == 0)
1190 228 : return NS_OK;
1191 :
1192 : *_results = static_cast<PRInt64*>
1193 181 : (nsMemory::Alloc(results.Length() * sizeof(PRInt64)));
1194 181 : NS_ENSURE_TRUE(*_results, NS_ERROR_OUT_OF_MEMORY);
1195 :
1196 181 : *_resultCount = results.Length();
1197 504 : for (PRUint32 i = 0; i < *_resultCount; i ++) {
1198 323 : (*_results)[i] = results[i];
1199 : }
1200 :
1201 181 : return NS_OK;
1202 : }
1203 :
1204 :
1205 : nsresult
1206 409 : nsAnnotationService::GetItemsWithAnnotationTArray(const nsACString& aName,
1207 : nsTArray<PRInt64>* _results)
1208 : {
1209 : nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
1210 : "SELECT a.item_id "
1211 : "FROM moz_anno_attributes n "
1212 : "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
1213 : "WHERE n.name = :anno_name"
1214 818 : );
1215 409 : NS_ENSURE_STATE(stmt);
1216 818 : mozStorageStatementScoper scoper(stmt);
1217 :
1218 409 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1219 409 : NS_ENSURE_SUCCESS(rv, rv);
1220 :
1221 409 : bool hasMore = false;
1222 1141 : while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) &&
1223 : hasMore) {
1224 323 : if (!_results->AppendElement(stmt->AsInt64(0)))
1225 0 : return NS_ERROR_OUT_OF_MEMORY;
1226 : }
1227 :
1228 409 : return NS_OK;
1229 : }
1230 :
1231 :
1232 : NS_IMETHODIMP
1233 6 : nsAnnotationService::GetPageAnnotationNames(nsIURI* aURI,
1234 : PRUint32* _count,
1235 : nsIVariant*** _result)
1236 : {
1237 6 : NS_ENSURE_ARG(aURI);
1238 5 : NS_ENSURE_ARG_POINTER(_count);
1239 5 : NS_ENSURE_ARG_POINTER(_result);
1240 :
1241 5 : *_count = 0;
1242 5 : *_result = nsnull;
1243 :
1244 10 : nsTArray<nsCString> names;
1245 5 : nsresult rv = GetAnnotationNamesTArray(aURI, 0, &names);
1246 5 : NS_ENSURE_SUCCESS(rv, rv);
1247 :
1248 5 : if (names.Length() == 0)
1249 0 : return NS_OK;
1250 :
1251 : *_result = static_cast<nsIVariant**>
1252 5 : (nsMemory::Alloc(sizeof(nsIVariant*) * names.Length()));
1253 5 : NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
1254 :
1255 13 : for (PRUint32 i = 0; i < names.Length(); i ++) {
1256 16 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
1257 8 : if (!var) {
1258 : // need to release all the variants we've already created
1259 0 : for (PRUint32 j = 0; j < i; j ++)
1260 0 : NS_RELEASE((*_result)[j]);
1261 0 : nsMemory::Free(*_result);
1262 0 : *_result = nsnull;
1263 0 : return NS_ERROR_OUT_OF_MEMORY;
1264 : }
1265 8 : var->SetAsAUTF8String(names[i]);
1266 16 : NS_ADDREF((*_result)[i] = var);
1267 : }
1268 5 : *_count = names.Length();
1269 :
1270 5 : return NS_OK;
1271 : }
1272 :
1273 :
1274 : nsresult
1275 589 : nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
1276 : PRInt64 aItemId,
1277 : nsTArray<nsCString>* _result)
1278 : {
1279 589 : _result->Clear();
1280 :
1281 589 : bool isItemAnnotation = (aItemId > 0);
1282 1178 : nsCOMPtr<mozIStorageStatement> statement;
1283 589 : if (isItemAnnotation) {
1284 : statement = mDB->GetStatement(
1285 : "SELECT n.name "
1286 : "FROM moz_anno_attributes n "
1287 : "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
1288 : "WHERE a.item_id = :item_id"
1289 584 : );
1290 : }
1291 : else {
1292 : statement = mDB->GetStatement(
1293 : "SELECT n.name "
1294 : "FROM moz_anno_attributes n "
1295 : "JOIN moz_annos a ON a.anno_attribute_id = n.id "
1296 : "JOIN moz_places h ON h.id = a.place_id "
1297 : "WHERE h.url = :page_url"
1298 5 : );
1299 : }
1300 589 : NS_ENSURE_STATE(statement);
1301 1178 : mozStorageStatementScoper scoper(statement);
1302 :
1303 : nsresult rv;
1304 589 : if (isItemAnnotation)
1305 584 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1306 : else
1307 5 : rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1308 589 : NS_ENSURE_SUCCESS(rv, rv);
1309 :
1310 589 : bool hasResult = false;
1311 1420 : while (NS_SUCCEEDED(statement->ExecuteStep(&hasResult)) &&
1312 : hasResult) {
1313 484 : nsCAutoString name;
1314 242 : rv = statement->GetUTF8String(0, name);
1315 242 : NS_ENSURE_SUCCESS(rv, rv);
1316 242 : if (!_result->AppendElement(name))
1317 0 : return NS_ERROR_OUT_OF_MEMORY;
1318 : }
1319 :
1320 589 : return NS_OK;
1321 : }
1322 :
1323 :
1324 : NS_IMETHODIMP
1325 585 : nsAnnotationService::GetItemAnnotationNames(PRInt64 aItemId,
1326 : PRUint32* _count,
1327 : nsIVariant*** _result)
1328 : {
1329 585 : NS_ENSURE_ARG_MIN(aItemId, 1);
1330 584 : NS_ENSURE_ARG_POINTER(_count);
1331 584 : NS_ENSURE_ARG_POINTER(_result);
1332 :
1333 584 : *_count = 0;
1334 584 : *_result = nsnull;
1335 :
1336 1168 : nsTArray<nsCString> names;
1337 584 : nsresult rv = GetAnnotationNamesTArray(nsnull, aItemId, &names);
1338 584 : NS_ENSURE_SUCCESS(rv, rv);
1339 :
1340 584 : if (names.Length() == 0)
1341 461 : return NS_OK;
1342 :
1343 : *_result = static_cast<nsIVariant**>
1344 123 : (nsMemory::Alloc(sizeof(nsIVariant*) * names.Length()));
1345 123 : NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
1346 :
1347 357 : for (PRUint32 i = 0; i < names.Length(); i ++) {
1348 468 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
1349 234 : if (!var) {
1350 : // need to release all the variants we've already created
1351 0 : for (PRUint32 j = 0; j < i; j ++)
1352 0 : NS_RELEASE((*_result)[j]);
1353 0 : nsMemory::Free(*_result);
1354 0 : *_result = nsnull;
1355 0 : return NS_ERROR_OUT_OF_MEMORY;
1356 : }
1357 234 : var->SetAsAUTF8String(names[i]);
1358 468 : NS_ADDREF((*_result)[i] = var);
1359 : }
1360 123 : *_count = names.Length();
1361 :
1362 123 : return NS_OK;
1363 : }
1364 :
1365 :
1366 : NS_IMETHODIMP
1367 71 : nsAnnotationService::PageHasAnnotation(nsIURI* aURI,
1368 : const nsACString& aName,
1369 : bool* _retval)
1370 : {
1371 71 : NS_ENSURE_ARG(aURI);
1372 70 : NS_ENSURE_ARG_POINTER(_retval);
1373 :
1374 70 : nsresult rv = HasAnnotationInternal(aURI, 0, aName, _retval);
1375 70 : NS_ENSURE_SUCCESS(rv, rv);
1376 :
1377 70 : return NS_OK;
1378 : }
1379 :
1380 :
1381 : NS_IMETHODIMP
1382 573 : nsAnnotationService::ItemHasAnnotation(PRInt64 aItemId,
1383 : const nsACString& aName,
1384 : bool* _retval)
1385 : {
1386 573 : NS_ENSURE_ARG_MIN(aItemId, 1);
1387 569 : NS_ENSURE_ARG_POINTER(_retval);
1388 :
1389 569 : nsresult rv = HasAnnotationInternal(nsnull, aItemId, aName, _retval);
1390 569 : NS_ENSURE_SUCCESS(rv, rv);
1391 :
1392 569 : return NS_OK;
1393 : }
1394 :
1395 :
1396 : /**
1397 : * @note We don't remove anything from the moz_anno_attributes table. If we
1398 : * delete the last item of a given name, that item really should go away.
1399 : * It will be cleaned up by expiration.
1400 : */
1401 : nsresult
1402 109 : nsAnnotationService::RemoveAnnotationInternal(nsIURI* aURI,
1403 : PRInt64 aItemId,
1404 : const nsACString& aName)
1405 : {
1406 109 : bool isItemAnnotation = (aItemId > 0);
1407 218 : nsCOMPtr<mozIStorageStatement> statement;
1408 109 : if (isItemAnnotation) {
1409 : statement = mDB->GetStatement(
1410 : "DELETE FROM moz_items_annos "
1411 : "WHERE item_id = :item_id "
1412 : "AND anno_attribute_id = "
1413 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
1414 101 : );
1415 : }
1416 : else {
1417 : statement = mDB->GetStatement(
1418 : "DELETE FROM moz_annos "
1419 : "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
1420 : "AND anno_attribute_id = "
1421 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
1422 8 : );
1423 : }
1424 109 : NS_ENSURE_STATE(statement);
1425 218 : mozStorageStatementScoper scoper(statement);
1426 :
1427 : nsresult rv;
1428 109 : if (isItemAnnotation)
1429 101 : rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1430 : else
1431 8 : rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1432 109 : NS_ENSURE_SUCCESS(rv, rv);
1433 :
1434 109 : rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1435 109 : NS_ENSURE_SUCCESS(rv, rv);
1436 :
1437 109 : rv = statement->Execute();
1438 109 : NS_ENSURE_SUCCESS(rv, rv);
1439 :
1440 109 : return NS_OK;
1441 : }
1442 :
1443 :
1444 : NS_IMETHODIMP
1445 9 : nsAnnotationService::RemovePageAnnotation(nsIURI* aURI,
1446 : const nsACString& aName)
1447 : {
1448 9 : NS_ENSURE_ARG(aURI);
1449 :
1450 8 : nsresult rv = RemoveAnnotationInternal(aURI, 0, aName);
1451 8 : NS_ENSURE_SUCCESS(rv, rv);
1452 :
1453 8 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, aName));
1454 :
1455 8 : return NS_OK;
1456 : }
1457 :
1458 :
1459 : NS_IMETHODIMP
1460 102 : nsAnnotationService::RemoveItemAnnotation(PRInt64 aItemId,
1461 : const nsACString& aName)
1462 : {
1463 102 : NS_ENSURE_ARG_MIN(aItemId, 1);
1464 :
1465 101 : nsresult rv = RemoveAnnotationInternal(nsnull, aItemId, aName);
1466 101 : NS_ENSURE_SUCCESS(rv, rv);
1467 :
1468 101 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, aName));
1469 :
1470 101 : return NS_OK;
1471 : }
1472 :
1473 :
1474 : NS_IMETHODIMP
1475 1 : nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
1476 : {
1477 1 : NS_ENSURE_ARG(aURI);
1478 :
1479 : // Should this be precompiled or a getter?
1480 : nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
1481 : "DELETE FROM moz_annos WHERE place_id = "
1482 : "(SELECT id FROM moz_places WHERE url = :page_url)"
1483 0 : );
1484 0 : NS_ENSURE_STATE(statement);
1485 0 : mozStorageStatementScoper scoper(statement);
1486 :
1487 0 : nsresult rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
1488 0 : NS_ENSURE_SUCCESS(rv, rv);
1489 :
1490 0 : rv = statement->Execute();
1491 0 : NS_ENSURE_SUCCESS(rv, rv);
1492 :
1493 : // Update observers
1494 0 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, EmptyCString()));
1495 :
1496 0 : return NS_OK;
1497 : }
1498 :
1499 :
1500 : NS_IMETHODIMP
1501 177 : nsAnnotationService::RemoveItemAnnotations(PRInt64 aItemId)
1502 : {
1503 177 : NS_ENSURE_ARG_MIN(aItemId, 1);
1504 :
1505 : // Should this be precompiled or a getter?
1506 : nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
1507 : "DELETE FROM moz_items_annos WHERE item_id = :item_id"
1508 352 : );
1509 176 : NS_ENSURE_STATE(statement);
1510 352 : mozStorageStatementScoper scoper(statement);
1511 :
1512 176 : nsresult rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1513 176 : NS_ENSURE_SUCCESS(rv, rv);
1514 :
1515 176 : rv = statement->Execute();
1516 176 : NS_ENSURE_SUCCESS(rv, rv);
1517 :
1518 176 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, EmptyCString()));
1519 :
1520 176 : return NS_OK;
1521 : }
1522 :
1523 :
1524 : /**
1525 : * @note If we use annotations for some standard items like GeckoFlags, it
1526 : * might be a good idea to blacklist these standard annotations from this
1527 : * copy function.
1528 : */
1529 : NS_IMETHODIMP
1530 3 : nsAnnotationService::CopyPageAnnotations(nsIURI* aSourceURI,
1531 : nsIURI* aDestURI,
1532 : bool aOverwriteDest)
1533 : {
1534 3 : NS_ENSURE_ARG(aSourceURI);
1535 2 : NS_ENSURE_ARG(aDestURI);
1536 :
1537 2 : if (InPrivateBrowsingMode())
1538 0 : return NS_OK;
1539 :
1540 4 : mozStorageTransaction transaction(mDB->MainConn(), false);
1541 :
1542 : nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
1543 : "SELECT h.id, n.id, n.name, a2.id "
1544 : "FROM moz_places h "
1545 : "JOIN moz_annos a ON a.place_id = h.id "
1546 : "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
1547 : "LEFT JOIN moz_annos a2 ON a2.place_id = "
1548 : "(SELECT id FROM moz_places WHERE url = :dest_url) "
1549 : "AND a2.anno_attribute_id = n.id "
1550 : "WHERE url = :source_url"
1551 4 : );
1552 2 : NS_ENSURE_STATE(sourceStmt);
1553 4 : mozStorageStatementScoper sourceScoper(sourceStmt);
1554 :
1555 2 : nsresult rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("source_url"), aSourceURI);
1556 2 : NS_ENSURE_SUCCESS(rv, rv);
1557 2 : rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("dest_url"), aDestURI);
1558 2 : NS_ENSURE_SUCCESS(rv, rv);
1559 :
1560 : nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
1561 : "INSERT INTO moz_annos "
1562 : "(place_id, anno_attribute_id, mime_type, content, flags, expiration, "
1563 : "type, dateAdded, lastModified) "
1564 : "SELECT (SELECT id FROM moz_places WHERE url = :page_url), "
1565 : "anno_attribute_id, mime_type, content, flags, expiration, type, "
1566 : ":date, :date "
1567 : "FROM moz_annos "
1568 : "WHERE place_id = :page_id "
1569 : "AND anno_attribute_id = :name_id"
1570 4 : );
1571 2 : NS_ENSURE_STATE(copyStmt);
1572 4 : mozStorageStatementScoper copyScoper(copyStmt);
1573 :
1574 : bool hasResult;
1575 8 : while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
1576 4 : PRInt64 sourcePlaceId = sourceStmt->AsInt64(0);
1577 4 : PRInt64 annoNameID = sourceStmt->AsInt64(1);
1578 8 : nsCAutoString annoName;
1579 4 : rv = sourceStmt->GetUTF8String(2, annoName);
1580 4 : NS_ENSURE_SUCCESS(rv, rv);
1581 4 : PRInt64 annoExistsOnDest = sourceStmt->AsInt64(3);
1582 :
1583 4 : if (annoExistsOnDest) {
1584 3 : if (!aOverwriteDest)
1585 1 : continue;
1586 2 : rv = RemovePageAnnotation(aDestURI, annoName);
1587 2 : NS_ENSURE_SUCCESS(rv, rv);
1588 : }
1589 :
1590 : // Copy the annotation.
1591 6 : mozStorageStatementScoper scoper(copyStmt);
1592 3 : rv = URIBinder::Bind(copyStmt, NS_LITERAL_CSTRING("page_url"), aDestURI);
1593 3 : NS_ENSURE_SUCCESS(rv, rv);
1594 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), sourcePlaceId);
1595 3 : NS_ENSURE_SUCCESS(rv, rv);
1596 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
1597 3 : NS_ENSURE_SUCCESS(rv, rv);
1598 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
1599 3 : NS_ENSURE_SUCCESS(rv, rv);
1600 :
1601 3 : rv = copyStmt->Execute();
1602 3 : NS_ENSURE_SUCCESS(rv, rv);
1603 :
1604 3 : NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationSet(aDestURI, annoName));
1605 : }
1606 :
1607 2 : rv = transaction.Commit();
1608 2 : NS_ENSURE_SUCCESS(rv, rv);
1609 :
1610 2 : return NS_OK;
1611 : }
1612 :
1613 :
1614 : NS_IMETHODIMP
1615 3 : nsAnnotationService::CopyItemAnnotations(PRInt64 aSourceItemId,
1616 : PRInt64 aDestItemId,
1617 : bool aOverwriteDest)
1618 : {
1619 3 : NS_ENSURE_ARG_MIN(aSourceItemId, 1);
1620 2 : NS_ENSURE_ARG_MIN(aDestItemId, 1);
1621 :
1622 4 : mozStorageTransaction transaction(mDB->MainConn(), false);
1623 :
1624 : nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
1625 : "SELECT n.id, n.name, a2.id "
1626 : "FROM moz_bookmarks b "
1627 : "JOIN moz_items_annos a ON a.item_id = b.id "
1628 : "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
1629 : "LEFT JOIN moz_items_annos a2 ON a2.item_id = :dest_item_id "
1630 : "AND a2.anno_attribute_id = n.id "
1631 : "WHERE b.id = :source_item_id"
1632 4 : );
1633 2 : NS_ENSURE_STATE(sourceStmt);
1634 4 : mozStorageStatementScoper sourceScoper(sourceStmt);
1635 :
1636 2 : nsresult rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
1637 2 : NS_ENSURE_SUCCESS(rv, rv);
1638 2 : rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
1639 2 : NS_ENSURE_SUCCESS(rv, rv);
1640 :
1641 : nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
1642 : "INSERT OR REPLACE INTO moz_items_annos "
1643 : "(item_id, anno_attribute_id, mime_type, content, flags, expiration, "
1644 : "type, dateAdded, lastModified) "
1645 : "SELECT :dest_item_id, anno_attribute_id, mime_type, content, flags, expiration, "
1646 : "type, :date, :date "
1647 : "FROM moz_items_annos "
1648 : "WHERE item_id = :source_item_id "
1649 : "AND anno_attribute_id = :name_id"
1650 4 : );
1651 2 : NS_ENSURE_STATE(copyStmt);
1652 4 : mozStorageStatementScoper copyScoper(copyStmt);
1653 :
1654 : bool hasResult;
1655 8 : while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
1656 4 : PRInt64 annoNameID = sourceStmt->AsInt64(0);
1657 8 : nsCAutoString annoName;
1658 4 : rv = sourceStmt->GetUTF8String(1, annoName);
1659 4 : NS_ENSURE_SUCCESS(rv, rv);
1660 4 : PRInt64 annoExistsOnDest = sourceStmt->AsInt64(2);
1661 :
1662 4 : if (annoExistsOnDest) {
1663 3 : if (!aOverwriteDest)
1664 1 : continue;
1665 2 : rv = RemoveItemAnnotation(aDestItemId, annoName);
1666 2 : NS_ENSURE_SUCCESS(rv, rv);
1667 : }
1668 :
1669 : // Copy the annotation.
1670 6 : mozStorageStatementScoper scoper(copyStmt);
1671 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
1672 3 : NS_ENSURE_SUCCESS(rv, rv);
1673 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
1674 3 : NS_ENSURE_SUCCESS(rv, rv);
1675 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), annoNameID);
1676 3 : NS_ENSURE_SUCCESS(rv, rv);
1677 3 : rv = copyStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), PR_Now());
1678 3 : NS_ENSURE_SUCCESS(rv, rv);
1679 :
1680 3 : rv = copyStmt->Execute();
1681 3 : NS_ENSURE_SUCCESS(rv, rv);
1682 :
1683 3 : NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationSet(aDestItemId, annoName));
1684 : }
1685 :
1686 2 : rv = transaction.Commit();
1687 2 : NS_ENSURE_SUCCESS(rv, rv);
1688 :
1689 2 : return NS_OK;
1690 : }
1691 :
1692 :
1693 : NS_IMETHODIMP
1694 199 : nsAnnotationService::AddObserver(nsIAnnotationObserver* aObserver)
1695 : {
1696 199 : NS_ENSURE_ARG(aObserver);
1697 :
1698 198 : if (mObservers.IndexOfObject(aObserver) >= 0)
1699 0 : return NS_ERROR_INVALID_ARG; // Already registered.
1700 198 : if (!mObservers.AppendObject(aObserver))
1701 0 : return NS_ERROR_OUT_OF_MEMORY;
1702 198 : return NS_OK;
1703 : }
1704 :
1705 :
1706 : NS_IMETHODIMP
1707 199 : nsAnnotationService::RemoveObserver(nsIAnnotationObserver* aObserver)
1708 : {
1709 199 : NS_ENSURE_ARG(aObserver);
1710 :
1711 198 : if (!mObservers.RemoveObject(aObserver))
1712 0 : return NS_ERROR_INVALID_ARG;
1713 198 : return NS_OK;
1714 : }
1715 :
1716 :
1717 : // nsAnnotationService::GetAnnotationURI
1718 : //
1719 : // XXX: does not support item-annotations
1720 :
1721 : NS_IMETHODIMP
1722 1 : nsAnnotationService::GetAnnotationURI(nsIURI* aURI,
1723 : const nsACString& aName,
1724 : nsIURI** _result)
1725 : {
1726 1 : if (aName.IsEmpty())
1727 1 : return NS_ERROR_INVALID_ARG;
1728 :
1729 0 : nsCAutoString annoSpec;
1730 0 : nsresult rv = aURI->GetSpec(annoSpec);
1731 0 : NS_ENSURE_SUCCESS(rv, rv);
1732 :
1733 0 : nsCAutoString spec;
1734 0 : spec.AssignLiteral("moz-anno:");
1735 0 : spec += aName;
1736 0 : spec += NS_LITERAL_CSTRING(":");
1737 0 : spec += annoSpec;
1738 :
1739 0 : return NS_NewURI(_result, spec);
1740 : }
1741 :
1742 :
1743 : nsresult
1744 639 : nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
1745 : PRInt64 aItemId,
1746 : const nsACString& aName,
1747 : bool* _hasAnno)
1748 : {
1749 639 : bool isItemAnnotation = (aItemId > 0);
1750 1278 : nsCOMPtr<mozIStorageStatement> stmt;
1751 639 : if (isItemAnnotation) {
1752 : stmt = mDB->GetStatement(
1753 : "SELECT b.id, "
1754 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1755 : "a.id, a.dateAdded "
1756 : "FROM moz_bookmarks b "
1757 : "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
1758 : "AND a.anno_attribute_id = nameid "
1759 : "WHERE b.id = :item_id"
1760 569 : );
1761 : }
1762 : else {
1763 : stmt = mDB->GetStatement(
1764 : "SELECT h.id, "
1765 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1766 : "a.id, a.dateAdded "
1767 : "FROM moz_places h "
1768 : "LEFT JOIN moz_annos a ON a.place_id = h.id "
1769 : "AND a.anno_attribute_id = nameid "
1770 : "WHERE h.url = :page_url"
1771 70 : );
1772 : }
1773 639 : NS_ENSURE_STATE(stmt);
1774 1278 : mozStorageStatementScoper checkAnnoScoper(stmt);
1775 :
1776 639 : nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1777 639 : NS_ENSURE_SUCCESS(rv, rv);
1778 639 : if (isItemAnnotation)
1779 569 : rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1780 : else
1781 70 : rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
1782 639 : NS_ENSURE_SUCCESS(rv, rv);
1783 :
1784 : bool hasResult;
1785 639 : rv = stmt->ExecuteStep(&hasResult);
1786 639 : NS_ENSURE_SUCCESS(rv, rv);
1787 639 : if (!hasResult) {
1788 : // We are trying to get an annotation on an invalid bookmarks or
1789 : // history entry.
1790 : // Here we preserve the old behavior, returning that we don't have the
1791 : // annotation, ignoring the fact itemId is invalid.
1792 : // Otherwise we should return NS_ERROR_INVALID_ARG, but this will somehow
1793 : // break the API. In future we could want to be pickier.
1794 36 : *_hasAnno = false;
1795 : }
1796 : else {
1797 603 : PRInt64 annotationId = stmt->AsInt64(2);
1798 603 : *_hasAnno = (annotationId > 0);
1799 : }
1800 :
1801 639 : return NS_OK;
1802 : }
1803 :
1804 :
1805 : /**
1806 : * This loads the statement and steps it once so you can get data out of it.
1807 : *
1808 : * @note You have to reset the statement when you're done if this succeeds.
1809 : * @throws NS_ERROR_NOT_AVAILABLE if the annotation is not found.
1810 : */
1811 :
1812 : nsresult
1813 1056 : nsAnnotationService::StartGetAnnotation(nsIURI* aURI,
1814 : PRInt64 aItemId,
1815 : const nsACString& aName,
1816 : nsCOMPtr<mozIStorageStatement>& aStatement)
1817 : {
1818 1056 : bool isItemAnnotation = (aItemId > 0);
1819 :
1820 1056 : if (isItemAnnotation) {
1821 : aStatement = mDB->GetStatement(
1822 : "SELECT a.id, a.item_id, :anno_name, a.mime_type, a.content, a.flags, "
1823 : "a.expiration, a.type "
1824 : "FROM moz_anno_attributes n "
1825 : "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
1826 : "WHERE a.item_id = :item_id "
1827 : "AND n.name = :anno_name"
1828 756 : );
1829 : }
1830 : else {
1831 : aStatement = mDB->GetStatement(
1832 : "SELECT a.id, a.place_id, :anno_name, a.mime_type, a.content, a.flags, "
1833 : "a.expiration, a.type "
1834 : "FROM moz_anno_attributes n "
1835 : "JOIN moz_annos a ON n.id = a.anno_attribute_id "
1836 : "JOIN moz_places h ON h.id = a.place_id "
1837 : "WHERE h.url = :page_url "
1838 : "AND n.name = :anno_name"
1839 300 : );
1840 : }
1841 1056 : NS_ENSURE_STATE(aStatement);
1842 2112 : mozStorageStatementScoper getAnnoScoper(aStatement);
1843 :
1844 : nsresult rv;
1845 1056 : if (isItemAnnotation)
1846 756 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1847 : else
1848 300 : rv = URIBinder::Bind(aStatement, NS_LITERAL_CSTRING("page_url"), aURI);
1849 1056 : NS_ENSURE_SUCCESS(rv, rv);
1850 :
1851 1056 : rv = aStatement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1852 1056 : NS_ENSURE_SUCCESS(rv, rv);
1853 :
1854 1056 : bool hasResult = false;
1855 1056 : rv = aStatement->ExecuteStep(&hasResult);
1856 1056 : if (NS_FAILED(rv) || !hasResult)
1857 232 : return NS_ERROR_NOT_AVAILABLE;
1858 :
1859 : // on success, DON'T reset the statement, the caller needs to read from it,
1860 : // and it is the caller's job to reset it.
1861 824 : getAnnoScoper.Abandon();
1862 :
1863 824 : return NS_OK;
1864 : }
1865 :
1866 :
1867 : bool
1868 307 : nsAnnotationService::InPrivateBrowsingMode() const
1869 : {
1870 307 : nsNavHistory* history = nsNavHistory::GetHistoryService();
1871 307 : return history && history->InPrivateBrowsingMode();
1872 : }
1873 :
1874 :
1875 : /**
1876 : * This does most of the setup work needed to set an annotation, except for
1877 : * binding the the actual value and MIME type and executing the statement.
1878 : * It will either update an existing annotation or insert a new one.
1879 : *
1880 : * @note The aStatement RESULT IS NOT ADDREFED. This is just one of the class
1881 : * vars, which control its scope. DO NOT RELEASE.
1882 : * The caller must take care of resetting the statement if this succeeds.
1883 : */
1884 : nsresult
1885 862 : nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
1886 : PRInt64 aItemId,
1887 : const nsACString& aName,
1888 : PRInt32 aFlags,
1889 : PRUint16 aExpiration,
1890 : PRUint16 aType,
1891 : nsCOMPtr<mozIStorageStatement>& aStatement)
1892 : {
1893 862 : bool isItemAnnotation = (aItemId > 0);
1894 :
1895 862 : if (aExpiration == EXPIRE_SESSION) {
1896 92 : mHasSessionAnnotations = true;
1897 : }
1898 :
1899 : // Ensure the annotation name exists.
1900 : nsCOMPtr<mozIStorageStatement> addNameStmt = mDB->GetStatement(
1901 : "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"
1902 1724 : );
1903 862 : NS_ENSURE_STATE(addNameStmt);
1904 1724 : mozStorageStatementScoper scoper(addNameStmt);
1905 :
1906 862 : nsresult rv = addNameStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1907 862 : NS_ENSURE_SUCCESS(rv, rv);
1908 862 : rv = addNameStmt->Execute();
1909 862 : NS_ENSURE_SUCCESS(rv, rv);
1910 :
1911 : // We have to check 2 things:
1912 : // - if the annotation already exists we should update it.
1913 : // - we should not allow setting annotations on invalid URIs or itemIds.
1914 : // This query will tell us:
1915 : // - whether the item or page exists.
1916 : // - whether the annotation already exists.
1917 : // - the nameID associated with the annotation name.
1918 : // - the id and dateAdded of the old annotation, if it exists.
1919 1724 : nsCOMPtr<mozIStorageStatement> stmt;
1920 862 : if (isItemAnnotation) {
1921 : stmt = mDB->GetStatement(
1922 : "SELECT b.id, "
1923 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1924 : "a.id, a.dateAdded "
1925 : "FROM moz_bookmarks b "
1926 : "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
1927 : "AND a.anno_attribute_id = nameid "
1928 : "WHERE b.id = :item_id"
1929 559 : );
1930 : }
1931 : else {
1932 : stmt = mDB->GetStatement(
1933 : "SELECT h.id, "
1934 : "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
1935 : "a.id, a.dateAdded "
1936 : "FROM moz_places h "
1937 : "LEFT JOIN moz_annos a ON a.place_id = h.id "
1938 : "AND a.anno_attribute_id = nameid "
1939 : "WHERE h.url = :page_url"
1940 303 : );
1941 : }
1942 862 : NS_ENSURE_STATE(stmt);
1943 1724 : mozStorageStatementScoper checkAnnoScoper(stmt);
1944 :
1945 862 : rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
1946 862 : NS_ENSURE_SUCCESS(rv, rv);
1947 862 : if (isItemAnnotation)
1948 559 : rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
1949 : else
1950 303 : rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
1951 862 : NS_ENSURE_SUCCESS(rv, rv);
1952 :
1953 : bool hasResult;
1954 862 : rv = stmt->ExecuteStep(&hasResult);
1955 862 : NS_ENSURE_SUCCESS(rv, rv);
1956 862 : if (!hasResult) {
1957 : // We are trying to create an annotation on an invalid bookmark
1958 : // or history entry.
1959 4 : return NS_ERROR_INVALID_ARG;
1960 : }
1961 :
1962 858 : PRInt64 fkId = stmt->AsInt64(0);
1963 858 : PRInt64 nameID = stmt->AsInt64(1);
1964 858 : PRInt64 oldAnnoId = stmt->AsInt64(2);
1965 858 : PRInt64 oldAnnoDate = stmt->AsInt64(3);
1966 :
1967 858 : if (isItemAnnotation) {
1968 : aStatement = mDB->GetStatement(
1969 : "INSERT OR REPLACE INTO moz_items_annos "
1970 : "(id, item_id, anno_attribute_id, mime_type, content, flags, "
1971 : "expiration, type, dateAdded, lastModified) "
1972 : "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
1973 : ":expiration, :type, :date_added, :last_modified)"
1974 555 : );
1975 : }
1976 : else {
1977 : aStatement = mDB->GetStatement(
1978 : "INSERT OR REPLACE INTO moz_annos "
1979 : "(id, place_id, anno_attribute_id, mime_type, content, flags, "
1980 : "expiration, type, dateAdded, lastModified) "
1981 : "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
1982 : ":expiration, :type, :date_added, :last_modified)"
1983 303 : );
1984 : }
1985 858 : NS_ENSURE_STATE(aStatement);
1986 1716 : mozStorageStatementScoper setAnnoScoper(aStatement);
1987 :
1988 : // Don't replace existing annotations.
1989 858 : if (oldAnnoId > 0) {
1990 17 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
1991 17 : NS_ENSURE_SUCCESS(rv, rv);
1992 17 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
1993 17 : NS_ENSURE_SUCCESS(rv, rv);
1994 : }
1995 : else {
1996 841 : rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
1997 841 : NS_ENSURE_SUCCESS(rv, rv);
1998 841 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), PR_Now());
1999 841 : NS_ENSURE_SUCCESS(rv, rv);
2000 : }
2001 :
2002 858 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
2003 858 : NS_ENSURE_SUCCESS(rv, rv);
2004 858 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
2005 858 : NS_ENSURE_SUCCESS(rv, rv);
2006 : // MimeType and Content will be bound by the caller.
2007 858 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
2008 858 : NS_ENSURE_SUCCESS(rv, rv);
2009 858 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
2010 858 : NS_ENSURE_SUCCESS(rv, rv);
2011 858 : rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
2012 858 : NS_ENSURE_SUCCESS(rv, rv);
2013 858 : rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), PR_Now());
2014 858 : NS_ENSURE_SUCCESS(rv, rv);
2015 :
2016 : // on success, leave the statement open, the caller will set the value
2017 : // and MIME type and execute the statement
2018 858 : setAnnoScoper.Abandon();
2019 :
2020 858 : return NS_OK;
2021 : }
2022 :
2023 : ////////////////////////////////////////////////////////////////////////////////
2024 : //// nsIObserver
2025 :
2026 : NS_IMETHODIMP
2027 207 : nsAnnotationService::Observe(nsISupports *aSubject,
2028 : const char *aTopic,
2029 : const PRUnichar *aData)
2030 : {
2031 207 : NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
2032 :
2033 207 : if (strcmp(aTopic, TOPIC_PLACES_SHUTDOWN) == 0) {
2034 : // Remove all session annotations, if any.
2035 207 : if (mHasSessionAnnotations) {
2036 : nsCOMPtr<mozIStorageAsyncStatement> pageAnnoStmt = mDB->GetAsyncStatement(
2037 : "DELETE FROM moz_annos WHERE expiration = :expire_session"
2038 20 : );
2039 10 : NS_ENSURE_STATE(pageAnnoStmt);
2040 20 : nsresult rv = pageAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
2041 10 : EXPIRE_SESSION);
2042 10 : NS_ENSURE_SUCCESS(rv, rv);
2043 :
2044 : nsCOMPtr<mozIStorageAsyncStatement> itemAnnoStmt = mDB->GetAsyncStatement(
2045 : "DELETE FROM moz_items_annos WHERE expiration = :expire_session"
2046 20 : );
2047 10 : NS_ENSURE_STATE(itemAnnoStmt);
2048 20 : rv = itemAnnoStmt->BindInt32ByName(NS_LITERAL_CSTRING("expire_session"),
2049 10 : EXPIRE_SESSION);
2050 10 : NS_ENSURE_SUCCESS(rv, rv);
2051 :
2052 : mozIStorageBaseStatement *stmts[] = {
2053 10 : pageAnnoStmt.get()
2054 10 : , itemAnnoStmt.get()
2055 30 : };
2056 :
2057 20 : nsCOMPtr<mozIStoragePendingStatement> ps;
2058 10 : rv = mDB->MainConn()->ExecuteAsync(stmts, ArrayLength(stmts), nsnull,
2059 10 : getter_AddRefs(ps));
2060 10 : NS_ENSURE_SUCCESS(rv, rv);
2061 : }
2062 : }
2063 :
2064 207 : return NS_OK;
2065 : }
|