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
50namespace {
51
52const char kScreenshotBaseUrl[] = "chrome://screenshots/";
53const char kCurrentScreenshotUrl[] = "chrome://screenshots/current";
54#if defined(OS_CHROMEOS)
55const char kSavedScreenshotsUrl[] = "chrome://screenshots/saved/";
56
57const char kScreenshotPattern[] = "*.png";
58const char kScreenshotsRelativePath[] = "/Screenshots";
59
60const size_t kMaxSavedScreenshots = 2;
61#endif
62
63#if defined(OS_CHROMEOS)
64
65void 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.
97void 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
105std::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
115int 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
129namespace browser {
130
131// TODO(rkc): Eventually find a better way to do this
132std::vector<unsigned char>* last_screenshot_png = 0;
133gfx::Rect screen_size;
134
135void 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
145void 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
166class 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
187class 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
236BugReportUIHTMLSource::BugReportUIHTMLSource(base::StringPiece html)
237    : DataSource(chrome::kChromeUIBugReportHost, MessageLoop::current()) {
238  bug_report_html_ = html;
239}
240
241void 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////////////////////////////////////////////////////////////////////////////////
386void 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////////////////////////////////////////////////////////////////////////////////
435BugReportHandler::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
445BugReportHandler::~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
454void 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
466void 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
476WebUIMessageHandler* BugReportHandler::Attach(WebUI* web_ui) {
477  SetupScreenshotsSource();
478  return WebUIMessageHandler::Attach(web_ui);
479}
480
481base::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
521void 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
538void 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
568void 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)
576void 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
588void 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
698void BugReportHandler::HandleCancel(const ListValue*) {
699  CloseFeedbackTab();
700}
701
702void BugReportHandler::HandleOpenSystemTab(const ListValue* args) {
703#if defined(OS_CHROMEOS)
704  BrowserList::GetLastActive()->OpenSystemTabAndActivate();
705#endif
706}
707
708void 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
719void 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////////////////////////////////////////////////////////////////////////////////
735BugReportUI::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