1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsPrinterListCUPS.h"
7 #include "mozilla/IntegerRange.h"
8 #include "mozilla/Maybe.h"
9 #include "nsCUPSShim.h"
10 #include "nsPrinterCUPS.h"
14 // Use a local static to initialize the CUPS shim lazily, when it's needed.
15 // This is used in order to avoid a global constructor.
16 static nsCUPSShim
& CupsShim() {
17 static nsCUPSShim sCupsShim
;
21 using PrinterInfo
= nsPrinterListBase::PrinterInfo
;
24 * Retrieves a human-readable name for the printer from CUPS.
25 * https://www.cups.org/doc/cupspm.html#basic-destination-information
27 static void GetDisplayNameForPrinter(const cups_dest_t
& aDest
,
29 // macOS clients expect prettified printer names
30 // while GTK clients expect non-prettified names.
31 // If you change this, please change NamedPrinter accordingly.
33 const char* displayName
= CupsShim().cupsGetOption(
34 "printer-info", aDest
.num_options
, aDest
.options
);
36 CopyUTF8toUTF16(MakeStringSpan(displayName
), aName
);
42 nsPrinterListCUPS::InitPrintSettingsFromPrinter(
43 const nsAString
& aPrinterName
, nsIPrintSettings
* aPrintSettings
) {
44 MOZ_ASSERT(aPrintSettings
);
46 // Set a default file name.
47 nsAutoString filename
;
48 nsresult rv
= aPrintSettings
->GetToFileName(filename
);
49 if (NS_FAILED(rv
) || filename
.IsEmpty()) {
50 const char* path
= PR_GetEnv("PWD");
52 path
= PR_GetEnv("HOME");
56 CopyUTF8toUTF16(mozilla::MakeStringSpan(path
), filename
);
57 filename
.AppendLiteral("/mozilla.pdf");
59 filename
.AssignLiteral("mozilla.pdf");
62 aPrintSettings
->SetToFileName(filename
);
65 aPrintSettings
->SetIsInitializedFromPrinter(true);
69 static int CupsDestCallback(void* user_data
, unsigned aFlags
,
71 MOZ_ASSERT(user_data
);
72 auto* printerInfoList
= static_cast<nsTArray
<PrinterInfo
>*>(user_data
);
74 cups_dest_t
* ownedDest
= nullptr;
75 mozilla::DebugOnly
<const int> numCopied
=
76 CupsShim().cupsCopyDest(aDest
, 0, &ownedDest
);
77 MOZ_ASSERT(numCopied
== 1);
80 GetDisplayNameForPrinter(*aDest
, name
);
82 printerInfoList
->AppendElement(PrinterInfo
{std::move(name
), ownedDest
});
84 return aFlags
== CUPS_DEST_FLAGS_MORE
? 1 : 0;
87 nsTArray
<PrinterInfo
> nsPrinterListCUPS::Printers() const {
88 if (!CupsShim().InitOkay()) {
92 nsTArray
<PrinterInfo
> printerInfoList
;
93 if (!CupsShim().cupsEnumDests(
95 0 /* timeout, 0 timeout shouldn't be a problem since we are masking
96 CUPS_PRINTER_DISCOVERED */
98 nullptr /* cancel* */, CUPS_PRINTER_LOCAL
,
99 CUPS_PRINTER_FAX
| CUPS_PRINTER_SCANNER
| CUPS_PRINTER_DISCOVERED
,
100 &CupsDestCallback
, &printerInfoList
)) {
104 return printerInfoList
;
107 RefPtr
<nsIPrinter
> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo
) const {
108 return mozilla::MakeRefPtr
<nsPrinterCUPS
>(
109 mCommonPaperInfo
, CupsShim(), std::move(aInfo
.mName
),
110 static_cast<cups_dest_t
*>(aInfo
.mCupsHandle
));
113 mozilla::Maybe
<PrinterInfo
> nsPrinterListCUPS::PrinterByName(
114 nsString aPrinterName
) const {
115 mozilla::Maybe
<PrinterInfo
> rv
;
116 if (!CupsShim().InitOkay()) {
120 // Will contain the printer, if found. This must be fully owned, and not a
121 // member of another array of printers.
122 cups_dest_t
* printer
= nullptr;
125 // On OS X the printer name given to this function is the readable/display
126 // name and not the CUPS name, so we iterate over all the printers for now.
127 // See bug 1659807 for one approach to improve perf here.
129 nsAutoCString printerName
;
130 CopyUTF16toUTF8(aPrinterName
, printerName
);
131 cups_dest_t
* printers
= nullptr;
132 const auto numPrinters
= CupsShim().cupsGetDests(&printers
);
133 for (auto i
: mozilla::IntegerRange(0, numPrinters
)) {
134 const char* const displayName
= CupsShim().cupsGetOption(
135 "printer-info", printers
[i
].num_options
, printers
[i
].options
);
136 if (printerName
== displayName
) {
137 // The second arg to CupsShim().cupsCopyDest is called num_dests, but
138 // it actually copies num_dests + 1 elements.
139 CupsShim().cupsCopyDest(printers
+ i
, 0, &printer
);
143 CupsShim().cupsFreeDests(numPrinters
, printers
);
146 // On GTK, we only ever show the CUPS name of printers, so we can use
147 // cupsGetNamedDest directly.
149 const auto printerName
= NS_ConvertUTF16toUTF8(aPrinterName
);
150 printer
= CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT
, printerName
.get(),
156 // Since the printer name had to be passed by-value, we can move the
158 rv
.emplace(PrinterInfo
{std::move(aPrinterName
), printer
});
163 mozilla::Maybe
<PrinterInfo
> nsPrinterListCUPS::PrinterBySystemName(
164 nsString aPrinterName
) const {
165 mozilla::Maybe
<PrinterInfo
> rv
;
166 if (!CupsShim().InitOkay()) {
170 const auto printerName
= NS_ConvertUTF16toUTF8(aPrinterName
);
171 if (cups_dest_t
* const printer
= CupsShim().cupsGetNamedDest(
172 CUPS_HTTP_DEFAULT
, printerName
.get(), nullptr)) {
173 rv
.emplace(PrinterInfo
{std::move(aPrinterName
), printer
});
178 nsresult
nsPrinterListCUPS::SystemDefaultPrinterName(nsAString
& aName
) const {
181 if (!CupsShim().InitOkay()) {
185 // Passing in nullptr for the name will return the default, if any.
187 CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT
, /* name */ nullptr,
188 /* instance */ nullptr);
193 GetDisplayNameForPrinter(*dest
, aName
);
194 if (aName
.IsEmpty()) {
195 CopyUTF8toUTF16(mozilla::MakeStringSpan(dest
->name
), aName
);
198 CupsShim().cupsFreeDests(1, dest
);