Home | History | Annotate | Download | only in webui
      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/ui/webui/new_tab_page_sync_handler.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/callback.h"
     10 #include "base/string_split.h"
     11 #include "base/string_util.h"
     12 #include "base/utf_string_conversions.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/net/chrome_url_request_context.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "content/browser/renderer_host/render_view_host.h"
     17 #include "grit/generated_resources.h"
     18 #include "net/base/cookie_monster.h"
     19 #include "net/url_request/url_request_context.h"
     20 #include "ui/base/l10n/l10n_util.h"
     21 
     22 // Default URL for the sync web interface.
     23 //
     24 // TODO(idana): when we figure out how we are going to allow third parties to
     25 // plug in their own sync engine, we should allow this value to be
     26 // configurable.
     27 static const char kSyncDefaultViewOnlineUrl[] = "http://docs.google.com";
     28 
     29 // TODO(idana): the following code was originally copied from
     30 // toolbar_importer.h/cc and it needs to be moved to a common Google Accounts
     31 // utility.
     32 
     33 // A simple pair of fields that identify a set of Google cookies, used to
     34 // filter from a larger set.
     35 struct GoogleCookieFilter {
     36   // The generalized, fully qualified URL of pages where
     37   // cookies with id |cookie_id| are obtained / accessed.
     38   const char* url;
     39   // The id of the cookie this filter is selecting,
     40   // with name/value delimiter (i.e '=').
     41   const char* cookie_id;
     42 };
     43 
     44 // Filters to select Google GAIA cookies.
     45 static const GoogleCookieFilter kGAIACookieFilters[] = {
     46   { "http://.google.com/",       "SID=" },     // Gmail.
     47   // Add filters here for other interesting cookies that should result in
     48   // showing the promotions (e.g ASIDAS for dasher accounts).
     49 };
     50 
     51 bool IsGoogleGAIACookieInstalled() {
     52   for (size_t i = 0; i < arraysize(kGAIACookieFilters); ++i) {
     53     // Since we are running on the UI thread don't call GetURLRequestContext().
     54     net::CookieStore* store =
     55         Profile::GetDefaultRequestContext()->DONTUSEME_GetCookieStore();
     56     GURL url(kGAIACookieFilters[i].url);
     57     net::CookieOptions options;
     58     options.set_include_httponly();  // The SID cookie might be httponly.
     59     std::string cookies = store->GetCookiesWithOptions(url, options);
     60     std::vector<std::string> cookie_list;
     61     base::SplitString(cookies, ';', &cookie_list);
     62     for (std::vector<std::string>::iterator current = cookie_list.begin();
     63          current != cookie_list.end();
     64          ++current) {
     65       size_t position =
     66           current->find(kGAIACookieFilters[i].cookie_id);
     67       if (0 == position)
     68         return true;
     69     }
     70   }
     71   return false;
     72 }
     73 
     74 NewTabPageSyncHandler::NewTabPageSyncHandler() : sync_service_(NULL),
     75   waiting_for_initial_page_load_(true) {
     76 }
     77 
     78 NewTabPageSyncHandler::~NewTabPageSyncHandler() {
     79   if (sync_service_)
     80     sync_service_->RemoveObserver(this);
     81 }
     82 
     83 // static
     84 NewTabPageSyncHandler::MessageType
     85     NewTabPageSyncHandler::FromSyncStatusMessageType(
     86         sync_ui_util::MessageType type) {
     87   switch (type) {
     88     case sync_ui_util::SYNC_ERROR:
     89       return SYNC_ERROR;
     90     case sync_ui_util::SYNC_PROMO:
     91       return SYNC_PROMO;
     92     case sync_ui_util::PRE_SYNCED:
     93     case sync_ui_util::SYNCED:
     94     default:
     95       return HIDE;
     96   }
     97 }
     98 
     99 WebUIMessageHandler* NewTabPageSyncHandler::Attach(WebUI* web_ui) {
    100   sync_service_ = web_ui->GetProfile()->GetProfileSyncService();
    101   DCHECK(sync_service_);  // This shouldn't get called by an incognito NTP.
    102   DCHECK(!sync_service_->IsManaged());  // And neither if sync is managed.
    103   sync_service_->AddObserver(this);
    104   return WebUIMessageHandler::Attach(web_ui);
    105 }
    106 
    107 void NewTabPageSyncHandler::RegisterMessages() {
    108   web_ui_->RegisterMessageCallback("GetSyncMessage",
    109       NewCallback(this, &NewTabPageSyncHandler::HandleGetSyncMessage));
    110   web_ui_->RegisterMessageCallback("SyncLinkClicked",
    111       NewCallback(this, &NewTabPageSyncHandler::HandleSyncLinkClicked));
    112 }
    113 
    114 void NewTabPageSyncHandler::HandleGetSyncMessage(const ListValue* args) {
    115   waiting_for_initial_page_load_ = false;
    116   BuildAndSendSyncStatus();
    117 }
    118 
    119 void NewTabPageSyncHandler::HideSyncStatusSection() {
    120   SendSyncMessageToPage(HIDE, std::string(), std::string());
    121 }
    122 
    123 void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
    124   DCHECK(!waiting_for_initial_page_load_);
    125 
    126   // Hide the sync status section if sync is managed or disabled entirely.
    127   if (!sync_service_ || sync_service_->IsManaged()) {
    128     HideSyncStatusSection();
    129     return;
    130   }
    131 
    132   // Don't show sync status if setup is not complete.
    133   if (!sync_service_->HasSyncSetupCompleted()) {
    134     return;
    135   }
    136 
    137   // Once sync has been enabled, the supported "sync statuses" for the NNTP
    138   // from the user's perspective are:
    139   //
    140   // "Sync error", when we can't authenticate or establish a connection with
    141   //               the sync server (appropriate information appended to
    142   //               message).
    143   string16 status_msg;
    144   string16 link_text;
    145   sync_ui_util::MessageType type =
    146       sync_ui_util::GetStatusLabelsForNewTabPage(sync_service_,
    147                                                  &status_msg,
    148                                                  &link_text);
    149   SendSyncMessageToPage(FromSyncStatusMessageType(type),
    150                         UTF16ToUTF8(status_msg), UTF16ToUTF8(link_text));
    151 }
    152 
    153 void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
    154   DCHECK(!waiting_for_initial_page_load_);
    155   DCHECK(sync_service_);
    156   if (!sync_service_->IsSyncEnabled())
    157     return;
    158   if (sync_service_->HasSyncSetupCompleted()) {
    159     sync_service_->ShowErrorUI(NULL);
    160     DictionaryValue value;
    161     value.SetString("syncEnabledMessage",
    162                     l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO,
    163                         sync_service_->GetAuthenticatedUsername()));
    164     web_ui_->CallJavascriptFunction("syncAlreadyEnabled", value);
    165   } else {
    166     // User clicked the 'Start now' link to begin syncing.
    167     ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP);
    168     sync_service_->ShowLoginDialog(NULL);
    169   }
    170 }
    171 
    172 void NewTabPageSyncHandler::OnStateChanged() {
    173   // Don't do anything if the page has not yet loaded.
    174   if (waiting_for_initial_page_load_)
    175     return;
    176   BuildAndSendSyncStatus();
    177 }
    178 
    179 void NewTabPageSyncHandler::SendSyncMessageToPage(
    180     MessageType type, std::string msg,
    181     std::string linktext) {
    182   DictionaryValue value;
    183   std::string user;
    184   std::string title;
    185   std::string linkurl;
    186 
    187   // If there is nothing to show, we should hide the sync section altogether.
    188   if (type == HIDE || (msg.empty() && linktext.empty())) {
    189     value.SetBoolean("syncsectionisvisible", false);
    190   } else {
    191     if (type == SYNC_ERROR)
    192       title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
    193     else if (type == SYNC_PROMO)
    194       title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE);
    195     else
    196       NOTREACHED();
    197 
    198     value.SetBoolean("syncsectionisvisible", true);
    199     value.SetString("msg", msg);
    200     value.SetString("title", title);
    201     if (linktext.empty()) {
    202       value.SetBoolean("linkisvisible", false);
    203     } else {
    204       value.SetBoolean("linkisvisible", true);
    205       value.SetString("linktext", linktext);
    206 
    207       // The only time we set the URL is when the user is synced and we need to
    208       // show a link to a web interface (e.g. http://docs.google.com). When we
    209       // set that URL, HandleSyncLinkClicked won't be called when the user
    210       // clicks on the link.
    211       if (linkurl.empty()) {
    212         value.SetBoolean("linkurlisset", false);
    213       } else {
    214         value.SetBoolean("linkurlisset", true);
    215         value.SetString("linkurl", linkurl);
    216       }
    217     }
    218   }
    219   web_ui_->CallJavascriptFunction("syncMessageChanged", value);
    220 }
    221