diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 14 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 16 | ||||
-rw-r--r-- | chrome/browser/importer/importer.cc | 64 | ||||
-rw-r--r-- | chrome/browser/importer/importer.h | 8 | ||||
-rw-r--r-- | chrome/browser/importer/toolbar_importer.cc | 578 | ||||
-rw-r--r-- | chrome/browser/importer/toolbar_importer.h | 164 | ||||
-rw-r--r-- | chrome/browser/views/importer_view.cc | 114 | ||||
-rw-r--r-- | chrome/browser/views/importer_view.h | 19 |
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 & 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, ×tamp)) { + 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); |