chromium/chrome/browser/ui/webui/ash/settings/pages/printing/cups_printers_handler.h

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_PRINTING_CUPS_PRINTERS_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_PRINTING_CUPS_PRINTERS_HANDLER_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/printing/cups_printers_manager.h"
#include "chrome/browser/ash/printing/printer_event_tracker.h"
#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
#include "chromeos/ash/components/dbus/printscanmgr/printscanmgr_client.h"
#include "chromeos/printing/cups_printer_status.h"
#include "chromeos/printing/ppd_provider.h"
#include "chromeos/printing/printer_configuration.h"
#include "printing/printer_query_result.h"
#include "ui/shell_dialogs/select_file_dialog.h"

namespace base {
class FilePath;
}  // namespace base

namespace chromeos {
struct PrinterAuthenticationInfo;
}

namespace local_discovery {
class EndpointResolver;
}  // namespace local_discovery

namespace printing {
struct PrinterStatus;
}  // namespace printing

class GURL;
class Profile;

namespace ash {

class ServerPrintersFetcher;

namespace settings {

// Chrome OS CUPS printing settings page UI handler.
class CupsPrintersHandler : public ::settings::SettingsPageUIHandler,
                            public ui::SelectFileDialog::Listener,
                            public CupsPrintersManager::Observer,
                            public CupsPrintersManager::LocalPrintersObserver {
 public:
  static std::unique_ptr<CupsPrintersHandler> CreateForTesting(
      Profile* profile,
      scoped_refptr<chromeos::PpdProvider> ppd_provider,
      CupsPrintersManager* printers_manager);

  CupsPrintersHandler(Profile* profile, CupsPrintersManager* printers_manager);

  CupsPrintersHandler(const CupsPrintersHandler&) = delete;
  CupsPrintersHandler& operator=(const CupsPrintersHandler&) = delete;

  ~CupsPrintersHandler() override;

  // SettingsPageUIHandler overrides:
  void RegisterMessages() override;
  void OnJavascriptAllowed() override;
  void OnJavascriptDisallowed() override;

  void SetWebUIForTest(content::WebUI* web_ui);

 private:
  CupsPrintersHandler(Profile* profile,
                      scoped_refptr<chromeos::PpdProvider> ppd_provider,
                      CupsPrintersManager* printers_manager);

  // Gets all CUPS printers and return it to WebUI.
  void HandleGetCupsSavedPrintersList(const base::Value::List& args);
  void HandleGetCupsEnterprisePrintersList(const base::Value::List& args);
  void HandleUpdateCupsPrinter(const base::Value::List& args);
  void HandleRemoveCupsPrinter(const base::Value::List& args);
  void HandleRetrieveCupsPrinterPpd(const base::Value::List& args);

  void OnSetUpPrinter(const std::string& printer_id,
                      const std::string& printer_name,
                      const std::string& eula,
                      PrinterSetupResult result);

  // For a CupsPrinterInfo in |args|, retrieves the relevant PrinterInfo object
  // using an IPP call to the printer.
  void HandleGetPrinterInfo(const base::Value::List& args);

  // Handles the callback for HandleGetPrinterInfo. |callback_id| is the
  // identifier to resolve the correct Promise. |result| indicates if the query
  // was successful. |printer_status| contains the current status of the
  // printer. |make_and_model| is the unparsed printer-make-and-model string.
  // |ipp_everywhere| indicates if configuration using the CUPS IPP Everywhere
  // driver should be attempted. If |result| is not SUCCESS, the values of
  // |printer_status|, |make_and_model|, |document_formats|, |ipp_everywhere|
  // and |auth_info| are not specified.
  void OnAutoconfQueried(const std::string& callback_id,
                         printing::PrinterQueryResult result,
                         const printing::PrinterStatus& printer_status,
                         const std::string& make_and_model,
                         const std::vector<std::string>& document_formats,
                         bool ipp_everywhere,
                         const chromeos::PrinterAuthenticationInfo& auth_info);

  // Handles the callback for HandleGetPrinterInfo for a discovered printer.
  void OnAutoconfQueriedDiscovered(
      const std::string& callback_id,
      chromeos::Printer printer,
      printing::PrinterQueryResult result,
      const printing::PrinterStatus& printer_status,
      const std::string& make_and_model,
      const std::vector<std::string>& document_formats,
      bool ipp_everywhere,
      const chromeos::PrinterAuthenticationInfo& auth_info);

  // Callback for PPD matching attempts;
  void OnPpdResolved(const std::string& callback_id,
                     base::Value::Dict info,
                     chromeos::PpdProvider::CallbackResultCode res,
                     const chromeos::Printer::PpdReference& ppd_ref,
                     const std::string& usb_manufacturer);

  void HandleAddCupsPrinter(const base::Value::List& args);

  void HandleReconfigureCupsPrinter(const base::Value::List& args);

  void AddOrReconfigurePrinter(const base::Value::List& args,
                               bool is_printer_edit);

  // Handles the result of adding a printer which the user specified the
  // location of (i.e. a printer that was not 'discovered' automatically).
  void OnAddedOrEditedSpecifiedPrinter(const std::string& callback_id,
                                       const chromeos::Printer& printer,
                                       bool is_printer_edit,
                                       PrinterSetupResult result);

  // Handles the result of failure to add a printer. |result_code| is used to
  // determine the reason for the failure.
  void OnAddOrEditPrinterError(const std::string& callback_id,
                               PrinterSetupResult result_code);

  // Get a list of all manufacturers for which we have at least one model of
  // printer supported.  Takes one argument, the callback id for the result.
  // The callback will be invoked with {success: <boolean>, models:
  // <Array<string>>}.
  void HandleGetCupsPrinterManufacturers(const base::Value::List& args);

  // Given a manufacturer, get a list of all models of printers for which we can
  // get drivers.  Takes two arguments - the callback id and the manufacturer
  // name for which we want to list models.  The callback will be called with
  // {success: <boolean>, models: Array<string>}.
  void HandleGetCupsPrinterModels(const base::Value::List& args);

  void HandleSelectPPDFile(const base::Value::List& args);

  // chromeos::PpdProvider callback handlers.
  void ResolveManufacturersDone(
      const std::string& callback_id,
      chromeos::PpdProvider::CallbackResultCode result_code,
      const std::vector<std::string>& available);
  void ResolvePrintersDone(
      const std::string& manufacturer,
      const std::string& callback_id,
      chromeos::PpdProvider::CallbackResultCode result_code,
      const chromeos::PpdProvider::ResolvedPrintersList& printers);

  void HandleStartDiscovery(const base::Value::List& args);
  void HandleStopDiscovery(const base::Value::List& args);

  // Logs printer set ups that are abandoned.
  void HandleSetUpCancel(const base::Value::List& args);

  // Given a printer id, find the corresponding ppdManufacturer and ppdModel.
  void HandleGetPrinterPpdManufacturerAndModel(const base::Value::List& args);
  void OnGetPrinterPpdManufacturerAndModel(
      const std::string& callback_id,
      chromeos::PpdProvider::CallbackResultCode result_code,
      const std::string& manufacturer,
      const std::string& model);

  // Emits the updated discovered printer list after new printers are received.
  void UpdateDiscoveredPrinters();

  // Attempt to add a discovered printer.
  void HandleAddDiscoveredPrinter(const base::Value::List& args);

  // Called when we get a response from
  // PrintscanmgrClient::CupsRetrievePrinterPpd.
  void OnRetrieveCupsPrinterPpd(
      const std::string& printer_name,
      const std::string& eula,
      std::optional<printscanmgr::CupsRetrievePpdResponse> response);

  void OnRetrievePpdError(const std::string& printer_name);
  void WriteAndDisplayPpdFile(const std::string& printer_name,
                              const std::string& ppd);
  void DisplayPpdFile(const base::FilePath& ppd_file_path);

  // Post printer setup callback.
  void OnAddedDiscoveredPrinter(const std::string& callback_id,
                                const chromeos::Printer& printer,
                                PrinterSetupResult result_code);

  // Code common between the discovered and manual add printer code paths.
  void OnAddedOrEditedPrinterCommon(const chromeos::Printer& printer,
                                    PrinterSetupResult result_code);

  // CupsPrintersManager::Observer override:
  void OnPrintersChanged(
      chromeos::PrinterClass printer_class,
      const std::vector<chromeos::Printer>& printers) override;

  // CupsPrintersManager::LocalPrintersObserver:
  void OnLocalPrintersUpdated() override;

  // Handles getting the EULA URL if available.
  void HandleGetEulaUrl(const base::Value::List& args);

  // Post EULA URL callback.
  void OnGetEulaUrl(const std::string& callback_id,
                    chromeos::PpdProvider::CallbackResultCode result,
                    const std::string& eula_url);

  // ui::SelectFileDialog::Listener override:
  void FileSelected(const ui::SelectedFileInfo& file, int index) override;
  void FileSelectionCanceled() override;

  // Used by FileSelected() in order to verify whether the beginning contents of
  // the selected file contain the magic number present in all PPD files. |path|
  // is used for display in the UI as this function calls back into javascript
  // with |path| as the result.
  void VerifyPpdContents(const base::FilePath& path,
                         const std::string& contents);

  // Fires the on-manually-add-discovered-printer event with the appropriate
  // parameters.  See https://crbug.com/835476
  void FireManuallyAddDiscoveredPrinter(const chromeos::Printer& printer);

  void OnIpResolved(const std::string& callback_id,
                    const chromeos::Printer& printer,
                    const net::IPEndPoint& endpoint);

  void HandleQueryPrintServer(const base::Value::List& args);

  void QueryPrintServer(const std::string& callback_id,
                        const GURL& server_url,
                        bool should_fallback);

  void OnQueryPrintServerCompleted(
      const std::string& callback_id,
      bool should_fallback,
      const ServerPrintersFetcher* sender,
      const GURL& server_url,
      std::vector<PrinterDetector::DetectedPrinter>&& returned_printers);

  void HandleOpenPrintManagementApp(const base::Value::List& args);

  void HandleOpenScanningApp(const base::Value::List& args);

  void HandleRequestPrinterStatus(const base::Value::List& args);

  void OnPrinterStatusReceived(
      const std::string& callback_id,
      const chromeos::CupsPrinterStatus& printer_status);

  raw_ptr<Profile, DanglingUntriaged> profile_;

  // Discovery support.  discovery_active_ tracks whether or not the UI
  // currently wants updates about printer availability.  The two vectors track
  // the most recent list of printers in each class.
  bool discovery_active_ = false;
  std::vector<chromeos::Printer> discovered_printers_;
  std::vector<chromeos::Printer> automatic_printers_;

  // These must be initialized before printers_manager_, as they are
  // used by callbacks that may be issued immediately by printers_manager_.
  //
  // TODO(crbug/757887) - Remove this subtle initialization constraint.
  scoped_refptr<chromeos::PpdProvider> ppd_provider_;

  // Cached list of {printer name, PpdReference} pairs for each manufacturer
  // that has been resolved in the lifetime of this object.
  std::map<std::string, chromeos::PpdProvider::ResolvedPrintersList>
      resolved_printers_;

  scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
  std::string webui_callback_id_;
  raw_ptr<CupsPrintersManager> printers_manager_;
  std::unique_ptr<local_discovery::EndpointResolver> endpoint_resolver_;

  std::unique_ptr<ServerPrintersFetcher> server_printers_fetcher_;

  base::ScopedObservation<CupsPrintersManager, CupsPrintersManager::Observer>
      printers_manager_observation_{this};

  base::ScopedObservation<CupsPrintersManager,
                          CupsPrintersManager::LocalPrintersObserver>
      local_printers_observation_{this};

  base::WeakPtrFactory<CupsPrintersHandler> weak_factory_{this};
};

}  // namespace settings
}  // namespace ash

#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_PRINTING_CUPS_PRINTERS_HANDLER_H_