普通文本  |  746行  |  25.08 KB

// Copyright (c) 2011 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/ui/webui/bug_report_ui.h"

#include <algorithm>
#include <string>
#include <vector>

#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bug_report_data.h"
#include "chrome/browser/bug_report_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/screenshot_source.h"
#include "chrome/browser/ui/window_snapshot/window_snapshot.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/rect.h"

#if defined(OS_CHROMEOS)
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/syslogs_library.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#endif

namespace {

const char kScreenshotBaseUrl[] = "chrome://screenshots/";
const char kCurrentScreenshotUrl[] = "chrome://screenshots/current";
#if defined(OS_CHROMEOS)
const char kSavedScreenshotsUrl[] = "chrome://screenshots/saved/";

const char kScreenshotPattern[] = "*.png";
const char kScreenshotsRelativePath[] = "/Screenshots";

const size_t kMaxSavedScreenshots = 2;
#endif

#if defined(OS_CHROMEOS)

void GetSavedScreenshots(std::vector<std::string>* saved_screenshots,
                         base::WaitableEvent* done) {
  saved_screenshots->clear();

  FilePath fileshelf_path;
  if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
                        &fileshelf_path)) {
    done->Signal();
    return;
  }

  // TODO(rkc): Change this to use FilePath.Append() once the cros
  // issue with it is fixed
  FilePath screenshots_path(fileshelf_path.value() +
                            std::string(kScreenshotsRelativePath));
  file_util::FileEnumerator screenshots(screenshots_path, false,
                                        file_util::FileEnumerator::FILES,
                                        std::string(kScreenshotPattern));
  FilePath screenshot = screenshots.Next();
  while (!screenshot.empty()) {
    saved_screenshots->push_back(std::string(kSavedScreenshotsUrl) +
                                 screenshot.BaseName().value());
    if (saved_screenshots->size() >= kMaxSavedScreenshots)
      break;

    screenshot = screenshots.Next();
  }
  done->Signal();
}

// This fuction posts a task to the file thread to create/list all the current
// and saved screenshots.
void GetScreenshotUrls(std::vector<std::string>* saved_screenshots) {
  base::WaitableEvent done(true, false);
  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                          NewRunnableFunction(&GetSavedScreenshots,
                                              saved_screenshots, &done));
  done.Wait();
}

std::string GetUserEmail() {
  chromeos::UserManager* manager = chromeos::UserManager::Get();
  if (!manager)
    return std::string();
  else
    return manager->logged_in_user().email();
}
#endif

// Returns the index of the feedback tab if already open, -1 otherwise
int GetIndexOfFeedbackTab(Browser* browser) {
  GURL bug_report_url(chrome::kChromeUIBugReportURL);
  for (int i = 0; i < browser->tab_count(); ++i) {
    TabContents* tab = browser->GetTabContentsAt(i);
    if (tab && tab->GetURL().GetWithEmptyPath() == bug_report_url)
      return i;
  }

  return -1;
}

}  // namespace


namespace browser {

// TODO(rkc): Eventually find a better way to do this
std::vector<unsigned char>* last_screenshot_png = 0;
gfx::Rect screen_size;

void RefreshLastScreenshot(Browser* browser) {
  if (last_screenshot_png)
    last_screenshot_png->clear();
  else
    last_screenshot_png = new std::vector<unsigned char>;

  gfx::NativeWindow native_window = browser->window()->GetNativeHandle();
  screen_size = browser::GrabWindowSnapshot(native_window, last_screenshot_png);
}

void ShowHtmlBugReportView(Browser* browser) {
  // First check if we're already open (we cannot depend on ShowSingletonTab
  // for this functionality since we need to make *sure* we never get
  // instantiated again while we are open - with singleton tabs, that can
  // happen)
  int feedback_tab_index = GetIndexOfFeedbackTab(browser);
  if (feedback_tab_index >=0) {
    // Do not refresh screenshot, do not create a new tab
    browser->ActivateTabAt(feedback_tab_index, true);
    return;
  }

  RefreshLastScreenshot(browser);
  std::string bug_report_url = std::string(chrome::kChromeUIBugReportURL) +
      "#" + base::IntToString(browser->active_index());
  browser->ShowSingletonTab(GURL(bug_report_url));
}

}  // namespace browser


class BugReportUIHTMLSource : public ChromeURLDataManager::DataSource {
 public:
  explicit BugReportUIHTMLSource(base::StringPiece html);

  // Called when the network layer has requested a resource underneath
  // the path we registered.
  virtual void StartDataRequest(const std::string& path,
                                bool is_incognito,
                                int request_id);
  virtual std::string GetMimeType(const std::string&) const {
    return "text/html";
  }

 private:
  base::StringPiece bug_report_html_;
  ~BugReportUIHTMLSource() {}

  DISALLOW_COPY_AND_ASSIGN(BugReportUIHTMLSource);
};

// The handler for Javascript messages related to the "bug report" dialog
class BugReportHandler : public WebUIMessageHandler,
                         public base::SupportsWeakPtr<BugReportHandler> {
 public:
  explicit BugReportHandler(TabContents* tab);
  virtual ~BugReportHandler();

  // Init work after Attach.
  base::StringPiece Init();

  // WebUIMessageHandler implementation.
  virtual WebUIMessageHandler* Attach(WebUI* web_ui);
  virtual void RegisterMessages();

 private:
  void HandleGetDialogDefaults(const ListValue* args);
  void HandleRefreshCurrentScreenshot(const ListValue* args);
#if defined(OS_CHROMEOS)
  void HandleRefreshSavedScreenshots(const ListValue* args);
#endif
  void HandleSendReport(const ListValue* args);
  void HandleCancel(const ListValue* args);
  void HandleOpenSystemTab(const ListValue* args);

  void SetupScreenshotsSource();
  void ClobberScreenshotsSource();

  void CancelFeedbackCollection();
  void CloseFeedbackTab();

  TabContents* tab_;
  ScreenshotSource* screenshot_source_;

  BugReportData* bug_report_;
  std::string target_tab_url_;
#if defined(OS_CHROMEOS)
  // Variables to track SyslogsLibrary::RequestSyslogs callback.
  chromeos::SyslogsLibrary::Handle syslogs_handle_;
  CancelableRequestConsumer syslogs_consumer_;
#endif

  DISALLOW_COPY_AND_ASSIGN(BugReportHandler);
};

////////////////////////////////////////////////////////////////////////////////
//
// BugReportHTMLSource
//
////////////////////////////////////////////////////////////////////////////////

BugReportUIHTMLSource::BugReportUIHTMLSource(base::StringPiece html)
    : DataSource(chrome::kChromeUIBugReportHost, MessageLoop::current()) {
  bug_report_html_ = html;
}

void BugReportUIHTMLSource::StartDataRequest(const std::string& path,
                                             bool is_incognito,
                                             int request_id) {
  DictionaryValue localized_strings;
  localized_strings.SetString(std::string("title"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_TITLE));
  localized_strings.SetString(std::string("page-title"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_PAGE_TITLE));
  localized_strings.SetString(std::string("issue-with"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_ISSUE_WITH));
  localized_strings.SetString(std::string("page-url"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_URL_LABEL));
  localized_strings.SetString(std::string("description"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_DESCRIPTION_LABEL));
  localized_strings.SetString(std::string("current-screenshot"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SCREENSHOT_LABEL));
  localized_strings.SetString(std::string("saved-screenshot"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOT_LABEL));
#if defined(OS_CHROMEOS)
  localized_strings.SetString(std::string("user-email"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_USER_EMAIL_LABEL));
  localized_strings.SetString(std::string("sysinfo"),
      l10n_util::GetStringUTF8(
          IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX));

  localized_strings.SetString(std::string("currentscreenshots"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_CURRENT_SCREENSHOTS));
  localized_strings.SetString(std::string("savedscreenshots"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOTS));

  localized_strings.SetString(std::string("choose-different-screenshot"),
      l10n_util::GetStringUTF8(
          IDS_BUGREPORT_CHOOSE_DIFFERENT_SCREENSHOT));
  localized_strings.SetString(std::string("choose-original-screenshot"),
      l10n_util::GetStringUTF8(
          IDS_BUGREPORT_CHOOSE_ORIGINAL_SCREENSHOT));
#else
  localized_strings.SetString(std::string("currentscreenshots"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE));
#endif
  localized_strings.SetString(std::string("noscreenshot"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NO_SCREENSHOT));

  localized_strings.SetString(std::string("send-report"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SEND_REPORT));
  localized_strings.SetString(std::string("cancel"),
      l10n_util::GetStringUTF8(IDS_CANCEL));

  // Option strings for the "issue with" drop-down.
  localized_strings.SetString(std::string("issue-choose"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_CHOOSE_ISSUE));

  localized_strings.SetString(std::string("no-issue-selected"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_ISSUE_SELECTED));

  localized_strings.SetString(std::string("no-description"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_DESCRIPTION));

  localized_strings.SetString(std::string("no-saved-screenshots"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_SAVED_SCREENSHOTS_HELP));

  localized_strings.SetString(std::string("privacy-note"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PRIVACY_NOTE));

  // TODO(rkc): Find some way to ensure this order of dropdowns is in sync
  // with the order in the userfeedback ChromeData proto buffer
#if defined(OS_CHROMEOS)
  // Dropdown for ChromeOS:
  //
  // Connectivity
  // Sync
  // Crash
  // Page Formatting
  // Extensions or Apps
  // Standby or Resume
  // Phishing Page
  // General Feedback/Other

  localized_strings.SetString(std::string("issue-connectivity"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_CONNECTIVITY));
  localized_strings.SetString(std::string("issue-sync"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
  localized_strings.SetString(std::string("issue-crashes"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
  localized_strings.SetString(std::string("issue-page-formatting"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
  localized_strings.SetString(std::string("issue-extensions"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
  localized_strings.SetString(std::string("issue-standby"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_STANDBY_RESUME));
  localized_strings.SetString(std::string("issue-phishing"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
  localized_strings.SetString(std::string("issue-other"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_GENERAL));
#else
  // Dropdown for Chrome:
  //
  // Page formatting or layout
  // Pages not loading
  // Plug-ins (e.g. Adobe Flash Player, Quicktime, etc)
  // Tabs or windows
  // Synced preferences
  // Crashes
  // Extensions or apps
  // Phishing
  // Other

  localized_strings.SetString(std::string("issue-page-formatting"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING));
  localized_strings.SetString(std::string("issue-page-load"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_LOAD));
  localized_strings.SetString(std::string("issue-plugins"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PLUGINS));
  localized_strings.SetString(std::string("issue-tabs"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_TABS));
  localized_strings.SetString(std::string("issue-sync"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC));
  localized_strings.SetString(std::string("issue-crashes"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES));
  localized_strings.SetString(std::string("issue-extensions"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS));
  localized_strings.SetString(std::string("issue-phishing"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE));
  localized_strings.SetString(std::string("issue-other"),
      l10n_util::GetStringUTF8(IDS_BUGREPORT_OTHER));
#endif

  SetFontAndTextDirection(&localized_strings);

  const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
      bug_report_html_, &localized_strings);

  scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
  html_bytes->data.resize(full_html.size());
  std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());

  SendResponse(request_id, html_bytes);
}


////////////////////////////////////////////////////////////////////////////////
//
// BugReportData
//
////////////////////////////////////////////////////////////////////////////////
void BugReportData::SendReport() {
#if defined(OS_CHROMEOS)
  // In case we already got the syslogs and sent the report, leave
  if (sent_report_) return;
  // Set send_report_ so that no one else processes SendReport
  sent_report_ = true;
#endif

  int image_data_size = image_.size();
  char* image_data = image_data_size ?
      reinterpret_cast<char*>(&(image_.front())) : NULL;
  BugReportUtil::SendReport(profile_
                            , problem_type_
                            , page_url_
                            , description_
                            , image_data
                            , image_data_size
                            , browser::screen_size.width()
                            , browser::screen_size.height()
#if defined(OS_CHROMEOS)
                            , user_email_
                            , zip_content_ ? zip_content_->c_str() : NULL
                            , zip_content_ ? zip_content_->length() : 0
                            , send_sys_info_ ? sys_info_ : NULL
#endif
                            );

#if defined(OS_CHROMEOS)
  if (sys_info_) {
    delete sys_info_;
    sys_info_ = NULL;
  }
  if (zip_content_) {
    delete zip_content_;
    zip_content_ = NULL;
  }
#endif

  // Once the report has been sent, this object has no purpose in life, delete
  // ourselves.
  delete this;
}


////////////////////////////////////////////////////////////////////////////////
//
// BugReportHandler
//
////////////////////////////////////////////////////////////////////////////////
BugReportHandler::BugReportHandler(TabContents* tab)
    : tab_(tab),
      screenshot_source_(NULL),
      bug_report_(NULL)
#if defined(OS_CHROMEOS)
    , syslogs_handle_(0)
#endif
{
}

BugReportHandler::~BugReportHandler() {
  // Just in case we didn't send off bug_report_ to SendReport
  if (bug_report_) {
    // If we're deleting the report object, cancel feedback collection first
    CancelFeedbackCollection();
    delete bug_report_;
  }
}

void BugReportHandler::ClobberScreenshotsSource() {
  // Re-create our screenshots data source (this clobbers the last source)
  // setting the screenshot to NULL, effectively disabling the source
  // TODO(rkc): Once there is a method to 'remove' a source, change this code
  tab_->profile()->GetChromeURLDataManager()->AddDataSource(
      new ScreenshotSource(NULL));

  // clobber last screenshot
  if (browser::last_screenshot_png)
    browser::last_screenshot_png->clear();
}

void BugReportHandler::SetupScreenshotsSource() {
  // If we don't already have a screenshot source object created, create one.
  if (!screenshot_source_)
    screenshot_source_ = new ScreenshotSource(
        browser::last_screenshot_png);

  // Add the source to the data manager.
  tab_->profile()->GetChromeURLDataManager()->AddDataSource(screenshot_source_);
}

WebUIMessageHandler* BugReportHandler::Attach(WebUI* web_ui) {
  SetupScreenshotsSource();
  return WebUIMessageHandler::Attach(web_ui);
}

base::StringPiece BugReportHandler::Init() {
  std::string page_url;
  if (tab_->controller().GetActiveEntry()) {
     page_url = tab_->controller().GetActiveEntry()->url().spec();
  }

  std::string params = page_url.substr(strlen(chrome::kChromeUIBugReportURL));
  // Erase the # - the first character.
  if (params.length())
    params.erase(params.begin(), params.begin() + 1);

  int index = 0;
  if (!base::StringToInt(params, &index)) {
    return base::StringPiece(
        ResourceBundle::GetSharedInstance().GetRawDataResource(
            IDR_BUGREPORT_HTML_INVALID));
  }

  Browser* browser = BrowserList::GetLastActive();
  // Sanity checks.
  if (((index == 0) && (params != "0")) || !browser ||
      index >= browser->tab_count()) {
    return base::StringPiece(
        ResourceBundle::GetSharedInstance().GetRawDataResource(
            IDR_BUGREPORT_HTML_INVALID));
  }

  TabContents* target_tab = browser->GetTabContentsAt(index);
  if (target_tab) {
    target_tab_url_ = target_tab->GetURL().spec();
  }

  // Setup the screenshot source after we've verified input is legit.
  SetupScreenshotsSource();

  return base::StringPiece(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_BUGREPORT_HTML));
}

void BugReportHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getDialogDefaults",
      NewCallback(this, &BugReportHandler::HandleGetDialogDefaults));
  web_ui_->RegisterMessageCallback("refreshCurrentScreenshot",
      NewCallback(this, &BugReportHandler::HandleRefreshCurrentScreenshot));
#if defined(OS_CHROMEOS)
  web_ui_->RegisterMessageCallback("refreshSavedScreenshots",
      NewCallback(this, &BugReportHandler::HandleRefreshSavedScreenshots));
#endif
  web_ui_->RegisterMessageCallback("sendReport",
      NewCallback(this, &BugReportHandler::HandleSendReport));
  web_ui_->RegisterMessageCallback("cancel",
      NewCallback(this, &BugReportHandler::HandleCancel));
  web_ui_->RegisterMessageCallback("openSystemTab",
      NewCallback(this, &BugReportHandler::HandleOpenSystemTab));
}

void BugReportHandler::HandleGetDialogDefaults(const ListValue*) {
  bug_report_ = new BugReportData();

  // send back values which the dialog js needs initially
  ListValue dialog_defaults;

  // 0: current url
  if (target_tab_url_.length())
    dialog_defaults.Append(new StringValue(target_tab_url_));
  else
    dialog_defaults.Append(new StringValue(""));

#if defined(OS_CHROMEOS)
  // 1: about:system
  dialog_defaults.Append(new StringValue(chrome::kChromeUISystemInfoURL));
  // Trigger the request for system information here.
  chromeos::SyslogsLibrary* syslogs_lib =
      chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
  if (syslogs_lib) {
    syslogs_handle_ = syslogs_lib->RequestSyslogs(
        true, true, &syslogs_consumer_,
        NewCallback(bug_report_, &BugReportData::SyslogsComplete));
  }
  // 2: user e-mail
  dialog_defaults.Append(new StringValue(GetUserEmail()));
#endif

  web_ui_->CallJavascriptFunction("setupDialogDefaults", dialog_defaults);
}

void BugReportHandler::HandleRefreshCurrentScreenshot(const ListValue*) {
  std::string current_screenshot(kCurrentScreenshotUrl);
  StringValue screenshot(current_screenshot);
  web_ui_->CallJavascriptFunction("setupCurrentScreenshot", screenshot);
}


#if defined(OS_CHROMEOS)
void BugReportHandler::HandleRefreshSavedScreenshots(const ListValue*) {
  std::vector<std::string> saved_screenshots;
  GetScreenshotUrls(&saved_screenshots);

  ListValue screenshots_list;
  for (size_t i = 0; i < saved_screenshots.size(); ++i)
    screenshots_list.Append(new StringValue(saved_screenshots[i]));
  web_ui_->CallJavascriptFunction("setupSavedScreenshots", screenshots_list);
}
#endif


void BugReportHandler::HandleSendReport(const ListValue* list_value) {
  if (!bug_report_) {
    LOG(ERROR) << "Bug report hasn't been intialized yet.";
    return;
  }

  ListValue::const_iterator i = list_value->begin();
  if (i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #0 - Problem type.
  int problem_type;
  std::string problem_type_str;
  (*i)->GetAsString(&problem_type_str);
  if (!base::StringToInt(problem_type_str, &problem_type)) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }
  if (++i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #1 - Page url.
  std::string page_url;
  (*i)->GetAsString(&page_url);
  if (++i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #2 - Description.
  std::string description;
  (*i)->GetAsString(&description);
  if (++i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #3 -  Screenshot to send.
  std::string screenshot_path;
  (*i)->GetAsString(&screenshot_path);
  screenshot_path.erase(0, strlen(kScreenshotBaseUrl));

  // Get the image to send in the report.
  std::vector<unsigned char> image;
  if (!screenshot_path.empty())
    image = screenshot_source_->GetScreenshot(screenshot_path);

#if defined(OS_CHROMEOS)
  if (++i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #4 - User e-mail
  std::string user_email;
  (*i)->GetAsString(&user_email);
  if (++i == list_value->end()) {
    LOG(ERROR) << "Incorrect data passed to sendReport.";
    return;
  }

  // #5 - System info checkbox.
  std::string sys_info_checkbox;
  (*i)->GetAsString(&sys_info_checkbox);
  bool send_sys_info = (sys_info_checkbox == "true");

  // If we aren't sending the sys_info, cancel the gathering of the syslogs.
  if (!send_sys_info)
    CancelFeedbackCollection();
#endif

  // Update the data in bug_report_ so it can be sent
  bug_report_->UpdateData(web_ui_->GetProfile()
                          , target_tab_url_
                          , problem_type
                          , page_url
                          , description
                          , image
#if defined(OS_CHROMEOS)
                          , user_email
                          , send_sys_info
                          , false // sent_report
#endif
                          );

#if defined(OS_CHROMEOS)
  // If we don't require sys_info, or we have it, or we never requested it
  // (because libcros failed to load), then send the report now.
  // Otherwise, the report will get sent when we receive sys_info.
  if (!send_sys_info || bug_report_->sys_info() != NULL ||
      syslogs_handle_ == 0) {
    bug_report_->SendReport();
  }
#else
  bug_report_->SendReport();
#endif
  // Lose the pointer to the BugReportData object; the object will delete itself
  // from SendReport, whether we called it, or will be called by the log
  // completion routine.
  bug_report_ = NULL;

  // Whether we sent the report, or if it will be sent by the Syslogs complete
  // function, close our feedback tab anyway, we have no more use for it.
  CloseFeedbackTab();
}

void BugReportHandler::HandleCancel(const ListValue*) {
  CloseFeedbackTab();
}

void BugReportHandler::HandleOpenSystemTab(const ListValue* args) {
#if defined(OS_CHROMEOS)
  BrowserList::GetLastActive()->OpenSystemTabAndActivate();
#endif
}

void BugReportHandler::CancelFeedbackCollection() {
#if defined(OS_CHROMEOS)
  if (syslogs_handle_ != 0) {
    chromeos::SyslogsLibrary* syslogs_lib =
        chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
    if (syslogs_lib)
      syslogs_lib->CancelRequest(syslogs_handle_);
  }
#endif
}

void BugReportHandler::CloseFeedbackTab() {
  ClobberScreenshotsSource();

  Browser* browser = BrowserList::GetLastActive();
  if (browser) {
    browser->CloseTabContents(tab_);
  } else {
    LOG(FATAL) << "Failed to get last active browser.";
  }
}

////////////////////////////////////////////////////////////////////////////////
//
// BugReportUI
//
////////////////////////////////////////////////////////////////////////////////
BugReportUI::BugReportUI(TabContents* tab) : HtmlDialogUI(tab) {
  BugReportHandler* handler = new BugReportHandler(tab);
  AddMessageHandler((handler)->Attach(this));

  // The handler's init will specify which html
  // resource we'll display to the user
  BugReportUIHTMLSource* html_source =
      new BugReportUIHTMLSource(handler->Init());
  // Set up the chrome://bugreport/ source.
  tab->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}