@esslassi/electron-printer 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +318 -318
- package/binding.gyp +57 -57
- package/lib/electronPrinter.js +17 -18
- package/lib/native.d.ts +2 -0
- package/lib/native.js +12 -0
- package/package.json +10 -3
- package/src/linux_printer.cpp +370 -370
- package/src/linux_printer.h +30 -30
- package/src/mac_printer.cpp +372 -372
- package/src/mac_printer.h +30 -30
- package/src/main.cpp +50 -50
- package/src/print.cpp +352 -352
- package/src/printer_factory.cpp +19 -19
- package/src/printer_factory.h +12 -12
- package/src/printer_interface.h +66 -66
- package/src/windows_printer.cpp +346 -346
- package/src/windows_printer.h +63 -63
- package/test.js +0 -120
package/src/mac_printer.cpp
CHANGED
|
@@ -1,373 +1,373 @@
|
|
|
1
|
-
#include "mac_printer.h"
|
|
2
|
-
|
|
3
|
-
#include <cups/cups.h>
|
|
4
|
-
#include <cups/ppd.h>
|
|
5
|
-
#include <cups/ipp.h>
|
|
6
|
-
#include <cups/http.h>
|
|
7
|
-
|
|
8
|
-
#include <vector>
|
|
9
|
-
#include <string>
|
|
10
|
-
#include <map>
|
|
11
|
-
#include <fstream>
|
|
12
|
-
#include <algorithm>
|
|
13
|
-
#include <unistd.h>
|
|
14
|
-
#include <cstring>
|
|
15
|
-
|
|
16
|
-
/* =========================================================
|
|
17
|
-
Helpers
|
|
18
|
-
========================================================= */
|
|
19
|
-
|
|
20
|
-
static std::string ToUpper(std::string s)
|
|
21
|
-
{
|
|
22
|
-
std::transform(s.begin(), s.end(), s.begin(),
|
|
23
|
-
[](unsigned char c) { return (char)std::toupper(c); });
|
|
24
|
-
return s;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static std::vector<uint8_t> ReadAllBytes(const std::string &path)
|
|
28
|
-
{
|
|
29
|
-
std::ifstream f(path, std::ios::binary);
|
|
30
|
-
if (!f) return {};
|
|
31
|
-
|
|
32
|
-
f.seekg(0, std::ios::end);
|
|
33
|
-
std::streamsize size = f.tellg();
|
|
34
|
-
if (size < 0) return {};
|
|
35
|
-
|
|
36
|
-
f.seekg(0, std::ios::beg);
|
|
37
|
-
|
|
38
|
-
std::vector<uint8_t> buf((size_t)size);
|
|
39
|
-
if (size > 0)
|
|
40
|
-
f.read((char*)buf.data(), size);
|
|
41
|
-
|
|
42
|
-
return buf;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* =========================================================
|
|
46
|
-
Printer Listing
|
|
47
|
-
========================================================= */
|
|
48
|
-
|
|
49
|
-
std::vector<PrinterDetailsNative> MacPrinter::GetPrinters()
|
|
50
|
-
{
|
|
51
|
-
std::vector<PrinterDetailsNative> out;
|
|
52
|
-
|
|
53
|
-
cups_dest_t *dests = nullptr;
|
|
54
|
-
int num = cupsGetDests(&dests);
|
|
55
|
-
|
|
56
|
-
for (int i = 0; i < num; i++)
|
|
57
|
-
{
|
|
58
|
-
PrinterDetailsNative p;
|
|
59
|
-
p.name = dests[i].name ? dests[i].name : "";
|
|
60
|
-
p.isDefault = dests[i].is_default != 0;
|
|
61
|
-
|
|
62
|
-
for (int k = 0; k < dests[i].num_options; k++)
|
|
63
|
-
{
|
|
64
|
-
if (dests[i].options[k].name && dests[i].options[k].value)
|
|
65
|
-
p.options[dests[i].options[k].name] = dests[i].options[k].value;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
out.push_back(std::move(p));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
cupsFreeDests(num, dests);
|
|
72
|
-
return out;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
PrinterDetailsNative MacPrinter::GetPrinter(const std::string &printerName)
|
|
76
|
-
{
|
|
77
|
-
auto list = GetPrinters();
|
|
78
|
-
for (auto &p : list)
|
|
79
|
-
if (p.name == printerName)
|
|
80
|
-
return p;
|
|
81
|
-
|
|
82
|
-
PrinterDetailsNative p;
|
|
83
|
-
p.name = printerName;
|
|
84
|
-
p.isDefault = false;
|
|
85
|
-
return p;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
std::string MacPrinter::GetDefaultPrinterName()
|
|
89
|
-
{
|
|
90
|
-
cups_dest_t *dests = nullptr;
|
|
91
|
-
int num = cupsGetDests(&dests);
|
|
92
|
-
|
|
93
|
-
cups_dest_t *def = cupsGetDest(NULL, NULL, num, dests);
|
|
94
|
-
|
|
95
|
-
std::string name;
|
|
96
|
-
if (def && def->name)
|
|
97
|
-
name = def->name;
|
|
98
|
-
|
|
99
|
-
cupsFreeDests(num, dests);
|
|
100
|
-
return name;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* =========================================================
|
|
104
|
-
Driver Options / Paper
|
|
105
|
-
========================================================= */
|
|
106
|
-
|
|
107
|
-
DriverOptions MacPrinter::GetPrinterDriverOptions(const std::string &printerName)
|
|
108
|
-
{
|
|
109
|
-
DriverOptions out;
|
|
110
|
-
|
|
111
|
-
const char *ppdPath = cupsGetPPD(printerName.c_str());
|
|
112
|
-
if (!ppdPath) return out;
|
|
113
|
-
|
|
114
|
-
ppd_file_t *ppd = ppdOpenFile(ppdPath);
|
|
115
|
-
if (!ppd)
|
|
116
|
-
{
|
|
117
|
-
unlink(ppdPath);
|
|
118
|
-
return out;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
ppdMarkDefaults(ppd);
|
|
122
|
-
|
|
123
|
-
for (ppd_option_t *opt = ppd->options; opt; opt = opt->next)
|
|
124
|
-
{
|
|
125
|
-
std::map<std::string, bool> choices;
|
|
126
|
-
|
|
127
|
-
for (int i = 0; i < opt->num_choices; i++)
|
|
128
|
-
{
|
|
129
|
-
bool isDefault =
|
|
130
|
-
(opt->defchoice &&
|
|
131
|
-
strcmp(opt->defchoice, opt->choices[i].choice) == 0);
|
|
132
|
-
|
|
133
|
-
choices[opt->choices[i].choice] = isDefault;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
out[opt->keyword ? opt->keyword : ""] = choices;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
ppdClose(ppd);
|
|
140
|
-
unlink(ppdPath);
|
|
141
|
-
|
|
142
|
-
return out;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
std::string MacPrinter::GetSelectedPaperSize(const std::string &printerName)
|
|
146
|
-
{
|
|
147
|
-
std::string paper;
|
|
148
|
-
|
|
149
|
-
const char *ppdPath = cupsGetPPD(printerName.c_str());
|
|
150
|
-
if (!ppdPath) return paper;
|
|
151
|
-
|
|
152
|
-
ppd_file_t *ppd = ppdOpenFile(ppdPath);
|
|
153
|
-
if (!ppd)
|
|
154
|
-
{
|
|
155
|
-
unlink(ppdPath);
|
|
156
|
-
return paper;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
ppdMarkDefaults(ppd);
|
|
160
|
-
|
|
161
|
-
ppd_option_t *opt = ppdFindOption(ppd, "PageSize");
|
|
162
|
-
if (!opt)
|
|
163
|
-
opt = ppdFindOption(ppd, "PageRegion");
|
|
164
|
-
|
|
165
|
-
if (opt && opt->defchoice)
|
|
166
|
-
paper = opt->defchoice;
|
|
167
|
-
|
|
168
|
-
ppdClose(ppd);
|
|
169
|
-
unlink(ppdPath);
|
|
170
|
-
|
|
171
|
-
return paper;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/* =========================================================
|
|
175
|
-
Capabilities
|
|
176
|
-
========================================================= */
|
|
177
|
-
|
|
178
|
-
std::vector<std::string> MacPrinter::GetSupportedPrintFormats()
|
|
179
|
-
{
|
|
180
|
-
return { "RAW", "TEXT", "PDF", "JPEG", "POSTSCRIPT", "COMMAND", "AUTO" };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/* =========================================================
|
|
184
|
-
Printing
|
|
185
|
-
========================================================= */
|
|
186
|
-
|
|
187
|
-
int MacPrinter::PrintDirect(const std::string &printerName,
|
|
188
|
-
const std::vector<uint8_t> &data,
|
|
189
|
-
const std::string &type,
|
|
190
|
-
const StringMap &options)
|
|
191
|
-
{
|
|
192
|
-
std::string t = ToUpper(type);
|
|
193
|
-
|
|
194
|
-
// For PDF/JPEG/POSTSCRIPT -> use temp file + cupsPrintFile
|
|
195
|
-
if (t == "PDF" || t == "JPEG" || t == "POSTSCRIPT")
|
|
196
|
-
{
|
|
197
|
-
char tmpName[] = "/tmp/esslassi_print_XXXXXX";
|
|
198
|
-
int fd = mkstemp(tmpName);
|
|
199
|
-
if (fd < 0)
|
|
200
|
-
return 0;
|
|
201
|
-
|
|
202
|
-
FILE *fp = fdopen(fd, "wb");
|
|
203
|
-
if (!fp)
|
|
204
|
-
{
|
|
205
|
-
close(fd);
|
|
206
|
-
return 0;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
fwrite(data.data(), 1, data.size(), fp);
|
|
210
|
-
fclose(fp);
|
|
211
|
-
|
|
212
|
-
cups_option_t *cupOpts = nullptr;
|
|
213
|
-
int num = 0;
|
|
214
|
-
|
|
215
|
-
for (auto &kv : options)
|
|
216
|
-
num = cupsAddOption(kv.first.c_str(),
|
|
217
|
-
kv.second.c_str(),
|
|
218
|
-
num,
|
|
219
|
-
&cupOpts);
|
|
220
|
-
|
|
221
|
-
int jobId = cupsPrintFile(
|
|
222
|
-
printerName.c_str(),
|
|
223
|
-
tmpName,
|
|
224
|
-
"Node Print Job",
|
|
225
|
-
num,
|
|
226
|
-
cupOpts);
|
|
227
|
-
|
|
228
|
-
if (cupOpts)
|
|
229
|
-
cupsFreeOptions(num, cupOpts);
|
|
230
|
-
|
|
231
|
-
unlink(tmpName);
|
|
232
|
-
|
|
233
|
-
return jobId > 0 ? jobId : 0;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// RAW / TEXT / COMMAND
|
|
237
|
-
int jobId = cupsCreateJob(
|
|
238
|
-
CUPS_HTTP_DEFAULT,
|
|
239
|
-
printerName.c_str(),
|
|
240
|
-
"Node Print Job",
|
|
241
|
-
0,
|
|
242
|
-
NULL);
|
|
243
|
-
|
|
244
|
-
if (jobId <= 0)
|
|
245
|
-
return 0;
|
|
246
|
-
|
|
247
|
-
http_status_t st = cupsStartDocument(
|
|
248
|
-
CUPS_HTTP_DEFAULT,
|
|
249
|
-
printerName.c_str(),
|
|
250
|
-
jobId,
|
|
251
|
-
"Node Print Job",
|
|
252
|
-
CUPS_FORMAT_RAW,
|
|
253
|
-
1);
|
|
254
|
-
|
|
255
|
-
if (st != HTTP_STATUS_CONTINUE)
|
|
256
|
-
{
|
|
257
|
-
cupsCancelJob(printerName.c_str(), jobId);
|
|
258
|
-
return 0;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (cupsWriteRequestData(
|
|
262
|
-
CUPS_HTTP_DEFAULT,
|
|
263
|
-
(const char*)data.data(),
|
|
264
|
-
data.size()) != HTTP_STATUS_CONTINUE)
|
|
265
|
-
{
|
|
266
|
-
cupsCancelJob(printerName.c_str(), jobId);
|
|
267
|
-
return 0;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
ipp_status_t fin =
|
|
271
|
-
(ipp_status_t)cupsFinishDocument(
|
|
272
|
-
CUPS_HTTP_DEFAULT,
|
|
273
|
-
printerName.c_str());
|
|
274
|
-
|
|
275
|
-
if (fin > IPP_STATUS_OK_CONFLICT)
|
|
276
|
-
return 0;
|
|
277
|
-
|
|
278
|
-
return jobId;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
int MacPrinter::PrintFile(const std::string &printerName,
|
|
282
|
-
const std::string &filename)
|
|
283
|
-
{
|
|
284
|
-
int jobId = cupsPrintFile(
|
|
285
|
-
printerName.c_str(),
|
|
286
|
-
filename.c_str(),
|
|
287
|
-
"Node Print Job",
|
|
288
|
-
0,
|
|
289
|
-
NULL);
|
|
290
|
-
|
|
291
|
-
return jobId > 0 ? jobId : 0;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/* =========================================================
|
|
295
|
-
Job Management
|
|
296
|
-
========================================================= */
|
|
297
|
-
|
|
298
|
-
JobDetailsNative MacPrinter::GetJob(const std::string &printerName, int jobId)
|
|
299
|
-
{
|
|
300
|
-
JobDetailsNative j;
|
|
301
|
-
j.id = jobId;
|
|
302
|
-
j.printerName = printerName;
|
|
303
|
-
|
|
304
|
-
cups_job_t *jobs = nullptr;
|
|
305
|
-
int num = cupsGetJobs(
|
|
306
|
-
&jobs,
|
|
307
|
-
printerName.c_str(),
|
|
308
|
-
0,
|
|
309
|
-
CUPS_WHICHJOBS_ALL);
|
|
310
|
-
|
|
311
|
-
for (int i = 0; i < num; i++)
|
|
312
|
-
{
|
|
313
|
-
if (jobs[i].id == jobId)
|
|
314
|
-
{
|
|
315
|
-
j.name = jobs[i].title ? jobs[i].title : "";
|
|
316
|
-
j.user = jobs[i].user ? jobs[i].user : "";
|
|
317
|
-
j.format = jobs[i].format ? jobs[i].format : "";
|
|
318
|
-
j.priority = jobs[i].priority;
|
|
319
|
-
j.size = jobs[i].size;
|
|
320
|
-
|
|
321
|
-
switch (jobs[i].state)
|
|
322
|
-
{
|
|
323
|
-
case IPP_JSTATE_PENDING: j.status = { "PENDING" }; break;
|
|
324
|
-
case IPP_JSTATE_HELD: j.status = { "PAUSED" }; break;
|
|
325
|
-
case IPP_JSTATE_PROCESSING: j.status = { "PRINTING" }; break;
|
|
326
|
-
case IPP_JSTATE_STOPPED: j.status = { "ABORTED" }; break;
|
|
327
|
-
case IPP_JSTATE_CANCELED: j.status = { "CANCELLED" }; break;
|
|
328
|
-
case IPP_JSTATE_ABORTED: j.status = { "ABORTED" }; break;
|
|
329
|
-
case IPP_JSTATE_COMPLETED: j.status = { "PRINTED" }; break;
|
|
330
|
-
default: j.status = { "PENDING" }; break;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
j.creationTime = jobs[i].creation_time;
|
|
334
|
-
j.processingTime = jobs[i].processing_time;
|
|
335
|
-
j.completedTime = jobs[i].completed_time;
|
|
336
|
-
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
cupsFreeJobs(num, jobs);
|
|
342
|
-
return j;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
void MacPrinter::SetJob(const std::string &printerName,
|
|
346
|
-
int jobId,
|
|
347
|
-
const std::string &command)
|
|
348
|
-
{
|
|
349
|
-
std::string cmd = ToUpper(command);
|
|
350
|
-
|
|
351
|
-
if (cmd == "CANCEL")
|
|
352
|
-
{
|
|
353
|
-
cupsCancelJob(printerName.c_str(), jobId);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (cmd == "PAUSE" || cmd == "HOLD")
|
|
358
|
-
{
|
|
359
|
-
cupsHoldJob(printerName.c_str(), jobId);
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (cmd == "RESUME" || cmd == "RELEASE")
|
|
364
|
-
{
|
|
365
|
-
cupsReleaseJob(printerName.c_str(), jobId);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
std::vector<std::string> MacPrinter::GetSupportedJobCommands()
|
|
371
|
-
{
|
|
372
|
-
return { "CANCEL", "PAUSE", "RESUME" };
|
|
1
|
+
#include "mac_printer.h"
|
|
2
|
+
|
|
3
|
+
#include <cups/cups.h>
|
|
4
|
+
#include <cups/ppd.h>
|
|
5
|
+
#include <cups/ipp.h>
|
|
6
|
+
#include <cups/http.h>
|
|
7
|
+
|
|
8
|
+
#include <vector>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <map>
|
|
11
|
+
#include <fstream>
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <unistd.h>
|
|
14
|
+
#include <cstring>
|
|
15
|
+
|
|
16
|
+
/* =========================================================
|
|
17
|
+
Helpers
|
|
18
|
+
========================================================= */
|
|
19
|
+
|
|
20
|
+
static std::string ToUpper(std::string s)
|
|
21
|
+
{
|
|
22
|
+
std::transform(s.begin(), s.end(), s.begin(),
|
|
23
|
+
[](unsigned char c) { return (char)std::toupper(c); });
|
|
24
|
+
return s;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static std::vector<uint8_t> ReadAllBytes(const std::string &path)
|
|
28
|
+
{
|
|
29
|
+
std::ifstream f(path, std::ios::binary);
|
|
30
|
+
if (!f) return {};
|
|
31
|
+
|
|
32
|
+
f.seekg(0, std::ios::end);
|
|
33
|
+
std::streamsize size = f.tellg();
|
|
34
|
+
if (size < 0) return {};
|
|
35
|
+
|
|
36
|
+
f.seekg(0, std::ios::beg);
|
|
37
|
+
|
|
38
|
+
std::vector<uint8_t> buf((size_t)size);
|
|
39
|
+
if (size > 0)
|
|
40
|
+
f.read((char*)buf.data(), size);
|
|
41
|
+
|
|
42
|
+
return buf;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* =========================================================
|
|
46
|
+
Printer Listing
|
|
47
|
+
========================================================= */
|
|
48
|
+
|
|
49
|
+
std::vector<PrinterDetailsNative> MacPrinter::GetPrinters()
|
|
50
|
+
{
|
|
51
|
+
std::vector<PrinterDetailsNative> out;
|
|
52
|
+
|
|
53
|
+
cups_dest_t *dests = nullptr;
|
|
54
|
+
int num = cupsGetDests(&dests);
|
|
55
|
+
|
|
56
|
+
for (int i = 0; i < num; i++)
|
|
57
|
+
{
|
|
58
|
+
PrinterDetailsNative p;
|
|
59
|
+
p.name = dests[i].name ? dests[i].name : "";
|
|
60
|
+
p.isDefault = dests[i].is_default != 0;
|
|
61
|
+
|
|
62
|
+
for (int k = 0; k < dests[i].num_options; k++)
|
|
63
|
+
{
|
|
64
|
+
if (dests[i].options[k].name && dests[i].options[k].value)
|
|
65
|
+
p.options[dests[i].options[k].name] = dests[i].options[k].value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
out.push_back(std::move(p));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
cupsFreeDests(num, dests);
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
PrinterDetailsNative MacPrinter::GetPrinter(const std::string &printerName)
|
|
76
|
+
{
|
|
77
|
+
auto list = GetPrinters();
|
|
78
|
+
for (auto &p : list)
|
|
79
|
+
if (p.name == printerName)
|
|
80
|
+
return p;
|
|
81
|
+
|
|
82
|
+
PrinterDetailsNative p;
|
|
83
|
+
p.name = printerName;
|
|
84
|
+
p.isDefault = false;
|
|
85
|
+
return p;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
std::string MacPrinter::GetDefaultPrinterName()
|
|
89
|
+
{
|
|
90
|
+
cups_dest_t *dests = nullptr;
|
|
91
|
+
int num = cupsGetDests(&dests);
|
|
92
|
+
|
|
93
|
+
cups_dest_t *def = cupsGetDest(NULL, NULL, num, dests);
|
|
94
|
+
|
|
95
|
+
std::string name;
|
|
96
|
+
if (def && def->name)
|
|
97
|
+
name = def->name;
|
|
98
|
+
|
|
99
|
+
cupsFreeDests(num, dests);
|
|
100
|
+
return name;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* =========================================================
|
|
104
|
+
Driver Options / Paper
|
|
105
|
+
========================================================= */
|
|
106
|
+
|
|
107
|
+
DriverOptions MacPrinter::GetPrinterDriverOptions(const std::string &printerName)
|
|
108
|
+
{
|
|
109
|
+
DriverOptions out;
|
|
110
|
+
|
|
111
|
+
const char *ppdPath = cupsGetPPD(printerName.c_str());
|
|
112
|
+
if (!ppdPath) return out;
|
|
113
|
+
|
|
114
|
+
ppd_file_t *ppd = ppdOpenFile(ppdPath);
|
|
115
|
+
if (!ppd)
|
|
116
|
+
{
|
|
117
|
+
unlink(ppdPath);
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
ppdMarkDefaults(ppd);
|
|
122
|
+
|
|
123
|
+
for (ppd_option_t *opt = ppd->options; opt; opt = opt->next)
|
|
124
|
+
{
|
|
125
|
+
std::map<std::string, bool> choices;
|
|
126
|
+
|
|
127
|
+
for (int i = 0; i < opt->num_choices; i++)
|
|
128
|
+
{
|
|
129
|
+
bool isDefault =
|
|
130
|
+
(opt->defchoice &&
|
|
131
|
+
strcmp(opt->defchoice, opt->choices[i].choice) == 0);
|
|
132
|
+
|
|
133
|
+
choices[opt->choices[i].choice] = isDefault;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
out[opt->keyword ? opt->keyword : ""] = choices;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
ppdClose(ppd);
|
|
140
|
+
unlink(ppdPath);
|
|
141
|
+
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
std::string MacPrinter::GetSelectedPaperSize(const std::string &printerName)
|
|
146
|
+
{
|
|
147
|
+
std::string paper;
|
|
148
|
+
|
|
149
|
+
const char *ppdPath = cupsGetPPD(printerName.c_str());
|
|
150
|
+
if (!ppdPath) return paper;
|
|
151
|
+
|
|
152
|
+
ppd_file_t *ppd = ppdOpenFile(ppdPath);
|
|
153
|
+
if (!ppd)
|
|
154
|
+
{
|
|
155
|
+
unlink(ppdPath);
|
|
156
|
+
return paper;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
ppdMarkDefaults(ppd);
|
|
160
|
+
|
|
161
|
+
ppd_option_t *opt = ppdFindOption(ppd, "PageSize");
|
|
162
|
+
if (!opt)
|
|
163
|
+
opt = ppdFindOption(ppd, "PageRegion");
|
|
164
|
+
|
|
165
|
+
if (opt && opt->defchoice)
|
|
166
|
+
paper = opt->defchoice;
|
|
167
|
+
|
|
168
|
+
ppdClose(ppd);
|
|
169
|
+
unlink(ppdPath);
|
|
170
|
+
|
|
171
|
+
return paper;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* =========================================================
|
|
175
|
+
Capabilities
|
|
176
|
+
========================================================= */
|
|
177
|
+
|
|
178
|
+
std::vector<std::string> MacPrinter::GetSupportedPrintFormats()
|
|
179
|
+
{
|
|
180
|
+
return { "RAW", "TEXT", "PDF", "JPEG", "POSTSCRIPT", "COMMAND", "AUTO" };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* =========================================================
|
|
184
|
+
Printing
|
|
185
|
+
========================================================= */
|
|
186
|
+
|
|
187
|
+
int MacPrinter::PrintDirect(const std::string &printerName,
|
|
188
|
+
const std::vector<uint8_t> &data,
|
|
189
|
+
const std::string &type,
|
|
190
|
+
const StringMap &options)
|
|
191
|
+
{
|
|
192
|
+
std::string t = ToUpper(type);
|
|
193
|
+
|
|
194
|
+
// For PDF/JPEG/POSTSCRIPT -> use temp file + cupsPrintFile
|
|
195
|
+
if (t == "PDF" || t == "JPEG" || t == "POSTSCRIPT")
|
|
196
|
+
{
|
|
197
|
+
char tmpName[] = "/tmp/esslassi_print_XXXXXX";
|
|
198
|
+
int fd = mkstemp(tmpName);
|
|
199
|
+
if (fd < 0)
|
|
200
|
+
return 0;
|
|
201
|
+
|
|
202
|
+
FILE *fp = fdopen(fd, "wb");
|
|
203
|
+
if (!fp)
|
|
204
|
+
{
|
|
205
|
+
close(fd);
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fwrite(data.data(), 1, data.size(), fp);
|
|
210
|
+
fclose(fp);
|
|
211
|
+
|
|
212
|
+
cups_option_t *cupOpts = nullptr;
|
|
213
|
+
int num = 0;
|
|
214
|
+
|
|
215
|
+
for (auto &kv : options)
|
|
216
|
+
num = cupsAddOption(kv.first.c_str(),
|
|
217
|
+
kv.second.c_str(),
|
|
218
|
+
num,
|
|
219
|
+
&cupOpts);
|
|
220
|
+
|
|
221
|
+
int jobId = cupsPrintFile(
|
|
222
|
+
printerName.c_str(),
|
|
223
|
+
tmpName,
|
|
224
|
+
"Node Print Job",
|
|
225
|
+
num,
|
|
226
|
+
cupOpts);
|
|
227
|
+
|
|
228
|
+
if (cupOpts)
|
|
229
|
+
cupsFreeOptions(num, cupOpts);
|
|
230
|
+
|
|
231
|
+
unlink(tmpName);
|
|
232
|
+
|
|
233
|
+
return jobId > 0 ? jobId : 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// RAW / TEXT / COMMAND
|
|
237
|
+
int jobId = cupsCreateJob(
|
|
238
|
+
CUPS_HTTP_DEFAULT,
|
|
239
|
+
printerName.c_str(),
|
|
240
|
+
"Node Print Job",
|
|
241
|
+
0,
|
|
242
|
+
NULL);
|
|
243
|
+
|
|
244
|
+
if (jobId <= 0)
|
|
245
|
+
return 0;
|
|
246
|
+
|
|
247
|
+
http_status_t st = cupsStartDocument(
|
|
248
|
+
CUPS_HTTP_DEFAULT,
|
|
249
|
+
printerName.c_str(),
|
|
250
|
+
jobId,
|
|
251
|
+
"Node Print Job",
|
|
252
|
+
CUPS_FORMAT_RAW,
|
|
253
|
+
1);
|
|
254
|
+
|
|
255
|
+
if (st != HTTP_STATUS_CONTINUE)
|
|
256
|
+
{
|
|
257
|
+
cupsCancelJob(printerName.c_str(), jobId);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (cupsWriteRequestData(
|
|
262
|
+
CUPS_HTTP_DEFAULT,
|
|
263
|
+
(const char*)data.data(),
|
|
264
|
+
data.size()) != HTTP_STATUS_CONTINUE)
|
|
265
|
+
{
|
|
266
|
+
cupsCancelJob(printerName.c_str(), jobId);
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
ipp_status_t fin =
|
|
271
|
+
(ipp_status_t)cupsFinishDocument(
|
|
272
|
+
CUPS_HTTP_DEFAULT,
|
|
273
|
+
printerName.c_str());
|
|
274
|
+
|
|
275
|
+
if (fin > IPP_STATUS_OK_CONFLICT)
|
|
276
|
+
return 0;
|
|
277
|
+
|
|
278
|
+
return jobId;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
int MacPrinter::PrintFile(const std::string &printerName,
|
|
282
|
+
const std::string &filename)
|
|
283
|
+
{
|
|
284
|
+
int jobId = cupsPrintFile(
|
|
285
|
+
printerName.c_str(),
|
|
286
|
+
filename.c_str(),
|
|
287
|
+
"Node Print Job",
|
|
288
|
+
0,
|
|
289
|
+
NULL);
|
|
290
|
+
|
|
291
|
+
return jobId > 0 ? jobId : 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* =========================================================
|
|
295
|
+
Job Management
|
|
296
|
+
========================================================= */
|
|
297
|
+
|
|
298
|
+
JobDetailsNative MacPrinter::GetJob(const std::string &printerName, int jobId)
|
|
299
|
+
{
|
|
300
|
+
JobDetailsNative j;
|
|
301
|
+
j.id = jobId;
|
|
302
|
+
j.printerName = printerName;
|
|
303
|
+
|
|
304
|
+
cups_job_t *jobs = nullptr;
|
|
305
|
+
int num = cupsGetJobs(
|
|
306
|
+
&jobs,
|
|
307
|
+
printerName.c_str(),
|
|
308
|
+
0,
|
|
309
|
+
CUPS_WHICHJOBS_ALL);
|
|
310
|
+
|
|
311
|
+
for (int i = 0; i < num; i++)
|
|
312
|
+
{
|
|
313
|
+
if (jobs[i].id == jobId)
|
|
314
|
+
{
|
|
315
|
+
j.name = jobs[i].title ? jobs[i].title : "";
|
|
316
|
+
j.user = jobs[i].user ? jobs[i].user : "";
|
|
317
|
+
j.format = jobs[i].format ? jobs[i].format : "";
|
|
318
|
+
j.priority = jobs[i].priority;
|
|
319
|
+
j.size = jobs[i].size;
|
|
320
|
+
|
|
321
|
+
switch (jobs[i].state)
|
|
322
|
+
{
|
|
323
|
+
case IPP_JSTATE_PENDING: j.status = { "PENDING" }; break;
|
|
324
|
+
case IPP_JSTATE_HELD: j.status = { "PAUSED" }; break;
|
|
325
|
+
case IPP_JSTATE_PROCESSING: j.status = { "PRINTING" }; break;
|
|
326
|
+
case IPP_JSTATE_STOPPED: j.status = { "ABORTED" }; break;
|
|
327
|
+
case IPP_JSTATE_CANCELED: j.status = { "CANCELLED" }; break;
|
|
328
|
+
case IPP_JSTATE_ABORTED: j.status = { "ABORTED" }; break;
|
|
329
|
+
case IPP_JSTATE_COMPLETED: j.status = { "PRINTED" }; break;
|
|
330
|
+
default: j.status = { "PENDING" }; break;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
j.creationTime = jobs[i].creation_time;
|
|
334
|
+
j.processingTime = jobs[i].processing_time;
|
|
335
|
+
j.completedTime = jobs[i].completed_time;
|
|
336
|
+
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
cupsFreeJobs(num, jobs);
|
|
342
|
+
return j;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void MacPrinter::SetJob(const std::string &printerName,
|
|
346
|
+
int jobId,
|
|
347
|
+
const std::string &command)
|
|
348
|
+
{
|
|
349
|
+
std::string cmd = ToUpper(command);
|
|
350
|
+
|
|
351
|
+
if (cmd == "CANCEL")
|
|
352
|
+
{
|
|
353
|
+
cupsCancelJob(printerName.c_str(), jobId);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (cmd == "PAUSE" || cmd == "HOLD")
|
|
358
|
+
{
|
|
359
|
+
cupsHoldJob(printerName.c_str(), jobId);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (cmd == "RESUME" || cmd == "RELEASE")
|
|
364
|
+
{
|
|
365
|
+
cupsReleaseJob(printerName.c_str(), jobId);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
std::vector<std::string> MacPrinter::GetSupportedJobCommands()
|
|
371
|
+
{
|
|
372
|
+
return { "CANCEL", "PAUSE", "RESUME" };
|
|
373
373
|
}
|