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