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/bug_report_ui.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/callback.h"
     12 #include "base/logging.h"
     13 #include "base/memory/singleton.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/message_loop.h"
     16 #include "base/string_number_conversions.h"
     17 #include "base/string_piece.h"
     18 #include "base/utf_string_conversions.h"
     19 #include "base/values.h"
     20 #include "chrome/browser/bug_report_data.h"
     21 #include "chrome/browser/bug_report_util.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_list.h"
     25 #include "chrome/browser/ui/browser_window.h"
     26 #include "chrome/browser/ui/webui/screenshot_source.h"
     27 #include "chrome/browser/ui/window_snapshot/window_snapshot.h"
     28 #include "chrome/common/chrome_paths.h"
     29 #include "chrome/common/jstemplate_builder.h"
     30 #include "chrome/common/url_constants.h"
     31 #include "content/browser/browser_thread.h"
     32 #include "content/browser/tab_contents/tab_contents.h"
     33 #include "grit/browser_resources.h"
     34 #include "grit/chromium_strings.h"
     35 #include "grit/generated_resources.h"
     36 #include "grit/locale_settings.h"
     37 #include "ui/base/l10n/l10n_util.h"
     38 #include "ui/base/resource/resource_bundle.h"
     39 #include "ui/gfx/rect.h"
     40 
     41 #if defined(OS_CHROMEOS)
     42 #include "base/file_util.h"
     43 #include "base/path_service.h"
     44 #include "base/synchronization/waitable_event.h"
     45 #include "chrome/browser/chromeos/cros/cros_library.h"
     46 #include "chrome/browser/chromeos/cros/syslogs_library.h"
     47 #include "chrome/browser/chromeos/login/user_manager.h"
     48 #endif
     49 
     50 namespace {
     51 
     52 const char kScreenshotBaseUrl[] = "chrome://screenshots/";
     53 const char kCurrentScreenshotUrl[] = "chrome://screenshots/current";
     54 #if defined(OS_CHROMEOS)
     55 const char kSavedScreenshotsUrl[] = "chrome://screenshots/saved/";
     56 
     57 const char kScreenshotPattern[] = "*.png";
     58 const char kScreenshotsRelativePath[] = "/Screenshots";
     59 
     60 const size_t kMaxSavedScreenshots = 2;
     61 #endif
     62 
     63 #if defined(OS_CHROMEOS)
     64 
     65 void GetSavedScreenshots(std::vector<std::string>* saved_screenshots,
     66                          base::WaitableEvent* done) {
     67   saved_screenshots->clear();
     68 
     69   FilePath fileshelf_path;
     70   if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
     71                         &fileshelf_path)) {
     72     done->Signal();
     73     return;
     74   }
     75 
     76   // TODO(rkc): Change this to use FilePath.Append() once the cros
     77   // issue with it is fixed
     78   FilePath screenshots_path(fileshelf_path.value() +
     79                             std::string(kScreenshotsRelativePath));
     80   file_util::FileEnumerator screenshots(screenshots_path, false,
     81                                         file_util::FileEnumerator::FILES,
     82                                         std::string(kScreenshotPattern));
     83   FilePath screenshot = screenshots.Next();
     84   while (!screenshot.empty()) {
     85     saved_screenshots->push_back(std::string(kSavedScreenshotsUrl) +
     86                                  screenshot.BaseName().value());
     87     if (saved_screenshots->size() >= kMaxSavedScreenshots)
     88       break;
     89 
     90     screenshot = screenshots.Next();
     91   }
     92   done->Signal();
     93 }
     94 
     95 // This fuction posts a task to the file thread to create/list all the current
     96 // and saved screenshots.
     97 void GetScreenshotUrls(std::vector<std::string>* saved_screenshots) {
     98   base::WaitableEvent done(true, false);
     99   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    100                           NewRunnableFunction(&GetSavedScreenshots,
    101                                               saved_screenshots, &done));
    102   done.Wait();
    103 }
    104 
    105 std::string GetUserEmail() {
    106   chromeos::UserManager* manager = chromeos::UserManager::Get();
    107   if (!manager)
    108     return std::string();
    109   else
    110     return manager->logged_in_user().email();
    111 }
    112 #endif
    113 
    114 // Returns the index of the feedback tab if already open, -1 otherwise
    115 int GetIndexOfFeedbackTab(Browser* browser) {
    116   GURL bug_report_url(chrome::kChromeUIBugReportURL);
    117   for (int i = 0; i < browser->tab_count(); ++i) {
    118     TabContents* tab = browser->GetTabContentsAt(i);
    119     if (tab && tab->GetURL().GetWithEmptyPath() == bug_report_url)
    120       return i;
    121   }
    122 
    123   return -1;
    124 }
    125 
    126 }  // namespace
    127 
    128 
    129 namespace browser {
    130 
    131 // TODO(rkc): Eventually find a better way to do this
    132 std::vector<unsigned char>* last_screenshot_png = 0;
    133 gfx::Rect screen_size;
    134 
    135 void RefreshLastScreenshot(Browser* browser) {
    136   if (last_screenshot_png)
    137     last_screenshot_png->clear();
    138   else
    139     last_screenshot_png = new std::vector<unsigned char>;
    140 
    141   gfx::NativeWindow native_window = browser->window()->GetNativeHandle();
    142   screen_size = browser::GrabWindowSnapshot(native_window, last_screenshot_png);
    143 }
    144 
    145 void ShowHtmlBugReportView(Browser* browser) {
    146   // First check if we're already open (we cannot depend on ShowSingletonTab
    147   // for this functionality since we need to make *sure* we never get
    148   // instantiated again while we are open - with singleton tabs, that can
    149   // happen)
    150   int feedback_tab_index = GetIndexOfFeedbackTab(browser);
    151   if (feedback_tab_index >=0) {
    152     // Do not refresh screenshot, do not create a new tab
    153     browser->ActivateTabAt(feedback_tab_index, true);
    154     return;
    155   }
    156 
    157   RefreshLastScreenshot(browser);
    158   std::string bug_report_url = std::string(chrome::kChromeUIBugReportURL) +
    159       "#" + base::IntToString(browser->active_index());
    160   browser->ShowSingletonTab(GURL(bug_report_url));
    161 }
    162 
    163 }  // namespace browser
    164 
    165 
    166 class BugReportUIHTMLSource : public ChromeURLDataManager::DataSource {
    167  public:
    168   explicit BugReportUIHTMLSource(base::StringPiece html);
    169 
    170   // Called when the network layer has requested a resource underneath
    171   // the path we registered.
    172   virtual void StartDataRequest(const std::string& path,
    173                                 bool is_incognito,
    174                                 int request_id);
    175   virtual std::string GetMimeType(const std::string&) const {
    176     return "text/html";
    177   }
    178 
    179  private:
    180   base::StringPiece bug_report_html_;
    181   ~BugReportUIHTMLSource() {}
    182 
    183   DISALLOW_COPY_AND_ASSIGN(BugReportUIHTMLSource);
    184 };
    185 
    186 // The handler for Javascript messages related to the "bug report" dialog
    187 class BugReportHandler : public WebUIMessageHandler,
    188                          public base::SupportsWeakPtr<BugReportHandler> {
    189  public:
    190   explicit BugReportHandler(TabContents* tab);
    191   virtual ~BugReportHandler();
    192 
    193   // Init work after Attach.
    194   base::StringPiece Init();
    195 
    196   // WebUIMessageHandler implementation.
    197   virtual WebUIMessageHandler* Attach(WebUI* web_ui);
    198   virtual void RegisterMessages();
    199 
    200  private:
    201   void HandleGetDialogDefaults(const ListValue* args);
    202   void HandleRefreshCurrentScreenshot(const ListValue* args);
    203 #if defined(OS_CHROMEOS)
    204   void HandleRefreshSavedScreenshots(const ListValue* args);
    205 #endif
    206   void HandleSendReport(const ListValue* args);
    207   void HandleCancel(const ListValue* args);
    208   void HandleOpenSystemTab(const ListValue* args);
    209 
    210   void SetupScreenshotsSource();
    211   void ClobberScreenshotsSource();
    212 
    213   void CancelFeedbackCollection();
    214   void CloseFeedbackTab();
    215 
    216   TabContents* tab_;
    217   ScreenshotSource* screenshot_source_;
    218 
    219   BugReportData* bug_report_;
    220   std::string target_tab_url_;
    221 #if defined(OS_CHROMEOS)
    222   // Variables to track SyslogsLibrary::RequestSyslogs callback.
    223   chromeos::SyslogsLibrary::Handle syslogs_handle_;
    224   CancelableRequestConsumer syslogs_consumer_;
    225 #endif
    226 
    227   DISALLOW_COPY_AND_ASSIGN(BugReportHandler);
    228 };
    229 
    230 ////////////////////////////////////////////////////////////////////////////////
    231 //
    232 // BugReportHTMLSource
    233 //
    234 ////////////////////////////////////////////////////////////////////////////////
    235 
    236 BugReportUIHTMLSource::BugReportUIHTMLSource(base::StringPiece html)
    237     : DataSource(chrome::kChromeUIBugReportHost, MessageLoop::current()) {
    238   bug_report_html_ = html;
    239 }
    240 
    241 void BugReportUIHTMLSource::StartDataRequest(const std::string& path,
    242                                              bool is_incognito,
    243                                              int request_id) {
    244   DictionaryValue localized_strings;
    245   localized_strings.SetString(std::string("title"),
    246       l10n_util::GetStringUTF8(IDS_BUGREPORT_TITLE));
    247   localized_strings.SetString(std::string("page-title"),
    248       l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_PAGE_TITLE));
    249   localized_strings.SetString(std::string("issue-with"),
    250       l10n_util::GetStringUTF8(IDS_BUGREPORT_ISSUE_WITH));
    251   localized_strings.SetString(std::string("page-url"),
    252       l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_URL_LABEL));
    253   localized_strings.SetString(std::string("description"),
    254       l10n_util::GetStringUTF8(IDS_BUGREPORT_DESCRIPTION_LABEL));
    255   localized_strings.SetString(std::string("current-screenshot"),
    256       l10n_util::GetStringUTF8(IDS_BUGREPORT_SCREENSHOT_LABEL));
    257   localized_strings.SetString(std::string("saved-screenshot"),
    258       l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOT_LABEL));
    259 #if defined(OS_CHROMEOS)
    260   localized_strings.SetString(std::string("user-email"),
    261       l10n_util::GetStringUTF8(IDS_BUGREPORT_USER_EMAIL_LABEL));
    262   localized_strings.SetString(std::string("sysinfo"),
    263       l10n_util::GetStringUTF8(
    264           IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX));
    265 
    266   localized_strings.SetString(std::string("currentscreenshots"),
    267       l10n_util::GetStringUTF8(IDS_BUGREPORT_CURRENT_SCREENSHOTS));
    268   localized_strings.SetString(std::string("savedscreenshots"),
    269       l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOTS));
    270 
    271   localized_strings.SetString(std::string("choose-different-screenshot"),
    272       l10n_util::GetStringUTF8(
    273           IDS_BUGREPORT_CHOOSE_DIFFERENT_SCREENSHOT));
    274   localized_strings.SetString(std::string("choose-original-screenshot"),
    275       l10n_util::GetStringUTF8(
    276           IDS_BUGREPORT_CHOOSE_ORIGINAL_SCREENSHOT));
    277 #else
    278   localized_strings.SetString(std::string("currentscreenshots"),
    279       l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE));
    280 #endif
    281   localized_strings.SetString(std::string("noscreenshot"),
    282       l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NO_SCREENSHOT));
    283 
    284   localized_strings.SetString(std::string("send-report"),
    285       l10n_util::GetStringUTF8(IDS_BUGREPORT_SEND_REPORT));
    286   localized_strings.SetString(std::string("cancel"),
    287       l10n_util::GetStringUTF8(IDS_CANCEL));
    288 
    289   // Option strings for the "issue with" drop-down.
    290   localized_strings.SetString(std::string("issue-choose"),
    291       l10n_util::GetStringUTF8(IDS_BUGREPORT_CHOOSE_ISSUE));
    292 
    293   localized_strings.SetString(std::string("no-issue-selected"),
    294       l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_ISSUE_SELECTED));
    295 
    296   localized_strings.SetString(std::string("no-description"),
    297       l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_DESCRIPTION));
    298 
    299   localized_strings.SetString(std::string("no-saved-screenshots"),
    300       l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_SAVED_SCREENSHOTS_HELP));
    301 
    302   localized_strings.SetString(std::string("privacy-note"),
    303       l10n_util::GetStringUTF8(IDS_BUGREPORT_PRIVACY_NOTE));
    304 
    305   // TODO(rkc): Find some way to ensure this order of dropdowns is in sync
    306   // with the order in the userfeedback ChromeData proto buffer
    307 #if defined(OS_CHROMEOS)
    308   // Dropdown for ChromeOS:
    309   //
    310   // Connectivity
    311   // Sync
    312   // Crash
    313   // Page Formatting
    314   // Extensions or Apps
    315   // Standby or Resume
    316   // Phishing Page
    317   // General Feedback/Other
    318 
    319   localized_strings.SetString(std::string("issue-connectivity"),
    320       l10n_util::GetStringUTF8(IDS_BUGREPORT_CONNECTIVITY));
    321   localized_strings.SetString(std::string("issue-sync"),
    322       l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
    323   localized_strings.SetString(std::string("issue-crashes"),
    324       l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
    325   localized_strings.SetString(std::string("issue-page-formatting"),
    326       l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
    327   localized_strings.SetString(std::string("issue-extensions"),
    328       l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
    329   localized_strings.SetString(std::string("issue-standby"),
    330       l10n_util::GetStringUTF8(IDS_BUGREPORT_STANDBY_RESUME));
    331   localized_strings.SetString(std::string("issue-phishing"),
    332       l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
    333   localized_strings.SetString(std::string("issue-other"),
    334       l10n_util::GetStringUTF8(IDS_BUGREPORT_GENERAL));
    335 #else
    336   // Dropdown for Chrome:
    337   //
    338   // Page formatting or layout
    339   // Pages not loading
    340   // Plug-ins (e.g. Adobe Flash Player, Quicktime, etc)
    341   // Tabs or windows
    342   // Synced preferences
    343   // Crashes
    344   // Extensions or apps
    345   // Phishing
    346   // Other
    347 
    348   localized_strings.SetString(std::string("issue-page-formatting"),
    349       l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
    350   localized_strings.SetString(std::string("issue-page-load"),
    351       l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_LOAD));
    352   localized_strings.SetString(std::string("issue-plugins"),
    353       l10n_util::GetStringUTF8(IDS_BUGREPORT_PLUGINS));
    354   localized_strings.SetString(std::string("issue-tabs"),
    355       l10n_util::GetStringUTF8(IDS_BUGREPORT_TABS));
    356   localized_strings.SetString(std::string("issue-sync"),
    357       l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
    358   localized_strings.SetString(std::string("issue-crashes"),
    359       l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
    360   localized_strings.SetString(std::string("issue-extensions"),
    361       l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
    362   localized_strings.SetString(std::string("issue-phishing"),
    363       l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
    364   localized_strings.SetString(std::string("issue-other"),
    365       l10n_util::GetStringUTF8(IDS_BUGREPORT_OTHER));
    366 #endif
    367 
    368   SetFontAndTextDirection(&localized_strings);
    369 
    370   const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
    371       bug_report_html_, &localized_strings);
    372 
    373   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
    374   html_bytes->data.resize(full_html.size());
    375   std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
    376 
    377   SendResponse(request_id, html_bytes);
    378 }
    379 
    380 
    381 ////////////////////////////////////////////////////////////////////////////////
    382 //
    383 // BugReportData
    384 //
    385 ////////////////////////////////////////////////////////////////////////////////
    386 void BugReportData::SendReport() {
    387 #if defined(OS_CHROMEOS)
    388   // In case we already got the syslogs and sent the report, leave
    389   if (sent_report_) return;
    390   // Set send_report_ so that no one else processes SendReport
    391   sent_report_ = true;
    392 #endif
    393 
    394   int image_data_size = image_.size();
    395   char* image_data = image_data_size ?
    396       reinterpret_cast<char*>(&(image_.front())) : NULL;
    397   BugReportUtil::SendReport(profile_
    398                             , problem_type_
    399                             , page_url_
    400                             , description_
    401                             , image_data
    402                             , image_data_size
    403                             , browser::screen_size.width()
    404                             , browser::screen_size.height()
    405 #if defined(OS_CHROMEOS)
    406                             , user_email_
    407                             , zip_content_ ? zip_content_->c_str() : NULL
    408                             , zip_content_ ? zip_content_->length() : 0
    409                             , send_sys_info_ ? sys_info_ : NULL
    410 #endif
    411                             );
    412 
    413 #if defined(OS_CHROMEOS)
    414   if (sys_info_) {
    415     delete sys_info_;
    416     sys_info_ = NULL;
    417   }
    418   if (zip_content_) {
    419     delete zip_content_;
    420     zip_content_ = NULL;
    421   }
    422 #endif
    423 
    424   // Once the report has been sent, this object has no purpose in life, delete
    425   // ourselves.
    426   delete this;
    427 }
    428 
    429 
    430 ////////////////////////////////////////////////////////////////////////////////
    431 //
    432 // BugReportHandler
    433 //
    434 ////////////////////////////////////////////////////////////////////////////////
    435 BugReportHandler::BugReportHandler(TabContents* tab)
    436     : tab_(tab),
    437       screenshot_source_(NULL),
    438       bug_report_(NULL)
    439 #if defined(OS_CHROMEOS)
    440     , syslogs_handle_(0)
    441 #endif
    442 {
    443 }
    444 
    445 BugReportHandler::~BugReportHandler() {
    446   // Just in case we didn't send off bug_report_ to SendReport
    447   if (bug_report_) {
    448     // If we're deleting the report object, cancel feedback collection first
    449     CancelFeedbackCollection();
    450     delete bug_report_;
    451   }
    452 }
    453 
    454 void BugReportHandler::ClobberScreenshotsSource() {
    455   // Re-create our screenshots data source (this clobbers the last source)
    456   // setting the screenshot to NULL, effectively disabling the source
    457   // TODO(rkc): Once there is a method to 'remove' a source, change this code
    458   tab_->profile()->GetChromeURLDataManager()->AddDataSource(
    459       new ScreenshotSource(NULL));
    460 
    461   // clobber last screenshot
    462   if (browser::last_screenshot_png)
    463     browser::last_screenshot_png->clear();
    464 }
    465 
    466 void BugReportHandler::SetupScreenshotsSource() {
    467   // If we don't already have a screenshot source object created, create one.
    468   if (!screenshot_source_)
    469     screenshot_source_ = new ScreenshotSource(
    470         browser::last_screenshot_png);
    471 
    472   // Add the source to the data manager.
    473   tab_->profile()->GetChromeURLDataManager()->AddDataSource(screenshot_source_);
    474 }
    475 
    476 WebUIMessageHandler* BugReportHandler::Attach(WebUI* web_ui) {
    477   SetupScreenshotsSource();
    478   return WebUIMessageHandler::Attach(web_ui);
    479 }
    480 
    481 base::StringPiece BugReportHandler::Init() {
    482   std::string page_url;
    483   if (tab_->controller().GetActiveEntry()) {
    484      page_url = tab_->controller().GetActiveEntry()->url().spec();
    485   }
    486 
    487   std::string params = page_url.substr(strlen(chrome::kChromeUIBugReportURL));
    488   // Erase the # - the first character.
    489   if (params.length())
    490     params.erase(params.begin(), params.begin() + 1);
    491 
    492   int index = 0;
    493   if (!base::StringToInt(params, &index)) {
    494     return base::StringPiece(
    495         ResourceBundle::GetSharedInstance().GetRawDataResource(
    496             IDR_BUGREPORT_HTML_INVALID));
    497   }
    498 
    499   Browser* browser = BrowserList::GetLastActive();
    500   // Sanity checks.
    501   if (((index == 0) && (params != "0")) || !browser ||
    502       index >= browser->tab_count()) {
    503     return base::StringPiece(
    504         ResourceBundle::GetSharedInstance().GetRawDataResource(
    505             IDR_BUGREPORT_HTML_INVALID));
    506   }
    507 
    508   TabContents* target_tab = browser->GetTabContentsAt(index);
    509   if (target_tab) {
    510     target_tab_url_ = target_tab->GetURL().spec();
    511   }
    512 
    513   // Setup the screenshot source after we've verified input is legit.
    514   SetupScreenshotsSource();
    515 
    516   return base::StringPiece(
    517       ResourceBundle::GetSharedInstance().GetRawDataResource(
    518           IDR_BUGREPORT_HTML));
    519 }
    520 
    521 void BugReportHandler::RegisterMessages() {
    522   web_ui_->RegisterMessageCallback("getDialogDefaults",
    523       NewCallback(this, &BugReportHandler::HandleGetDialogDefaults));
    524   web_ui_->RegisterMessageCallback("refreshCurrentScreenshot",
    525       NewCallback(this, &BugReportHandler::HandleRefreshCurrentScreenshot));
    526 #if defined(OS_CHROMEOS)
    527   web_ui_->RegisterMessageCallback("refreshSavedScreenshots",
    528       NewCallback(this, &BugReportHandler::HandleRefreshSavedScreenshots));
    529 #endif
    530   web_ui_->RegisterMessageCallback("sendReport",
    531       NewCallback(this, &BugReportHandler::HandleSendReport));
    532   web_ui_->RegisterMessageCallback("cancel",
    533       NewCallback(this, &BugReportHandler::HandleCancel));
    534   web_ui_->RegisterMessageCallback("openSystemTab",
    535       NewCallback(this, &BugReportHandler::HandleOpenSystemTab));
    536 }
    537 
    538 void BugReportHandler::HandleGetDialogDefaults(const ListValue*) {
    539   bug_report_ = new BugReportData();
    540 
    541   // send back values which the dialog js needs initially
    542   ListValue dialog_defaults;
    543 
    544   // 0: current url
    545   if (target_tab_url_.length())
    546     dialog_defaults.Append(new StringValue(target_tab_url_));
    547   else
    548     dialog_defaults.Append(new StringValue(""));
    549 
    550 #if defined(OS_CHROMEOS)
    551   // 1: about:system
    552   dialog_defaults.Append(new StringValue(chrome::kChromeUISystemInfoURL));
    553   // Trigger the request for system information here.
    554   chromeos::SyslogsLibrary* syslogs_lib =
    555       chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
    556   if (syslogs_lib) {
    557     syslogs_handle_ = syslogs_lib->RequestSyslogs(
    558         true, true, &syslogs_consumer_,
    559         NewCallback(bug_report_, &BugReportData::SyslogsComplete));
    560   }
    561   // 2: user e-mail
    562   dialog_defaults.Append(new StringValue(GetUserEmail()));
    563 #endif
    564 
    565   web_ui_->CallJavascriptFunction("setupDialogDefaults", dialog_defaults);
    566 }
    567 
    568 void BugReportHandler::HandleRefreshCurrentScreenshot(const ListValue*) {
    569   std::string current_screenshot(kCurrentScreenshotUrl);
    570   StringValue screenshot(current_screenshot);
    571   web_ui_->CallJavascriptFunction("setupCurrentScreenshot", screenshot);
    572 }
    573 
    574 
    575 #if defined(OS_CHROMEOS)
    576 void BugReportHandler::HandleRefreshSavedScreenshots(const ListValue*) {
    577   std::vector<std::string> saved_screenshots;
    578   GetScreenshotUrls(&saved_screenshots);
    579 
    580   ListValue screenshots_list;
    581   for (size_t i = 0; i < saved_screenshots.size(); ++i)
    582     screenshots_list.Append(new StringValue(saved_screenshots[i]));
    583   web_ui_->CallJavascriptFunction("setupSavedScreenshots", screenshots_list);
    584 }
    585 #endif
    586 
    587 
    588 void BugReportHandler::HandleSendReport(const ListValue* list_value) {
    589   if (!bug_report_) {
    590     LOG(ERROR) << "Bug report hasn't been intialized yet.";
    591     return;
    592   }
    593 
    594   ListValue::const_iterator i = list_value->begin();
    595   if (i == list_value->end()) {
    596     LOG(ERROR) << "Incorrect data passed to sendReport.";
    597     return;
    598   }
    599 
    600   // #0 - Problem type.
    601   int problem_type;
    602   std::string problem_type_str;
    603   (*i)->GetAsString(&problem_type_str);
    604   if (!base::StringToInt(problem_type_str, &problem_type)) {
    605     LOG(ERROR) << "Incorrect data passed to sendReport.";
    606     return;
    607   }
    608   if (++i == list_value->end()) {
    609     LOG(ERROR) << "Incorrect data passed to sendReport.";
    610     return;
    611   }
    612 
    613   // #1 - Page url.
    614   std::string page_url;
    615   (*i)->GetAsString(&page_url);
    616   if (++i == list_value->end()) {
    617     LOG(ERROR) << "Incorrect data passed to sendReport.";
    618     return;
    619   }
    620 
    621   // #2 - Description.
    622   std::string description;
    623   (*i)->GetAsString(&description);
    624   if (++i == list_value->end()) {
    625     LOG(ERROR) << "Incorrect data passed to sendReport.";
    626     return;
    627   }
    628 
    629   // #3 -  Screenshot to send.
    630   std::string screenshot_path;
    631   (*i)->GetAsString(&screenshot_path);
    632   screenshot_path.erase(0, strlen(kScreenshotBaseUrl));
    633 
    634   // Get the image to send in the report.
    635   std::vector<unsigned char> image;
    636   if (!screenshot_path.empty())
    637     image = screenshot_source_->GetScreenshot(screenshot_path);
    638 
    639 #if defined(OS_CHROMEOS)
    640   if (++i == list_value->end()) {
    641     LOG(ERROR) << "Incorrect data passed to sendReport.";
    642     return;
    643   }
    644 
    645   // #4 - User e-mail
    646   std::string user_email;
    647   (*i)->GetAsString(&user_email);
    648   if (++i == list_value->end()) {
    649     LOG(ERROR) << "Incorrect data passed to sendReport.";
    650     return;
    651   }
    652 
    653   // #5 - System info checkbox.
    654   std::string sys_info_checkbox;
    655   (*i)->GetAsString(&sys_info_checkbox);
    656   bool send_sys_info = (sys_info_checkbox == "true");
    657 
    658   // If we aren't sending the sys_info, cancel the gathering of the syslogs.
    659   if (!send_sys_info)
    660     CancelFeedbackCollection();
    661 #endif
    662 
    663   // Update the data in bug_report_ so it can be sent
    664   bug_report_->UpdateData(web_ui_->GetProfile()
    665                           , target_tab_url_
    666                           , problem_type
    667                           , page_url
    668                           , description
    669                           , image
    670 #if defined(OS_CHROMEOS)
    671                           , user_email
    672                           , send_sys_info
    673                           , false // sent_report
    674 #endif
    675                           );
    676 
    677 #if defined(OS_CHROMEOS)
    678   // If we don't require sys_info, or we have it, or we never requested it
    679   // (because libcros failed to load), then send the report now.
    680   // Otherwise, the report will get sent when we receive sys_info.
    681   if (!send_sys_info || bug_report_->sys_info() != NULL ||
    682       syslogs_handle_ == 0) {
    683     bug_report_->SendReport();
    684   }
    685 #else
    686   bug_report_->SendReport();
    687 #endif
    688   // Lose the pointer to the BugReportData object; the object will delete itself
    689   // from SendReport, whether we called it, or will be called by the log
    690   // completion routine.
    691   bug_report_ = NULL;
    692 
    693   // Whether we sent the report, or if it will be sent by the Syslogs complete
    694   // function, close our feedback tab anyway, we have no more use for it.
    695   CloseFeedbackTab();
    696 }
    697 
    698 void BugReportHandler::HandleCancel(const ListValue*) {
    699   CloseFeedbackTab();
    700 }
    701 
    702 void BugReportHandler::HandleOpenSystemTab(const ListValue* args) {
    703 #if defined(OS_CHROMEOS)
    704   BrowserList::GetLastActive()->OpenSystemTabAndActivate();
    705 #endif
    706 }
    707 
    708 void BugReportHandler::CancelFeedbackCollection() {
    709 #if defined(OS_CHROMEOS)
    710   if (syslogs_handle_ != 0) {
    711     chromeos::SyslogsLibrary* syslogs_lib =
    712         chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
    713     if (syslogs_lib)
    714       syslogs_lib->CancelRequest(syslogs_handle_);
    715   }
    716 #endif
    717 }
    718 
    719 void BugReportHandler::CloseFeedbackTab() {
    720   ClobberScreenshotsSource();
    721 
    722   Browser* browser = BrowserList::GetLastActive();
    723   if (browser) {
    724     browser->CloseTabContents(tab_);
    725   } else {
    726     LOG(FATAL) << "Failed to get last active browser.";
    727   }
    728 }
    729 
    730 ////////////////////////////////////////////////////////////////////////////////
    731 //
    732 // BugReportUI
    733 //
    734 ////////////////////////////////////////////////////////////////////////////////
    735 BugReportUI::BugReportUI(TabContents* tab) : HtmlDialogUI(tab) {
    736   BugReportHandler* handler = new BugReportHandler(tab);
    737   AddMessageHandler((handler)->Attach(this));
    738 
    739   // The handler's init will specify which html
    740   // resource we'll display to the user
    741   BugReportUIHTMLSource* html_source =
    742       new BugReportUIHTMLSource(handler->Init());
    743   // Set up the chrome://bugreport/ source.
    744   tab->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
    745 }
    746