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 nsTArray
<PrinterInfo
>* printerInfoList
=
73 reinterpret_cast<nsTArray
<PrinterInfo
>*>(user_data
);
75 cups_dest_t
* ownedDest
= nullptr;
76 mozilla::DebugOnly
<const int> numCopied
=
77 CupsShim().cupsCopyDest(aDest
, 0, &ownedDest
);
78 MOZ_ASSERT(numCopied
== 1);
81 GetDisplayNameForPrinter(*aDest
, name
);
83 printerInfoList
->AppendElement(PrinterInfo
{std::move(name
), ownedDest
});
85 return aFlags
== CUPS_DEST_FLAGS_MORE
? 1 : 0;
88 nsTArray
<PrinterInfo
> nsPrinterListCUPS::Printers() const {
89 if (!CupsShim().InitOkay()) {
93 nsTArray
<PrinterInfo
> printerInfoList
;
94 if (!CupsShim().cupsEnumDests(
96 0 /* timeout, 0 timeout shouldn't be a problem since we are masking
97 CUPS_PRINTER_DISCOVERED */
99 nullptr /* cancel* */, CUPS_PRINTER_LOCAL
,
100 CUPS_PRINTER_FAX
| CUPS_PRINTER_SCANNER
| CUPS_PRINTER_DISCOVERED
,
101 &CupsDestCallback
, &printerInfoList
)) {
105 return printerInfoList
;
108 RefPtr
<nsIPrinter
> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo
) const {
109 return mozilla::MakeRefPtr
<nsPrinterCUPS
>(
110 mCommonPaperInfo
, CupsShim(), std::move(aInfo
.mName
),
111 static_cast<cups_dest_t
*>(aInfo
.mCupsHandle
));
114 mozilla::Maybe
<PrinterInfo
> nsPrinterListCUPS::PrinterByName(
115 nsString aPrinterName
) const {
116 mozilla::Maybe
<PrinterInfo
> rv
;
117 if (!CupsShim().InitOkay()) {
121 // Will contain the printer, if found. This must be fully owned, and not a
122 // member of another array of printers.
123 cups_dest_t
* printer
= nullptr;
126 // On OS X the printer name given to this function is the readable/display
127 // name and not the CUPS name, so we iterate over all the printers for now.
128 // See bug 1659807 for one approach to improve perf here.
130 nsAutoCString printerName
;
131 CopyUTF16toUTF8(aPrinterName
, printerName
);
132 cups_dest_t
* printers
= nullptr;
133 const auto numPrinters
= CupsShim().cupsGetDests(&printers
);
134 for (auto i
: mozilla::IntegerRange(0, numPrinters
)) {
135 const char* const displayName
= CupsShim().cupsGetOption(
136 "printer-info", printers
[i
].num_options
, printers
[i
].options
);
137 if (printerName
== displayName
) {
138 // The second arg to CupsShim().cupsCopyDest is called num_dests, but
139 // it actually copies num_dests + 1 elements.
140 CupsShim().cupsCopyDest(printers
+ i
, 0, &printer
);
144 CupsShim().cupsFreeDests(numPrinters
, printers
);
147 // On GTK, we only ever show the CUPS name of printers, so we can use
148 // cupsGetNamedDest directly.
150 const auto printerName
= NS_ConvertUTF16toUTF8(aPrinterName
);
151 printer
= CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT
, printerName
.get(),
157 // Since the printer name had to be passed by-value, we can move the
159 rv
.emplace(PrinterInfo
{std::move(aPrinterName
), printer
});
164 mozilla::Maybe
<PrinterInfo
> nsPrinterListCUPS::PrinterBySystemName(
165 nsString aPrinterName
) const {
166 mozilla::Maybe
<PrinterInfo
> rv
;
167 if (!CupsShim().InitOkay()) {
171 const auto printerName
= NS_ConvertUTF16toUTF8(aPrinterName
);
172 if (cups_dest_t
* const printer
= CupsShim().cupsGetNamedDest(
173 CUPS_HTTP_DEFAULT
, printerName
.get(), nullptr)) {
174 rv
.emplace(PrinterInfo
{std::move(aPrinterName
), printer
});
179 nsresult
nsPrinterListCUPS::SystemDefaultPrinterName(nsAString
& aName
) const {
182 if (!CupsShim().InitOkay()) {
186 // Passing in nullptr for the name will return the default, if any.
188 CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT
, /* name */ nullptr,
189 /* instance */ nullptr);
194 GetDisplayNameForPrinter(*dest
, aName
);
195 if (aName
.IsEmpty()) {
196 CopyUTF8toUTF16(mozilla::MakeStringSpan(dest
->name
), aName
);
199 CupsShim().cupsFreeDests(1, dest
);