summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd14
-rw-r--r--chrome/browser/browser.vcproj16
-rw-r--r--chrome/browser/importer/importer.cc64
-rw-r--r--chrome/browser/importer/importer.h8
-rw-r--r--chrome/browser/importer/toolbar_importer.cc578
-rw-r--r--chrome/browser/importer/toolbar_importer.h164
-rw-r--r--chrome/browser/views/importer_view.cc114
-rw-r--r--chrome/browser/views/importer_view.h19
8 files changed, 958 insertions, 19 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 214da38..ef8c525 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1768,6 +1768,9 @@ each locale. -->
<message name="IDS_IMPORT_FROM_FIREFOX" desc="browser combo box: Mozilla Firefox">
Mozilla Firefox
</message>
+ <message name="IDS_IMPORT_FROM_GOOGLE_TOOLBAR" desc="browser combo box: Google Toolbar">
+ Google Toolbar
+ </message>
<message name="IDS_IMPORT_ITEMS_LABEL" desc="Label before item select checkboxes">
Select items to import:
</message>
@@ -1791,6 +1794,10 @@ each locale. -->
Import
</message>
+ <message name="IDS_IMPORTER_GOOGLE_LOGIN_TEXT" desc="The message to be displayed on dialog">
+ In order to import Toolbar bookmarks into Chrome, you must be logged into your Google account. Please log in and try to import again.
+ </message>
+
<!-- Import progress popup -->
<message name="IDS_IMPORT_PROGRESS_TITLE" desc="Title for the importing progress dialog">
Importing
@@ -2032,7 +2039,7 @@ each locale. -->
<message name="IDS_BOOKMARKS_NO_ITEMS" desc="Text shown when the user has no bookmarks">
For quick access, place your bookmarks here in the bookmarks bar.
</message>
-
+
<!-- The location for special bookmark groups -->
<message name="IDS_BOOKMARK_GROUP_FROM_IE" desc="The group name of bookmarks from Internet Explorer">
Imported From IE
@@ -2040,11 +2047,14 @@ each locale. -->
<message name="IDS_BOOKMARK_GROUP_FROM_FIREFOX" desc="The group name of bookmarks from Firefox">
Imported From Firefox
</message>
+ <message name="IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR" desc="The group name of bookmarks from Google Toolbar">
+ Imported From Google Toolbar
+ </message>
<message name="IDS_BOOKMARK_GROUP" desc="The group name of bookmarks imported from a file">
Imported
</message>
- <!-- bookmark editor messages-->
+ <!-- bookmark editor messages-->
<message name="IDS_BOOMARK_EDITOR_NAME_LABEL" desc="Label shown before the title/name of the URL.">
Name:
</message>
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 033b3e3..a39fe95 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -722,19 +722,19 @@
Name="Bookmarks"
>
<File
- RelativePath=".\bookmarks\bookmark_context_menu.cc"
+ RelativePath=".\bookmarks\bookmark_codec.cc"
>
</File>
<File
- RelativePath=".\bookmarks\bookmark_context_menu.h"
+ RelativePath=".\bookmarks\bookmark_codec.h"
>
</File>
<File
- RelativePath=".\bookmarks\bookmark_codec.cc"
+ RelativePath=".\bookmarks\bookmark_context_menu.cc"
>
</File>
<File
- RelativePath=".\bookmarks\bookmark_codec.h"
+ RelativePath=".\bookmarks\bookmark_context_menu.h"
>
</File>
<File
@@ -1577,6 +1577,14 @@
RelativePath=".\importer\mork_reader.h"
>
</File>
+ <File
+ RelativePath=".\importer\toolbar_importer.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\importer\toolbar_importer.h"
+ >
+ </File>
</Filter>
<Filter
Name="Drag &amp; Drop"
diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc
index e1cbd13..c2fa2a6 100644
--- a/chrome/browser/importer/importer.cc
+++ b/chrome/browser/importer/importer.cc
@@ -11,12 +11,16 @@
#include "base/gfx/png_encoder.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/first_run.h"
#include "chrome/browser/importer/firefox2_importer.h"
#include "chrome/browser/importer/firefox3_importer.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
#include "chrome/browser/importer/firefox_profile_lock.h"
#include "chrome/browser/importer/ie_importer.h"
+#include "chrome/browser/importer/toolbar_importer.h"
#include "chrome/browser/template_url_model.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/webdata/web_data_service.h"
@@ -24,6 +28,7 @@
#include "chrome/common/l10n_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
+#include "chrome/common/win_util.h"
#include "chrome/views/window.h"
#include "webkit/glue/image_decoder.h"
@@ -245,7 +250,8 @@ void ProfileWriter::AddKeywords(const std::vector<TemplateURL*>& template_urls,
}
if (t_url->url() && t_url->url()->IsValid()) {
model->Add(t_url);
- if (default_keyword && t_url->url() && t_url->url()->SupportsReplacement())
+ if (default_keyword && t_url->url() &&
+ t_url->url()->SupportsReplacement())
model->SetDefaultSearchProvider(t_url);
} else {
// Don't add invalid TemplateURLs to the model.
@@ -327,6 +333,7 @@ ImporterHost::ImporterHost(MessageLoop* file_loop)
ImporterHost::~ImporterHost() {
STLDeleteContainerPointers(source_profiles_.begin(), source_profiles_.end());
+ if (NULL != importer_) importer_->Release();
}
void ImporterHost::Loaded(BookmarkModel* model) {
@@ -386,6 +393,7 @@ void ImporterHost::StartImportSettings(const ProfileInfo& profile_info,
// will be notified.
writer_ = writer;
importer_ = CreateImporterByType(profile_info.browser_type);
+ importer_->AddRef();
importer_->set_first_run(first_run);
task_ = NewRunnableMethod(importer_, &Importer::StartImport,
profile_info, items, writer_.get(), this);
@@ -402,6 +410,27 @@ void ImporterHost::StartImportSettings(const ProfileInfo& profile_info,
}
}
+ if (profile_info.browser_type == GOOGLE_TOOLBAR5) {
+ if (!ToolbarImporterUtils::IsGoogleGAIACookieInstalled()) {
+ win_util::MessageBox(
+ NULL,
+ l10n_util::GetString(IDS_IMPORTER_GOOGLE_LOGIN_TEXT).c_str(),
+ L"",
+ MB_OK | MB_TOPMOST);
+
+ GURL url("https://www.google.com/accounts/ServiceLogin");
+ BrowsingInstance* instance = new BrowsingInstance(writer_->GetProfile());
+ SiteInstance* site = instance->GetSiteInstanceForURL(url);
+ Browser* browser = BrowserList::GetLastActive();
+ browser->AddTabWithURL(url, GURL(), PageTransition::TYPED, true, site);
+
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &ImporterHost::OnLockViewEnd, false));
+
+ is_source_readable_ = false;
+ }
+ }
+
// BookmarkModel should be loaded before adding IE favorites. So we observe
// the BookmarkModel if needed, and start the task after it has been loaded.
if ((items & FAVORITES) && !writer_->BookmarkModelIsLoaded()) {
@@ -469,6 +498,8 @@ Importer* ImporterHost::CreateImporterByType(ProfileType type) {
return new Firefox2Importer();
case FIREFOX3:
return new Firefox3Importer();
+ case GOOGLE_TOOLBAR5:
+ return new Toolbar5Importer();
}
NOTREACHED();
return NULL;
@@ -489,6 +520,8 @@ const ProfileInfo& ImporterHost::GetSourceProfileInfoAt(int index) const {
}
void ImporterHost::DetectSourceProfiles() {
+ // The order in which detect is called determines the order
+ // in which the options appear in the dropdown combo-box
if (ShellIntegration::IsFirefoxDefaultBrowser()) {
DetectFirefoxProfiles();
DetectIEProfiles();
@@ -496,6 +529,8 @@ void ImporterHost::DetectSourceProfiles() {
DetectIEProfiles();
DetectFirefoxProfiles();
}
+
+ if (!FirstRun::IsChromeFirstRun()) DetectGoogleToolbarProfiles();
}
void ImporterHost::DetectIEProfiles() {
@@ -505,6 +540,8 @@ void ImporterHost::DetectIEProfiles() {
ie->browser_type = MS_IE;
ie->source_path.clear();
ie->app_path.clear();
+ ie->services_supported = HISTORY | FAVORITES | COOKIES | PASSWORDS |
+ SEARCH_ENGINES;
source_profiles_.push_back(ie);
}
@@ -568,7 +605,32 @@ void ImporterHost::DetectFirefoxProfiles() {
firefox->browser_type = firefox_type;
firefox->source_path = source_path;
firefox->app_path = GetFirefoxInstallPath();
+ firefox->services_supported = HISTORY | FAVORITES | COOKIES | PASSWORDS |
+ SEARCH_ENGINES;
source_profiles_.push_back(firefox);
}
}
+void ImporterHost::DetectGoogleToolbarProfiles() {
+ if (ToolbarImporterUtils::IsToolbarInstalled()) {
+ TOOLBAR_VERSION version = ToolbarImporterUtils::GetToolbarVersion();
+ if (DEPRECATED != version) {
+ ProfileInfo* google_toolbar = new ProfileInfo();
+ switch (version) {
+ // TODO(brg): Support other toolbar version after 1.0.
+ case VERSION_5:
+ google_toolbar->browser_type = GOOGLE_TOOLBAR5;
+ break;
+ default:
+ NOTREACHED() << "Supported Google Toolbar version not implemented.";
+ break;
+ }
+ google_toolbar->description = l10n_util::GetString(
+ IDS_IMPORT_FROM_GOOGLE_TOOLBAR);
+ google_toolbar->source_path.clear();
+ google_toolbar->app_path.clear();
+ google_toolbar->services_supported = FAVORITES;
+ source_profiles_.push_back(google_toolbar);
+ }
+ }
+}
diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h
index 3d83ca0..dba4cd4 100644
--- a/chrome/browser/importer/importer.h
+++ b/chrome/browser/importer/importer.h
@@ -26,7 +26,8 @@
enum ProfileType {
MS_IE = 0,
FIREFOX2,
- FIREFOX3
+ FIREFOX3,
+ GOOGLE_TOOLBAR5
};
// An enumeration of the type of data we want to import.
@@ -38,6 +39,7 @@ enum ImportItem {
PASSWORDS = 0x0008,
SEARCH_ENGINES = 0x0010,
HOME_PAGE = 0x0020,
+ ALL = 0x003f
};
typedef struct {
@@ -45,6 +47,7 @@ typedef struct {
ProfileType browser_type;
std::wstring source_path;
std::wstring app_path;
+ uint16 services_supported; // bitmap of ImportItem
} ProfileInfo;
class FirefoxProfileLock;
@@ -103,6 +106,8 @@ class ProfileWriter : public base::RefCounted<ProfileWriter> {
// Shows the bookmarks toolbar.
void ShowBookmarkBar();
+ Profile* GetProfile() const { return profile_; }
+
private:
Profile* profile_;
@@ -228,6 +233,7 @@ class ImporterHost : public base::RefCounted<ImporterHost>,
// Helper methods for detecting available profiles.
void DetectIEProfiles();
void DetectFirefoxProfiles();
+ void DetectGoogleToolbarProfiles();
// The list of profiles with the default one first.
std::vector<ProfileInfo*> source_profiles_;
diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc
new file mode 100644
index 0000000..6428a92
--- /dev/null
+++ b/chrome/browser/importer/toolbar_importer.cc
@@ -0,0 +1,578 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/importer/toolbar_importer.h"
+
+#include <limits>
+#include "base/string_util.h"
+#include "base/rand_util.h"
+#include "base/registry.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/libxml_utils.h"
+#include "net/base/data_url.h"
+#include "net/base/cookie_monster.h"
+
+#include "generated_resources.h"
+
+
+//
+// ToolbarImporterUtils
+//
+const HKEY ToolbarImporterUtils::kToolbarInstallRegistryRoots[] =
+ {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
+const TCHAR* ToolbarImporterUtils::kToolbarRootRegistryFolder =
+ L"Software\\Google\\Google Toolbar";
+const TCHAR* ToolbarImporterUtils::kToolbarVersionRegistryFolder =
+ L"SOFTWARE\\Google\\Google Toolbar\\Component";
+const TCHAR* ToolbarImporterUtils::kToolbarVersionRegistryKey =
+ L"CurrentVersion";
+
+
+bool ToolbarImporterUtils::IsToolbarInstalled() {
+ for (int index = 0;
+ index < arraysize(kToolbarInstallRegistryRoots);
+ ++index) {
+ RegKey key(kToolbarInstallRegistryRoots[index],
+ kToolbarRootRegistryFolder);
+ if (key.Valid())
+ return true;
+ }
+ return false;
+}
+
+bool ToolbarImporterUtils::IsGoogleGAIACookieInstalled() {
+ URLRequestContext* context = Profile::GetDefaultRequestContext();
+ net::CookieMonster* store= context->cookie_store();
+ GURL url("http://.google.com/");
+ net::CookieMonster::CookieOptions options = net::CookieMonster::NORMAL;
+ std::string cookies = store->GetCookiesWithOptions(url, options);
+ std::vector<std::string> cookie_list;
+ SplitString(cookies, L';', &cookie_list);
+ for (std::vector<std::string>::iterator current = cookie_list.begin();
+ current != cookie_list.end();
+ ++current) {
+ size_t position = (*current).find("SID=");
+ if (0 == position)
+ return true;
+ }
+ return false;
+}
+
+TOOLBAR_VERSION ToolbarImporterUtils::GetToolbarVersion() {
+ TOOLBAR_VERSION toolbar_version = NO_VERSION;
+ for (int index = 0;
+ (index < arraysize(kToolbarInstallRegistryRoots)) &&
+ NO_VERSION == toolbar_version;
+ ++index) {
+ RegKey key(kToolbarInstallRegistryRoots[index],
+ kToolbarVersionRegistryFolder);
+ if (key.Valid() && key.ValueExists(kToolbarVersionRegistryKey)) {
+ TCHAR version_buffer[128];
+ DWORD version_buffer_length = sizeof(version_buffer);
+ if (key.ReadValue(kToolbarVersionRegistryKey,
+ &version_buffer,
+ &version_buffer_length)) {
+ int version_value = _wtoi(version_buffer);
+ switch (version_value) {
+ case 5: {
+ toolbar_version = VERSION_5;
+ break;
+ }
+ default: {
+ toolbar_version = DEPRECATED;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return toolbar_version;
+}
+
+//
+// Toolbar5Importer
+//
+
+const std::string Toolbar5Importer::kXmlApiReplyXmlTag = "xml_api_reply";
+const std::string Toolbar5Importer::kBookmarksXmlTag = "bookmarks";
+const std::string Toolbar5Importer::kBookmarkXmlTag = "bookmark";
+const std::string Toolbar5Importer::kTitleXmlTag = "title";
+const std::string Toolbar5Importer::kUrlXmlTag = "url";
+const std::string Toolbar5Importer::kTimestampXmlTag = "timestamp";
+const std::string Toolbar5Importer::kLabelsXmlTag = "labels";
+const std::string Toolbar5Importer::kLabelXmlTag = "label";
+const std::string Toolbar5Importer::kAttributesXmlTag = "attributes";
+const std::string Toolbar5Importer::kAttributeXmlTag = "attribute";
+const std::string Toolbar5Importer::kNameXmlTag = "name";
+const std::string Toolbar5Importer::kValueXmlTag = "favicon";
+const std::string Toolbar5Importer::kFaviconAttributeXmlName = "favicon_url";
+
+const std::string Toolbar5Importer::kRandomNumberToken = "{random_number}";
+const std::string Toolbar5Importer::kAuthorizationToken = "{auth_token}";
+const std::string Toolbar5Importer::kAuthorizationTokenPrefix = "/*";
+const std::string Toolbar5Importer::kAuthorizationTokenSuffix = "*/";
+const std::string Toolbar5Importer::kMaxNumToken = "{max_num}";
+const std::string Toolbar5Importer::kMaxTimestampToken = "{max_timestamp}";
+
+const std::string Toolbar5Importer::kT5AuthorizationTokenUrl =
+ "http://www.google.com/notebook/token?zx={random_number}";
+const std::string Toolbar5Importer::kT5FrontEndUrlTemplate =
+ "http://www.google.com/notebook/toolbar?cmd=list&tok={auth_token}& "
+ "num={max_num}&min={max_timestamp}&all=0&zx={random_number}";
+const std::string Toolbar5Importer::kT4FrontEndUrlTemplate =
+ "http://www.google.com/bookmarks/?output=xml&num={max_num}&"
+ "min={max_timestamp}&all=0&zx={random_number}";
+
+// Importer methods.
+Toolbar5Importer::Toolbar5Importer() : writer_(NULL),
+ state_(NOT_USED),
+ items_to_import_(NONE),
+ token_fetcher_(NULL),
+ data_fetcher_(NULL) {
+}
+
+Toolbar5Importer::~Toolbar5Importer() {
+ DCHECK(!token_fetcher_);
+ DCHECK(!data_fetcher_);
+}
+
+void Toolbar5Importer::StartImport(ProfileInfo profile_info,
+ uint16 items,
+ ProfileWriter* writer,
+ ImporterHost* host) {
+ DCHECK(writer);
+ DCHECK(host);
+
+ importer_host_ = host;
+ writer_ = writer;
+ items_to_import_ = items;
+ state_ = INITIALIZED;
+
+ NotifyStarted();
+ ContinueImport();
+}
+
+void Toolbar5Importer::OnURLFetchComplete(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ if (200 != response_code) { // HTTP/Ok
+ // Display to the user an error dialog and cancel the import
+ EndImportBookmarks(false);
+ return;
+ }
+
+ switch (state_) {
+ case GET_AUTHORIZATION_TOKEN:
+ GetBookmarkDataFromServer(data);
+ break;
+ case GET_BOOKMARKS:
+ GetBookmarsFromServerDataResponse(data);
+ break;
+ default:
+ NOTREACHED() << "Invalid state.";
+ EndImportBookmarks(false);
+ break;
+ }
+}
+
+void Toolbar5Importer::ContinueImport() {
+ DCHECK((items_to_import_ == FAVORITES) || (items_to_import_ == NONE)) <<
+ "The items requested are not supported";
+
+ // The order here is important. Each Begin... will clear the flag
+ // of its item before its task finishes and re-enters this method.
+ if (NONE == items_to_import_) {
+ EndImport();
+ }
+ if ((items_to_import_ & FAVORITES) && !cancelled()) {
+ items_to_import_ &= ~FAVORITES;
+ BeginImportBookmarks();
+ }
+ // TODO(brg): Import history, autocomplete, other toolbar information
+ // for 2.0
+}
+
+void Toolbar5Importer::EndImport() {
+ // By spec the fetcher's must be destroyed within the same
+ // thread they are created. The importer is destroyed in the ui_thread
+ // so when we complete in the file_thread we destroy them first.
+ if (NULL != token_fetcher_) {
+ delete token_fetcher_;
+ token_fetcher_ = NULL;
+ }
+
+ if (NULL != data_fetcher_) {
+ delete data_fetcher_;
+ data_fetcher_ = NULL;
+ }
+
+ NotifyEnded();
+}
+
+void Toolbar5Importer::BeginImportBookmarks() {
+ NotifyItemStarted(FAVORITES);
+ GetAuthenticationFromServer();
+}
+
+void Toolbar5Importer::EndImportBookmarks(bool success) {
+ NotifyItemEnded(FAVORITES);
+ ContinueImport();
+}
+
+
+// Notebook FE connection managers.
+void Toolbar5Importer::GetAuthenticationFromServer() {
+ // Authentication is a token string retreived from the authentication server
+ // To access it we call the url below with a random number replacing the
+ // value in the string.
+ state_ = GET_AUTHORIZATION_TOKEN;
+
+ // Random number construction.
+ int random = base::RandInt(0, std::numeric_limits<int>::max());
+ std::string random_string = UintToString(random);
+
+ // Retrieve authorization token from the network.
+ std::string url_string(kT5AuthorizationTokenUrl);
+ url_string.replace(url_string.find(kRandomNumberToken),
+ kRandomNumberToken.size(),
+ random_string);
+ GURL url(url_string);
+
+ token_fetcher_ = new URLFetcher(url, URLFetcher::GET, this);
+ token_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
+ token_fetcher_->Start();
+}
+
+void Toolbar5Importer::GetBookmarkDataFromServer(const std::string& response) {
+ state_ = GET_BOOKMARKS;
+
+ // Parse and verify the authorization token from the response.
+ std::string token;
+ if (!ParseAuthenticationTokenResponse(response, &token)) {
+ EndImportBookmarks(false);
+ return;
+ }
+
+ // Build the Toolbar FE connection string, and call the server for
+ // the xml blob. We must tag the connection string with a random number.
+ std::string conn_string = kT5FrontEndUrlTemplate;
+ int random = base::RandInt(0, std::numeric_limits<int>::max());
+ std::string random_string = UintToString(random);
+ conn_string.replace(conn_string.find(kRandomNumberToken),
+ kRandomNumberToken.size(),
+ random_string);
+ conn_string.replace(conn_string.find(kAuthorizationToken),
+ kAuthorizationToken.size(),
+ token);
+ GURL url(conn_string);
+
+ data_fetcher_ = new URLFetcher(url, URLFetcher::GET, this);
+ data_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
+ data_fetcher_->Start();
+}
+
+void Toolbar5Importer::GetBookmarsFromServerDataResponse(
+ const std::string& response) {
+ bool retval = false;
+ XmlReader reader;
+ if (reader.Load(response) && !cancelled()) {
+ // Construct Bookmarks
+ std::vector< ProfileWriter::BookmarkEntry > bookmarks;
+ std::vector< history::ImportedFavIconUsage > favicons;
+ retval = ParseBookmarksFromReader(&reader, &bookmarks, &favicons);
+ if (retval && !cancelled()) {
+ AddBookMarksToChrome(bookmarks, favicons);
+ }
+ }
+ EndImportBookmarks(retval);
+}
+
+bool Toolbar5Importer::ParseAuthenticationTokenResponse(
+ const std::string& response,
+ std::string* token) {
+ DCHECK(token);
+
+ *token = response;
+ size_t position = token->find(kAuthorizationTokenPrefix);
+ if (0 != position)
+ return false;
+ token->replace(position, kAuthorizationTokenPrefix.size(), "");
+
+ position = token->find(kAuthorizationTokenSuffix);
+ if (token->size() != (position + kAuthorizationTokenSuffix.size()))
+ return false;
+ token->replace(position, kAuthorizationTokenSuffix.size(), "");
+
+ return true;
+}
+
+// Parsing
+bool Toolbar5Importer::ParseBookmarksFromReader(
+ XmlReader* reader,
+ std::vector< ProfileWriter::BookmarkEntry >* bookmarks,
+ std::vector< history::ImportedFavIconUsage >* favicons) {
+ DCHECK(reader);
+ DCHECK(bookmarks);
+ DCHECK(favicons);
+
+ // The XML blob returned from the server is described in the
+ // Toolbar-Notebook/Bookmarks Protocol document located at
+ // https://docs.google.com/a/google.com/Doc?docid=cgt3m7dr_24djt62m&hl=en
+ // We are searching for the section with structure
+ // <bookmarks><bookmark>...</bookmark><bookmark>...</bookmark></bookmarks>
+
+ // Locate the |bookmarks| blob.
+ if (!reader->SkipToElement())
+ return false;
+
+ if (!LocateNextTagByName(reader, kBookmarksXmlTag))
+ return false;
+
+ // Parse each |bookmark| blob
+ while (LocateNextTagByName(reader, kBookmarkXmlTag)) {
+ ProfileWriter::BookmarkEntry bookmark_entry;
+ history::ImportedFavIconUsage favicon_entry;
+ if (ExtractBookmarkInformation(reader, &bookmark_entry, &favicon_entry)) {
+ bookmarks->push_back(bookmark_entry);
+ if (!favicon_entry.favicon_url.is_empty())
+ favicons->push_back(favicon_entry);
+ }
+ }
+
+ return true;
+}
+
+bool Toolbar5Importer::LocateNextTagByName(XmlReader* reader,
+ const std::string& tag) {
+ // Locate the |tag| blob.
+ while (tag != reader->NodeName()) {
+ if (!reader->Read())
+ return false;
+ }
+ return true;
+}
+
+bool Toolbar5Importer::ExtractBookmarkInformation(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* bookmark_entry,
+ history::ImportedFavIconUsage* favicon_entry) {
+ DCHECK(reader);
+ DCHECK(bookmark_entry);
+ DCHECK(favicon_entry);
+
+ // The following is a typical bookmark entry.
+ // The reader should be pointing to the <title> tag at the moment.
+ //
+ // <bookmark>
+ // <title>MyTitle</title>
+ // <url>http://www.sohu.com/</url>
+ // <timestamp>1153328691085181</timestamp>
+ // <id>N123nasdf239</id>
+ // <notebook_id>Bxxxxxxx</notebook_id> (for bookmarks, a special id is used)
+ // <section_id>Sxxxxxx</section_id>
+ // <has_highlight>0</has_highlight>
+ // <labels>
+ // <label>China</label>
+ // <label>^k</label> (if this special label is present, the note is deleted)
+ // </labels>
+ // <attributes>
+ // <attribute>
+ // <name>favicon_url</name>
+ // <value>http://www.sohu.com/favicon.ico</value>
+ // </attribute>
+ // <attribute>
+ // <name>favicon_timestamp</name>
+ // <value>1153328653</value>
+ // </attribute>
+ // <attribute>
+ // <name>notebook_name</name>
+ // <value>My notebook 0</value>
+ // </attribute>
+ // <attribute>
+ // <name>section_name</name>
+ // <value>My section 0</value>
+ // </attribute>
+ // <attribute>
+ // </attributes>
+ // </bookmark>
+ //
+ // We parse the blob in order, title->url->timestamp etc. Any failure
+ // causes us to skip this bookmark. Note Favicons are optional so failure
+ // to find them is not a failure to parse the blob.
+
+ if (!ExtractTitleFromXmlReader(reader, bookmark_entry))
+ return false;
+ if (!ExtractUrlFromXmlReader(reader, bookmark_entry))
+ return false;
+ if (!ExtractTimeFromXmlReader(reader, bookmark_entry))
+ return false;
+ if (!ExtractFolderFromXmlReader(reader, bookmark_entry))
+ return false;
+ ExtractFaviconFromXmlReader(reader, bookmark_entry, favicon_entry);
+
+ return true;
+}
+
+bool Toolbar5Importer::ExtractNamedValueFromXmlReader(XmlReader* reader,
+ const std::string& name,
+ std::string* buffer) {
+ DCHECK(reader);
+ DCHECK(buffer);
+
+ if (name != reader->NodeName())
+ return false;
+ if (!reader->ReadElementContent(buffer))
+ return false;
+ return true;
+}
+
+bool Toolbar5Importer::ExtractTitleFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry) {
+ DCHECK(reader);
+ DCHECK(entry);
+
+ if (!LocateNextTagByName(reader, kTitleXmlTag))
+ return false;
+ std::string buffer;
+ if (!ExtractNamedValueFromXmlReader(reader, kTitleXmlTag, &buffer)) {
+ return false;
+ }
+ entry->title = UTF8ToWide(buffer);
+ return true;
+}
+
+bool Toolbar5Importer::ExtractUrlFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry) {
+ DCHECK(reader);
+ DCHECK(entry);
+
+ if (!LocateNextTagByName(reader, kUrlXmlTag))
+ return false;
+ std::string buffer;
+ if (!ExtractNamedValueFromXmlReader(reader, kUrlXmlTag, &buffer)) {
+ return false;
+ }
+ entry->url = GURL(buffer);
+ return true;
+}
+
+bool Toolbar5Importer::ExtractTimeFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry) {
+ DCHECK(reader);
+ DCHECK(entry);
+ if (!LocateNextTagByName(reader, kTimestampXmlTag))
+ return false;
+ std::string buffer;
+ if (!ExtractNamedValueFromXmlReader(reader, kTimestampXmlTag, &buffer)) {
+ return false;
+ }
+ int64 timestamp;
+ if (!StringToInt64(buffer, &timestamp)) {
+ return false;
+ }
+ entry->creation_time = base::Time::FromTimeT(timestamp);
+ return true;
+}
+
+bool Toolbar5Importer::ExtractFolderFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry) {
+ DCHECK(reader);
+ DCHECK(entry);
+
+ if (!LocateNextTagByName(reader, kLabelsXmlTag))
+ return false;
+ if (!LocateNextTagByName(reader, kLabelXmlTag))
+ return false;
+
+ std::vector<std::wstring> label_vector;
+ std::string label_buffer;
+ while (kLabelXmlTag == reader->NodeName() &&
+ false != reader->ReadElementContent(&label_buffer)) {
+ label_vector.push_back(UTF8ToWide(label_buffer));
+ }
+
+ // if this is the first run then we place favorites with no labels
+ // in the title bar. Else they are placed in the "Google Toolbar" folder.
+ if (first_run() && 0 == label_vector.size()) {
+ entry->in_toolbar = true;
+ } else {
+ entry->in_toolbar = false;
+ entry->path.push_back(l10n_util::GetString(
+ IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR));
+ }
+
+ // If there is only one label and it is in the form "xxx:yyy:zzz" this
+ // was created from a Firefox folder. We undo the label creation and
+ // recreate the correct folder.
+ if (1 == label_vector.size()) {
+ std::vector< std::wstring > folder_names;
+ SplitString(label_vector[0], L':', &folder_names);
+ entry->path.insert(entry->path.end(),
+ folder_names.begin(), folder_names.end());
+ } else if (0 != label_vector.size()) {
+ std::wstring folder_name = label_vector[0];
+ entry->path.push_back(folder_name);
+ }
+
+ return true;
+}
+
+bool Toolbar5Importer::ExtractFaviconFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* bookmark_entry,
+ history::ImportedFavIconUsage* favicon_entry) {
+ DCHECK(reader);
+ DCHECK(bookmark_entry);
+ DCHECK(favicon_entry);
+
+ if (!LocateNextTagByName(reader, kAttributesXmlTag))
+ return false;
+ if (!LocateNextTagByName(reader, kAttributeXmlTag))
+ return false;
+ if (!LocateNextTagByName(reader, kNameXmlTag))
+ return false;
+
+ // Attributes are <name>...</name><value>...</value> pairs. The first
+ // attribute should be the favicon name tage, and the value is the url.
+ std::string buffer;
+ if (!ExtractNamedValueFromXmlReader(reader, kNameXmlTag, &buffer))
+ return false;
+ if (kFaviconAttributeXmlName != buffer)
+ return false;
+ if (!ExtractNamedValueFromXmlReader(reader, kValueXmlTag, &buffer))
+ return false;
+
+ // Validate the url
+ GURL favicon = GURL(buffer);
+ if (!favicon.is_valid())
+ return false;
+
+ favicon_entry->favicon_url = favicon;
+ favicon_entry->urls.insert(bookmark_entry->url);
+
+ return true;
+}
+
+// Bookmark creation
+void Toolbar5Importer::AddBookMarksToChrome(
+ const std::vector< ProfileWriter::BookmarkEntry >& bookmarks,
+ const std::vector< history::ImportedFavIconUsage >& favicons) {
+ if (!bookmarks.empty() && !cancelled()) {
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddBookmarkEntry, bookmarks));
+ }
+
+ if (!favicons.empty()) {
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddFavicons, favicons));
+ }
+}
diff --git a/chrome/browser/importer/toolbar_importer.h b/chrome/browser/importer/toolbar_importer.h
new file mode 100644
index 0000000..729e73e
--- /dev/null
+++ b/chrome/browser/importer/toolbar_importer.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_IMPORTER_TOOLBAR_IMPROTER_H__
+#define CHROME_BROWSER_IMPORTER_TOOLBAR_IMPROTER_H__
+
+#include <string>
+#include <vector>
+
+#include "chrome/browser/importer/importer.h"
+#include "chrome/browser/url_fetcher.h"
+
+class XmlReader;
+
+enum TOOLBAR_VERSION {
+ NO_VERSION = -1,
+ DEPRECATED,
+ VERSION_4,
+ VERSION_5
+};
+
+class ToolbarImporterUtils {
+ public:
+
+ static bool IsToolbarInstalled();
+ static bool IsGoogleGAIACookieInstalled();
+ static TOOLBAR_VERSION GetToolbarVersion();
+
+ private:
+ static const HKEY kToolbarInstallRegistryRoots[2];
+ static const TCHAR* kToolbarRootRegistryFolder;
+ static const TCHAR* kToolbarVersionRegistryFolder;
+ static const TCHAR* kToolbarVersionRegistryKey;
+
+ ToolbarImporterUtils() {}
+ ~ToolbarImporterUtils() {}
+
+ DISALLOW_COPY_AND_ASSIGN(ToolbarImporterUtils);
+};
+
+class Toolbar5Importer : public URLFetcher::Delegate,
+ public Importer {
+ public:
+ Toolbar5Importer();
+ virtual ~Toolbar5Importer();
+
+ // Importer view calls this method to being the process.
+ virtual void StartImport(ProfileInfo profile_info,
+ uint16 items,
+ ProfileWriter* writer,
+ ImporterHost* host);
+
+ // URLFetcher::Delegate method
+ void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ private:
+ // Internal state
+ enum INTERNAL_STATE {
+ NOT_USED = -1,
+ INITIALIZED,
+ GET_AUTHORIZATION_TOKEN,
+ GET_BOOKMARKS,
+ DONE
+ };
+
+ // URLs for connecting to the toolbar front end
+ static const std::string kT5AuthorizationTokenUrl;
+ static const std::string kT5FrontEndUrlTemplate;
+ static const std::string kT4FrontEndUrlTemplate;
+
+ // Token replacement tags
+ static const std::string kRandomNumberToken;
+ static const std::string kAuthorizationToken;
+ static const std::string kAuthorizationTokenPrefix;
+ static const std::string kAuthorizationTokenSuffix;
+ static const std::string kMaxNumToken;
+ static const std::string kMaxTimestampToken;
+
+ // XML tag names
+ static const std::string kXmlApiReplyXmlTag;
+ static const std::string kBookmarksXmlTag;
+ static const std::string kBookmarkXmlTag;
+ static const std::string kTitleXmlTag;
+ static const std::string kUrlXmlTag;
+ static const std::string kTimestampXmlTag;
+ static const std::string kLabelsXmlTag;
+ static const std::string kLabelXmlTag;
+ static const std::string kAttributesXmlTag;
+ static const std::string kAttributeXmlTag;
+ static const std::string kNameXmlTag;
+ static const std::string kValueXmlTag;
+ static const std::string kFaviconAttributeXmlName;
+
+ // Flow control
+ void ContinueImport();
+ void EndImport();
+ void BeginImportBookmarks();
+ void EndImportBookmarks(bool success);
+
+ // Network I/O
+ void GetAuthenticationFromServer();
+ void GetBookmarkDataFromServer(const std::string& response);
+ void GetBookmarsFromServerDataResponse(const std::string& response);
+
+ // XML Parsing
+ bool ParseAuthenticationTokenResponse(const std::string& response,
+ std::string* token);
+ void ConstructFEConnectionString(const std::string& token,
+ std::string* conn_string);
+
+ bool ParseBookmarksFromReader(
+ XmlReader* reader,
+ std::vector< ProfileWriter::BookmarkEntry >* bookmarks,
+ std::vector< history::ImportedFavIconUsage >* favicons);
+
+ bool LocateNextTagByName(XmlReader* reader, const std::string& tag);
+
+ bool ExtractBookmarkInformation(XmlReader* reader,
+ ProfileWriter::BookmarkEntry* bookmark_entry,
+ history::ImportedFavIconUsage* favicon_entry);
+ bool ExtractNamedValueFromXmlReader(XmlReader* reader,
+ const std::string& name,
+ std::string* buffer);
+ bool ExtractTitleFromXmlReader(XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry);
+ bool ExtractUrlFromXmlReader(XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry);
+ bool ExtractTimeFromXmlReader(XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry);
+ bool ExtractFolderFromXmlReader(XmlReader* reader,
+ ProfileWriter::BookmarkEntry* entry);
+ bool ExtractFaviconFromXmlReader(
+ XmlReader* reader,
+ ProfileWriter::BookmarkEntry* bookmark_entry,
+ history::ImportedFavIconUsage* favicon_entry);
+
+ // Bookmark creation
+ void AddBookMarksToChrome(
+ const std::vector< ProfileWriter::BookmarkEntry >& bookmarks,
+ const std::vector< history::ImportedFavIconUsage >& favicons);
+
+ // Hosts the writer used in this importer.
+ ProfileWriter* writer_;
+
+ // Internal state
+ INTERNAL_STATE state_;
+
+ // Bitmask of Importer::ImportItem
+ uint16 items_to_import_;
+
+ // The fetchers need to be available to cancel the network call on user cancel
+ URLFetcher * token_fetcher_;
+ URLFetcher * data_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(Toolbar5Importer);
+};
+
+#endif // CHROME_BROWSER_IMPORTER_TOOLBAR_IMPROTER_H__
diff --git a/chrome/browser/views/importer_view.cc b/chrome/browser/views/importer_view.cc
index eedce0b..3d9e93f 100644
--- a/chrome/browser/views/importer_view.cc
+++ b/chrome/browser/views/importer_view.cc
@@ -41,6 +41,7 @@ void ImporterView::SetupControl() {
new views::Label(l10n_util::GetString(IDS_IMPORT_FROM_LABEL));
profile_combobox_ = new views::ComboBox(this);
+ profile_combobox_->SetListener(this);
import_items_label_ =
new views::Label(l10n_util::GetString(IDS_IMPORT_ITEMS_LABEL));
@@ -120,16 +121,7 @@ bool ImporterView::Accept() {
return false;
}
- uint16 items = NONE;
- if (history_checkbox_->IsEnabled() && history_checkbox_->IsSelected())
- items |= HISTORY;
- if (favorites_checkbox_->IsEnabled() && favorites_checkbox_->IsSelected())
- items |= FAVORITES;
- if (passwords_checkbox_->IsEnabled() && passwords_checkbox_->IsSelected())
- items |= PASSWORDS;
- if (search_engines_checkbox_->IsEnabled() &&
- search_engines_checkbox_->IsSelected())
- items |= SEARCH_ENGINES;
+ uint16 items = GetCheckedItems();
Browser* browser = BrowserList::GetLastActive();
int selected_index = profile_combobox_->GetSelectedItem();
@@ -149,7 +141,10 @@ views::View* ImporterView::GetContentsView() {
int ImporterView::GetItemCount(views::ComboBox* source) {
DCHECK(source == profile_combobox_);
DCHECK(importer_host_.get());
- return importer_host_->GetAvailableProfileCount();
+ int item_count = importer_host_->GetAvailableProfileCount();
+ if (checkbox_items_.size() < static_cast<size_t>(item_count))
+ checkbox_items_.resize(item_count, ALL);
+ return item_count;
}
std::wstring ImporterView::GetItemAt(views::ComboBox* source, int index) {
@@ -158,6 +153,29 @@ std::wstring ImporterView::GetItemAt(views::ComboBox* source, int index) {
return importer_host_->GetSourceProfileNameAt(index);
}
+void ImporterView::ItemChanged(views::ComboBox* combo_box,
+ int prev_index, int new_index) {
+ DCHECK(combo_box);
+ DCHECK(checkbox_items_.size() >=
+ static_cast<size_t>(importer_host_->GetAvailableProfileCount()));
+
+ if (prev_index == new_index)
+ return;
+
+ // Save the current state
+ uint16 prev_items = GetCheckedItems();
+ checkbox_items_[prev_index] = prev_items;
+
+ // Enable/Disable the checkboxes for this Item
+ uint16 new_enabled_items = importer_host_->GetSourceProfileInfoAt(
+ new_index).services_supported;
+ SetCheckedItemsState(new_enabled_items);
+
+ // Set the checked items for this Item
+ uint16 new_items = checkbox_items_[new_index];
+ SetCheckedItems(new_items);
+}
+
void ImporterView::ImportCanceled() {
ImportComplete();
}
@@ -174,3 +192,77 @@ views::CheckBox* ImporterView::InitCheckbox(const std::wstring& text,
return checkbox;
}
+uint16 ImporterView::GetCheckedItems() {
+ uint16 items = NONE;
+ if (history_checkbox_->IsEnabled() && history_checkbox_->IsSelected())
+ items |= HISTORY;
+ if (favorites_checkbox_->IsEnabled() && favorites_checkbox_->IsSelected())
+ items |= FAVORITES;
+ if (passwords_checkbox_->IsEnabled() && passwords_checkbox_->IsSelected())
+ items |= PASSWORDS;
+ if (search_engines_checkbox_->IsEnabled() &&
+ search_engines_checkbox_->IsSelected())
+ items |= SEARCH_ENGINES;
+ return items;
+}
+
+void ImporterView::SetCheckedItemsState(uint16 items) {
+ if (items & HISTORY) {
+ history_checkbox_->SetEnabled(true);
+ } else {
+ history_checkbox_->SetEnabled(false);
+ history_checkbox_->SetIsSelected(false);
+ }
+ if (items & FAVORITES) {
+ favorites_checkbox_->SetEnabled(true);
+ } else {
+ favorites_checkbox_->SetEnabled(false);
+ favorites_checkbox_->SetIsSelected(false);
+ }
+ if (items & PASSWORDS) {
+ passwords_checkbox_->SetEnabled(true);
+ } else {
+ passwords_checkbox_->SetEnabled(false);
+ passwords_checkbox_->SetIsSelected(false);
+ }
+ if (items & SEARCH_ENGINES) {
+ search_engines_checkbox_->SetEnabled(true);
+ } else {
+ search_engines_checkbox_->SetEnabled(false);
+ search_engines_checkbox_->SetIsSelected(false);
+ }
+}
+
+void ImporterView::SetCheckedItems(uint16 items) {
+ if (history_checkbox_->IsEnabled()) {
+ if (items & HISTORY) {
+ history_checkbox_->SetIsSelected(true);
+ } else {
+ history_checkbox_->SetIsSelected(false);
+ }
+ }
+
+ if (favorites_checkbox_->IsEnabled()) {
+ if (items & FAVORITES) {
+ favorites_checkbox_->SetIsSelected(true);
+ } else {
+ favorites_checkbox_->SetIsSelected(false);
+ }
+ }
+
+ if (passwords_checkbox_->IsEnabled()) {
+ if (items & PASSWORDS) {
+ passwords_checkbox_->SetIsSelected(true);
+ } else {
+ passwords_checkbox_->SetIsSelected(false);
+ }
+ }
+
+ if (search_engines_checkbox_->IsEnabled()) {
+ if (items & SEARCH_ENGINES) {
+ search_engines_checkbox_->SetIsSelected(true);
+ } else {
+ search_engines_checkbox_->SetIsSelected(false);
+ }
+ }
+}
diff --git a/chrome/browser/views/importer_view.h b/chrome/browser/views/importer_view.h
index 1f3002d..fa97e99 100644
--- a/chrome/browser/views/importer_view.h
+++ b/chrome/browser/views/importer_view.h
@@ -26,6 +26,7 @@ class Profile;
class ImporterView : public views::View,
public views::DialogDelegate,
public views::ComboBox::Model,
+ public views::ComboBox::Listener,
public ImportObserver {
public:
explicit ImporterView(Profile* profile);
@@ -46,6 +47,11 @@ class ImporterView : public views::View,
virtual int GetItemCount(views::ComboBox* source);
virtual std::wstring GetItemAt(views::ComboBox* source, int index);
+ // Overridden from ChromeViews::ComboBox::Listener
+ virtual void ItemChanged(views::ComboBox* combo_box,
+ int prev_index,
+ int new_index);
+
// Overridden from ImportObserver:
virtual void ImportCanceled();
virtual void ImportComplete();
@@ -57,6 +63,15 @@ class ImporterView : public views::View,
// Creates and initializes a new check-box.
views::CheckBox* InitCheckbox(const std::wstring& text, bool checked);
+ // Create a bitmap from the checkboxes of the view.
+ uint16 GetCheckedItems();
+
+ // Enables/Disables all the checked items for the given state
+ void SetCheckedItemsState(uint16 items);
+
+ // Sets all checked items in the given state
+ void SetCheckedItems(uint16 items);
+
views::Label* import_from_label_;
views::ComboBox* profile_combobox_;
views::Label* import_items_label_;
@@ -67,6 +82,10 @@ class ImporterView : public views::View,
scoped_refptr<ImporterHost> importer_host_;
+ // Stores the state of the checked items associated with the position of the
+ // selected item in the combo-box.
+ std::vector<uint16> checkbox_items_;
+
Profile* profile_;
DISALLOW_EVIL_CONSTRUCTORS(ImporterView);