1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/history/history_publisher.h"
6
7#include <atlsafe.h>
8#include <objbase.h>
9#include <oleauto.h>
10#include <wtypes.h>
11
12#include "base/string_util.h"
13#include "base/time.h"
14#include "base/utf_string_conversions.h"
15#include "base/win/registry.h"
16#include "base/win/scoped_bstr.h"
17#include "base/win/scoped_comptr.h"
18#include "base/win/scoped_variant.h"
19#include "googleurl/src/gurl.h"
20
21namespace {
22
23// Instantiates a IChromeHistoryIndexer COM object. Takes a COM class id
24// in |name| and returns the object in |indexer|. Returns false if the
25// operation fails.
26bool CoCreateIndexerFromName(const wchar_t* name,
27                             IChromeHistoryIndexer** indexer) {
28  CLSID clsid;
29  HRESULT hr = CLSIDFromString(const_cast<wchar_t*>(name), &clsid);
30  if (FAILED(hr))
31    return false;
32  hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC,
33                        __uuidof(IChromeHistoryIndexer),
34                        reinterpret_cast<void**>(indexer));
35  if (FAILED(hr))
36    return false;
37  return true;
38}
39
40// Instantiates the registered indexers from the registry |root| + |path| key
41// and adds them to the |indexers| list.
42void AddRegisteredIndexers(HKEY root, const wchar_t* path,
43    std::vector< base::win::ScopedComPtr<IChromeHistoryIndexer> >* indexers) {
44  IChromeHistoryIndexer* indexer;
45  base::win::RegistryKeyIterator r_iter(root, path);
46  while (r_iter.Valid()) {
47    if (CoCreateIndexerFromName(r_iter.Name(), &indexer)) {
48      indexers->push_back(
49          base::win::ScopedComPtr<IChromeHistoryIndexer>(indexer));
50      indexer->Release();
51    }
52    ++r_iter;
53  }
54}
55
56}  // namespace
57
58namespace history {
59
60const wchar_t* const HistoryPublisher::kRegKeyRegisteredIndexersInfo =
61    L"Software\\Google\\Google Chrome\\IndexerPlugins";
62
63// static
64double HistoryPublisher::TimeToUTCVariantTime(const base::Time& time) {
65  double var_time = 0;
66  if (!time.is_null()) {
67    base::Time::Exploded exploded;
68    time.UTCExplode(&exploded);
69
70    // Create the system time struct representing our exploded time.
71    SYSTEMTIME system_time;
72    system_time.wYear = exploded.year;
73    system_time.wMonth = exploded.month;
74    system_time.wDayOfWeek = exploded.day_of_week;
75    system_time.wDay = exploded.day_of_month;
76    system_time.wHour = exploded.hour;
77    system_time.wMinute = exploded.minute;
78    system_time.wSecond = exploded.second;
79    system_time.wMilliseconds = exploded.millisecond;
80    SystemTimeToVariantTime(&system_time, &var_time);
81  }
82
83  return var_time;
84}
85
86HistoryPublisher::HistoryPublisher() {
87  CoInitialize(NULL);
88}
89
90HistoryPublisher::~HistoryPublisher() {
91  CoUninitialize();
92}
93
94bool HistoryPublisher::Init() {
95  return ReadRegisteredIndexersFromRegistry();
96}
97
98// Peruse the registry for Indexer to instantiate and store in |indexers_|.
99// Return true if we found at least one indexer object. We look both in HKCU
100// and HKLM.
101bool HistoryPublisher::ReadRegisteredIndexersFromRegistry() {
102  AddRegisteredIndexers(HKEY_CURRENT_USER,
103                        kRegKeyRegisteredIndexersInfo, &indexers_);
104  AddRegisteredIndexers(HKEY_LOCAL_MACHINE,
105                        kRegKeyRegisteredIndexersInfo, &indexers_);
106  return !indexers_.empty();
107}
108
109void HistoryPublisher::PublishDataToIndexers(const PageData& page_data)
110    const {
111  double var_time = TimeToUTCVariantTime(page_data.time);
112
113  CComSafeArray<unsigned char> thumbnail_arr;
114  if (page_data.thumbnail) {
115    for (size_t i = 0; i < page_data.thumbnail->size(); ++i)
116      thumbnail_arr.Add((*page_data.thumbnail)[i]);
117  }
118
119  // Send data to registered indexers.
120  base::win::ScopedVariant time(var_time, VT_DATE);
121  base::win::ScopedBstr url(ASCIIToWide(page_data.url.spec()).c_str());
122  base::win::ScopedBstr html(page_data.html);
123  base::win::ScopedBstr title(page_data.title);
124  // Don't send a NULL string through ASCIIToWide.
125  base::win::ScopedBstr format(page_data.thumbnail_format ?
126      ASCIIToWide(page_data.thumbnail_format).c_str() :
127      NULL);
128  base::win::ScopedVariant psa(thumbnail_arr.m_psa);
129  for (size_t i = 0; i < indexers_.size(); ++i) {
130    indexers_[i]->SendPageData(time, url, html, title, format, psa);
131  }
132}
133
134void HistoryPublisher::DeleteUserHistoryBetween(const base::Time& begin_time,
135                                                const base::Time& end_time)
136    const {
137  base::win::ScopedVariant var_begin_time(TimeToUTCVariantTime(begin_time),
138                                          VT_DATE);
139  base::win::ScopedVariant var_end_time(TimeToUTCVariantTime(end_time),
140                                        VT_DATE);
141  for (size_t i = 0; i < indexers_.size(); ++i) {
142    indexers_[i]->DeleteUserHistoryBetween(var_begin_time, var_end_time);
143  }
144}
145
146}  // namespace history
147