1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "print_cups_client.h"
17
18 #include <mutex>
19 #include <string>
20 #include <cups/cups-private.h>
21 #include <cups/adminutil.h>
22 #include <thread>
23 #include <semaphore.h>
24 #include <csignal>
25 #include <cstdlib>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <wifi_device.h>
30 #include <wifi_p2p.h>
31 #include <wifi_p2p_msg.h>
32
33 #include "system_ability_definition.h"
34 #include "parameter.h"
35 #include "nlohmann/json.hpp"
36 #include "print_service_ability.h"
37 #include "print_log.h"
38 #include "print_constant.h"
39 #include "print_utils.h"
40 #include "print_service_converter.h"
41 #include "print_cups_attribute.h"
42
43 namespace OHOS::Print {
44 using namespace std;
45 using json = nlohmann::json;
46
47 const uint32_t THOUSAND_INCH = 1000;
48 const uint32_t CUPS_SEVER_PORT = 1631;
49 const uint32_t TIME_OUT = 2000;
50 const uint32_t CONVERSION_UNIT = 2540;
51 const uint32_t LONG_TIME_OUT = 3000;
52 const uint32_t LONG_LONG_TIME_OUT = 30000;
53 const uint32_t INTERVAL_FOR_FIRST_QUERY = 1;
54 const uint32_t INTERVAL_FOR_QUERY = 2;
55 const uint32_t OFFLINE_RETRY_TIMES = 5;
56 const uint32_t RESOURCE_COUNT = 2;
57 const uint32_t DIR_COUNT = 3;
58 const uint32_t INDEX_ZERO = 0;
59 const uint32_t INDEX_ONE = 1;
60 const uint32_t INDEX_TWO = 2;
61 const uint32_t INDEX_THREE = 3;
62 const uint32_t MAX_RETRY_TIMES = 5;
63 const uint32_t BUFFER_LEN = 256;
64 const uint32_t DIR_MODE = 0771;
65 const uint32_t IP_RIGHT_SHIFT_0 = 0;
66 const uint32_t IP_RIGHT_SHIFT_8 = 8;
67 const uint32_t IP_RIGHT_SHIFT_16 = 16;
68 const uint32_t IP_RIGHT_SHIFT_24 = 24;
69 const uint32_t NUMBER_FOR_SPLICING_SUBSTATE = 100;
70 const uint32_t SERIAL_LENGTH = 6;
71
72 static bool g_isFirstQueryState = false;
73
74 static const std::string CUPS_ROOT_DIR = "/data/service/el1/public/print_service/cups";
75 static const std::string CUPS_RUN_DIR = "/data/service/el1/public/print_service/cups/run";
76 static const std::string DEFAULT_PPD_NAME = "everywhere";
77 static const std::string DEFAULT_MAKE_MODEL = "IPP Everywhere";
78 static const std::string REMOTE_PRINTER_MAKE_MODEL = "Remote Printer";
79 static const std::string DEFAULT_USER = "default";
80 static const std::string PRINTER_STATE_WAITING_COMPLETE = "cups-waiting-for-job-completed";
81 static const std::string PRINTER_STATE_WIFI_NOT_CONFIGURED = "wifi-not-configured-report";
82 static const std::string PRINTER_STATE_MEDIA_LOW_WARNING = "media-low-warning";
83 static const std::string PRINTER_STATE_TONER_LOW_WARNING = "toner-low-warning";
84 static const std::string PRINTER_STATE_TONER_LOW_REPORT = "toner-low-report";
85 static const std::string PRINTER_STATE_IGNORE_HP = "wifi-not-configured-report,cups-waiting-for-job-completed";
86 static const std::string PRINTER_STATE_IGNORE_BUSY =
87 "cups-ipp-conformance-failure-report,cups-ipp-missing-job-history,cups-waiting-for-job-completed";
88 static const std::string PRINTER_STATE_IGNORE_BUSY_COMPLETED =
89 "cups-ipp-conformance-failure-report,cups-ipp-missing-job-history";
90 static const std::string PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE =
91 "cups-ipp-conformance-failure-report,cups-ipp-missing-job-state";
92 static const std::string PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE_COMPLETED =
93 "cups-ipp-conformance-failure-report,cups-ipp-missing-job-state,cups-waiting-for-job-completed";
94 static const std::string PRINTER_STATE_IGNORE_TONER_LOW_JOB_STATE_COMPLETED =
95 "toner-low-warning,cups-waiting-for-job-completed";
96 static const std::string PRINTER_STATE_IGNORE_MEDIA_LOW_JOB_STATE_COMPLETED =
97 "media-low-warning,cups-waiting-for-job-completed";
98 static const std::string PRINTER_STATE_IGNORE_BUSY_WAITING_COMPLETE_OTHER_REPORT =
99 "cups-waiting-for-job-completed,other-report";
100 static const std::string PRINTER_STATE_IGNORE_BUSY_OTHER_REPORT = "other-report";
101 static const std::string PRINTER_STATE_MARKER_LOW_WARNING = "marker-supply-low-warning";
102 static const std::string PRINTER_STATE_MEDIA_EMPTY_WARNING = "media-empty-warning";
103 static const std::string PRINTER_STATE_NONE = "none";
104 static const std::string PRINTER_STATE_EMPTY = "";
105 static const std::string PRINTER_STATE_ERROR = "error";
106 static const std::string PRINTER_STATE_MEDIA_EMPTY = "media-empty";
107 static const std::string PRINTER_STATE_MEDIA_JAM = "media-jam";
108 static const std::string PRINTER_STATE_PAUSED = "paused";
109 static const std::string PRINTER_STATE_TONER_LOW = "toner-low";
110 static const std::string PRINTER_STATE_TONER_EMPTY = "toner-empty";
111 static const std::string PRINTER_STATE_DOOR_EMPTY = "door-open";
112 static const std::string PRINTER_STATE_MEDIA_NEEDED = "media-needed";
113 static const std::string PRINTER_STATE_MEDIA_NEEDED_ERROR = "media-needed-error";
114 static const std::string PRINTER_STATE_MARKER_LOW = "marker-supply-low";
115 static const std::string PRINTER_STATE_MARKER_EMPTY = "marker-supply-empty";
116 static const std::string PRINTER_STATE_INK_EMPTY = "marker-ink-almost-empty";
117 static const std::string PRINTER_STATE_COVER_OPEN = "cover-open";
118 static const std::string PRINTER_STATE_OFFLINE = "offline";
119 static const std::string DEFAULT_JOB_NAME = "test";
120 static const std::string CUPSD_CONTROL_PARAM = "print.cupsd.ready";
121 static const std::string P2P_PRINTER = "p2p";
122 static const std::string USB_PRINTER = "usb";
123 static const std::string PRINTER_ID_USB_PREFIX = "USB";
124 static const std::string PRINTER_MAKE_UNKNOWN = "Unknown";
125 static const std::string SPOOLER_BUNDLE_NAME = "com.ohos.spooler";
126 static const std::string VENDOR_MANAGER_PREFIX = "fwk.";
127 static const std::vector<std::string> IGNORE_STATE_LIST = {PRINTER_STATE_WAITING_COMPLETE,
128 PRINTER_STATE_NONE,
129 PRINTER_STATE_EMPTY,
130 PRINTER_STATE_WIFI_NOT_CONFIGURED,
131 PRINTER_STATE_MEDIA_LOW_WARNING,
132 PRINTER_STATE_TONER_LOW_WARNING,
133 PRINTER_STATE_TONER_LOW_REPORT,
134 PRINTER_STATE_IGNORE_HP,
135 PRINTER_STATE_IGNORE_BUSY,
136 PRINTER_STATE_IGNORE_BUSY_COMPLETED,
137 PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE,
138 PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE_COMPLETED,
139 PRINTER_STATE_IGNORE_TONER_LOW_JOB_STATE_COMPLETED,
140 PRINTER_STATE_IGNORE_MEDIA_LOW_JOB_STATE_COMPLETED,
141 PRINTER_STATE_IGNORE_BUSY_WAITING_COMPLETE_OTHER_REPORT,
142 PRINTER_STATE_IGNORE_BUSY_OTHER_REPORT};
143 std::mutex jobMutex;
144
145 static std::vector<PrinterInfo> usbPrinters;
DeviceCb(const char *deviceClass, const char *deviceId, const char *deviceInfo, const char *deviceMakeAndModel, const char *deviceUri, const char *deviceLocation, void *userData)146 static void DeviceCb(const char *deviceClass, const char *deviceId, const char *deviceInfo,
147 const char *deviceMakeAndModel, const char *deviceUri, const char *deviceLocation, void *userData)
148 {
149 PRINT_HILOGD("Device: uri = %{private}s\n", deviceUri);
150 PRINT_HILOGD("class = %{private}s\n", deviceClass);
151 PRINT_HILOGD("make-and-model = %{private}s\n", deviceMakeAndModel);
152 PRINT_HILOGD("location = %{private}s\n", deviceLocation);
153 std::string printerUri(deviceUri);
154 std::string printerMake(deviceMakeAndModel);
155 if (printerUri.length() > SERIAL_LENGTH && printerUri.substr(INDEX_ZERO, INDEX_THREE) == USB_PRINTER &&
156 printerMake != PRINTER_MAKE_UNKNOWN) {
157 std::string printerName(deviceInfo);
158 std::string serial = printerUri.substr(printerUri.length() - SERIAL_LENGTH);
159 PrinterInfo info;
160 info.SetPrinterId(PRINTER_ID_USB_PREFIX + "-" + printerName + "-" + serial);
161 info.SetPrinterName(PRINTER_ID_USB_PREFIX + "-" + printerName + "-" + serial);
162 info.SetPrinterMake(printerMake);
163 info.SetUri(printerUri);
164 info.SetPrinterState(PRINTER_ADDED);
165 PrinterCapability printerCapability;
166 info.SetCapability(printerCapability);
167 info.SetDescription("usb");
168 nlohmann::json infoOps;
169 infoOps["printerUri"] = printerUri;
170 infoOps["printerMake"] = printerMake;
171 info.SetOption(infoOps.dump());
172 usbPrinters.emplace_back(info);
173 }
174 }
175
PrintCupsClient()176 PrintCupsClient::PrintCupsClient()
177 {
178 printAbility_ = new (std::nothrow) PrintCupsWrapper();
179 }
180
~PrintCupsClient()181 PrintCupsClient::~PrintCupsClient()
182 {
183 if (printAbility_ != nullptr) {
184 delete printAbility_;
185 printAbility_ = nullptr;
186 }
187 }
188
StartCupsdService()189 int32_t PrintCupsClient::StartCupsdService()
190 {
191 PRINT_HILOGD("StartCupsdService enter");
192 if (!IsCupsServerAlive()) {
193 PRINT_HILOGI("The cupsd process is not started, start it now.");
194 int result = SetParameter(CUPSD_CONTROL_PARAM.c_str(), "true");
195 if (result) {
196 PRINT_HILOGD("SetParameter failed: %{public}d.", result);
197 return E_PRINT_SERVER_FAILURE;
198 }
199 const int bufferSize = 96;
200 char value[bufferSize] = {0};
201 GetParameter(CUPSD_CONTROL_PARAM.c_str(), "", value, bufferSize - 1);
202 PRINT_HILOGD("print.cupsd.ready value: %{public}s.", value);
203 return E_PRINT_NONE;
204 }
205 std::string pidFile = CUPS_RUN_DIR + "/cupsd.pid";
206 struct stat sb;
207 if (stat(pidFile.c_str(), &sb) != 0) {
208 PRINT_HILOGI("stat pidFile failed.");
209 return E_PRINT_SERVER_FAILURE;
210 }
211 char realPidFile[PATH_MAX] = {};
212 if (realpath(pidFile.c_str(), realPidFile) == nullptr) {
213 PRINT_HILOGE("The realPidFile is null, errno:%{public}s", std::to_string(errno).c_str());
214 return E_PRINT_SERVER_FAILURE;
215 }
216 int fd;
217 if ((fd = open(realPidFile, O_RDONLY)) < 0) {
218 PRINT_HILOGE("Open pidFile error!");
219 return E_PRINT_SERVER_FAILURE;
220 }
221 lseek(fd, 0, SEEK_SET);
222 char buf[BUFFER_LEN] = {0};
223 if ((read(fd, buf, sb.st_size)) < 0) {
224 PRINT_HILOGE("Read pidFile error!");
225 close(fd);
226 return E_PRINT_SERVER_FAILURE;
227 }
228 close(fd);
229 PRINT_HILOGD("The Process of CUPSD has existed, pid: %{public}s.", buf);
230 return E_PRINT_NONE;
231 }
232
ChangeFilterPermission(const std::string &path, mode_t mode)233 void PrintCupsClient::ChangeFilterPermission(const std::string &path, mode_t mode)
234 {
235 DIR *dir = opendir(path.c_str());
236 if (dir == nullptr) {
237 return;
238 }
239 struct dirent *entry;
240 while ((entry = readdir(dir)) != nullptr) {
241 std::string fileName = entry->d_name;
242 if (fileName == "." || fileName == "..") {
243 continue;
244 }
245 std::string filePath = path + "/" + fileName;
246 struct stat fileStat;
247 if (stat(filePath.c_str(), &fileStat) != 0) {
248 continue;
249 }
250 if (S_ISDIR(fileStat.st_mode)) {
251 ChangeFilterPermission(filePath.c_str(), mode);
252 } else if (S_ISREG(fileStat.st_mode)) {
253 if (chmod(filePath.c_str(), mode) == -1) {
254 PRINT_HILOGE("Failed to change mode");
255 }
256 }
257 }
258 closedir(dir);
259 }
260
SymlinkFile(std::string srcFilePath, std::string destFilePath)261 void PrintCupsClient::SymlinkFile(std::string srcFilePath, std::string destFilePath)
262 {
263 int ret = symlink(srcFilePath.c_str(), destFilePath.c_str());
264 if (!ret) {
265 PRINT_HILOGD("symlink success, ret = %{public}d, errno = %{public}d", ret, errno);
266 } else {
267 PRINT_HILOGE("symlink failed, ret = %{public}d, errno = %{public}d", ret, errno);
268 }
269 }
270
SymlinkDirectory(const char *srcDir, const char *destDir)271 void PrintCupsClient::SymlinkDirectory(const char *srcDir, const char *destDir)
272 {
273 DIR *dir = opendir(srcDir);
274 if (dir == nullptr) {
275 PRINT_HILOGE("Failed to open Dir: %{private}s", srcDir);
276 return;
277 }
278 if (access(destDir, F_OK)) {
279 mkdir(destDir, DIR_MODE);
280 }
281 struct dirent *file;
282 struct stat filestat = {};
283 struct stat destFilestat = {};
284 while ((file = readdir(dir)) != nullptr) {
285 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
286 continue;
287 }
288 std::string srcFilePath = std::string(srcDir) + "/" + std::string(file->d_name);
289 std::string destFilePath = std::string(destDir) + "/" + std::string(file->d_name);
290
291 stat(srcFilePath.c_str(), &filestat);
292 if (S_ISDIR(filestat.st_mode)) {
293 SymlinkDirectory(srcFilePath.c_str(), destFilePath.c_str());
294 } else if (lstat(destFilePath.c_str(), &destFilestat) == 0) {
295 PRINT_HILOGD("symlink lstat %{public}s err: %{public}s", destFilePath.c_str(), strerror(errno));
296
297 if (S_ISLNK(destFilestat.st_mode)) {
298 PRINT_HILOGW("symlink already exists, continue.");
299 continue;
300 }
301 if (std::remove(destFilePath.c_str()) != 0) {
302 PRINT_HILOGE("error deleting file %{public}s err: %{public}s",
303 destFilePath.c_str(), strerror(errno));
304 continue;
305 } else {
306 PRINT_HILOGW("file successfully deleted");
307 }
308 SymlinkFile(srcFilePath, destFilePath);
309 } else {
310 PRINT_HILOGE("symlink lstat %{public}s err: %{public}s", destFilePath.c_str(), strerror(errno));
311 SymlinkFile(srcFilePath, destFilePath);
312 }
313 }
314 closedir(dir);
315 }
316
CopyDirectory(const char *srcDir, const char *destDir)317 void PrintCupsClient::CopyDirectory(const char *srcDir, const char *destDir)
318 {
319 DIR *dir = opendir(srcDir);
320 if (dir == nullptr) {
321 PRINT_HILOGE("Failed to open Dir: %{private}s", srcDir);
322 return;
323 }
324 if (access(destDir, F_OK) != 0) {
325 mkdir(destDir, DIR_MODE);
326 }
327 struct dirent *file;
328 struct stat filestat;
329 while ((file = readdir(dir)) != nullptr) {
330 if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0) {
331 continue;
332 }
333 std::string srcFilePath = std::string(srcDir) + "/" + std::string(file->d_name);
334 std::string destFilePath = std::string(destDir) + "/" + std::string(file->d_name);
335
336 stat(srcFilePath.c_str(), &filestat);
337 if (S_ISDIR(filestat.st_mode)) {
338 CopyDirectory(srcFilePath.c_str(), destFilePath.c_str());
339 chmod(destFilePath.c_str(), filestat.st_mode);
340 } else {
341 char realSrc[PATH_MAX] = {};
342 char destSrc[PATH_MAX] = {};
343 if (realpath(srcFilePath.c_str(), realSrc) == nullptr ||
344 realpath(destDir, destSrc) == nullptr) {
345 PRINT_HILOGE("The realSrc is null, errno:%{public}s", std::to_string(errno).c_str());
346 continue;
347 }
348 FILE *srcFile = fopen(realSrc, "rb");
349 if (srcFile == nullptr) {
350 continue;
351 }
352 FILE *destFile = fopen(destFilePath.c_str(), "wb");
353 if (destFile == nullptr) {
354 fclose(srcFile);
355 continue;
356 }
357 char buffer[4096];
358 size_t bytesRead;
359 while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
360 fwrite(buffer, 1, bytesRead, destFile);
361 }
362 fclose(srcFile);
363 fclose(destFile);
364 chmod(destFilePath.c_str(), filestat.st_mode);
365 }
366 }
367 closedir(dir);
368 }
369
InitCupsResources()370 int32_t PrintCupsClient::InitCupsResources()
371 {
372 string array[RESOURCE_COUNT][DIR_COUNT] = {
373 {"/system/bin/cups/", CUPS_ROOT_DIR + "/serverbin", CUPS_ROOT_DIR + "/serverbin/daemon"},
374 {"/system/etc/cups/share/", CUPS_ROOT_DIR + "/datadir", CUPS_ROOT_DIR + "/datadir/mime"}
375 };
376 for (uint32_t i = 0; i < RESOURCE_COUNT; i++) {
377 if (!i) {
378 SymlinkDirectory(array[i][INDEX_ZERO].c_str(), array[i][INDEX_ONE].c_str());
379 } else {
380 if (access(array[i][INDEX_TWO].c_str(), F_OK) != -1) {
381 PRINT_HILOGD("The resource has been copied.");
382 continue;
383 }
384 CopyDirectory(array[i][INDEX_ZERO].c_str(), array[i][INDEX_ONE].c_str());
385 }
386 }
387 std::string dstDir = CUPS_ROOT_DIR + "/serverbin/filter";
388 SymlinkDirectory("/system/bin/uni_print_driver/filter/", dstDir.c_str());
389 dstDir = CUPS_ROOT_DIR + "/serverbin/backend";
390 SymlinkDirectory("/system/bin/uni_print_driver/backend/", dstDir.c_str());
391 return StartCupsdService();
392 }
393
StopCupsdService()394 void PrintCupsClient::StopCupsdService()
395 {
396 PRINT_HILOGD("StopCupsdService enter");
397 if (!IsCupsServerAlive()) {
398 PRINT_HILOGI("The cupsd process is not started, no need stop.");
399 return;
400 }
401 PRINT_HILOGI("The cupsd process is started, stop it now.");
402 int result = SetParameter(CUPSD_CONTROL_PARAM.c_str(), "false");
403 if (result) {
404 PRINT_HILOGD("SetParameter failed: %{public}d.", result);
405 return;
406 }
407 const int bufferSize = 96;
408 char value[bufferSize] = {0};
409 GetParameter(CUPSD_CONTROL_PARAM.c_str(), "", value, bufferSize - 1);
410 PRINT_HILOGD("print.cupsd.ready value: %{public}s.", value);
411 }
412
QueryPPDInformation(const char *makeModel, std::vector<std::string> &ppds)413 void PrintCupsClient::QueryPPDInformation(const char *makeModel, std::vector<std::string> &ppds)
414 {
415 ipp_t *request;
416 ipp_t *response;
417 const char *ppd_make_model;
418 const char *ppd_name;
419
420 if (printAbility_ == nullptr) {
421 PRINT_HILOGW("printAbility_ is null");
422 return;
423 }
424 request = ippNewRequest(CUPS_GET_PPDS);
425 if (request == nullptr) {
426 return;
427 }
428 if (makeModel) {
429 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model", NULL, makeModel);
430 }
431
432 PRINT_HILOGD("CUPS_GET_PPDS start.");
433 response = printAbility_->DoRequest(CUPS_HTTP_DEFAULT, request, "/");
434 if (response == NULL) {
435 PRINT_HILOGE("GetAvaiablePPDS failed: %{public}s", cupsLastErrorString());
436 return;
437 }
438 if (response->request.status.status_code > IPP_OK_CONFLICT) {
439 PRINT_HILOGE("GetAvaiablePPDS failed: %{public}s", cupsLastErrorString());
440 ippDelete(response);
441 return;
442 }
443 ParsePPDInfo(response, ppd_make_model, ppd_name, ppds);
444 ippDelete(response);
445 ippDelete(request);
446 }
447
ParsePPDInfo(ipp_t *response, const char *ppd_make_model, const char *ppd_name, std::vector<std::string> &ppds)448 void PrintCupsClient::ParsePPDInfo(ipp_t *response, const char *ppd_make_model, const char *ppd_name,
449 std::vector<std::string> &ppds)
450 {
451 if (response == nullptr) {
452 return;
453 }
454 for (ipp_attribute_t *attr = response->attrs; attr != NULL; attr = attr->next) {
455 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) {
456 attr = attr->next;
457 }
458 if (attr == NULL) {
459 break;
460 }
461 ppd_make_model = NULL;
462 ppd_name = NULL;
463
464 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
465 if (!strcmp(attr->name, "ppd-make-and-model") && attr->value_tag == IPP_TAG_TEXT) {
466 ppd_make_model = attr->values[0].string.text;
467 } else if (!strcmp(attr->name, "ppd-name") && attr->value_tag == IPP_TAG_NAME) {
468 ppd_name = attr->values[0].string.text;
469 }
470 attr = attr->next;
471 }
472 if (ppd_make_model != NULL && ppd_name != NULL) {
473 ppds.push_back(ppd_name);
474 PRINT_HILOGI("ppd: name = %{private}s, make-and-model = %{private}s", ppd_name, ppd_make_model);
475 }
476 if (attr == NULL) {
477 break;
478 }
479 }
480 }
481
AddPrinterToCups(const std::string &printerUri, const std::string &printerName, const std::string &printerMake)482 int32_t PrintCupsClient::AddPrinterToCups(const std::string &printerUri, const std::string &printerName,
483 const std::string &printerMake)
484 {
485 PRINT_HILOGD("PrintCupsClient AddPrinterToCups start, printerMake: %{public}s", printerMake.c_str());
486 ipp_t *request;
487 char uri[HTTP_MAX_URI] = {0};
488 std::vector<string> ppds;
489 std::string ppd = DEFAULT_PPD_NAME;
490 std::string standardName = PrintUtil::StandardizePrinterName(printerName);
491
492 ippSetPort(CUPS_SEVER_PORT);
493 QueryPPDInformation(printerMake.c_str(), ppds);
494 if (!ppds.empty()) {
495 ppd = ppds[0];
496 std::string serverBin = CUPS_ROOT_DIR + "/serverbin";
497 mode_t permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH;
498 ChangeFilterPermission(serverBin, permissions);
499 }
500 PRINT_HILOGI("ppd driver: %{public}s", ppd.c_str());
501 if (IsPrinterExist(printerUri.c_str(), standardName.c_str(), ppd.c_str())) {
502 PRINT_HILOGI("add success, printer has added");
503 return E_PRINT_NONE;
504 }
505 if (printAbility_ == nullptr) {
506 PRINT_HILOGW("printAbility_ is null");
507 return E_PRINT_SERVER_FAILURE;
508 }
509 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
510 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s",
511 standardName.c_str());
512 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
513 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
514 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, standardName.c_str());
515 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, printerUri.c_str());
516 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
517 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", NULL, ppd.c_str());
518 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
519 PRINT_HILOGD("IPP_OP_CUPS_ADD_MODIFY_PRINTER cupsDoRequest");
520 ippDelete(printAbility_->DoRequest(NULL, request, "/admin/"));
521 if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
522 PRINT_HILOGE("add error: %s", cupsLastErrorString());
523 return E_PRINT_SERVER_FAILURE;
524 }
525 PRINT_HILOGI("add success");
526 return E_PRINT_NONE;
527 }
528
AddPrinterToCupsWithPpd(const std::string &printerUri, const std::string &printerName, const std::string &ppdName, const std::string &ppdData)529 int32_t PrintCupsClient::AddPrinterToCupsWithPpd(const std::string &printerUri, const std::string &printerName,
530 const std::string &ppdName, const std::string &ppdData)
531 {
532 PRINT_HILOGD("AddPrinterToCupsWithPpd, ppdName: %{public}s", ppdName.c_str());
533 ipp_t *request = nullptr;
534 char uri[HTTP_MAX_URI] = {0};
535 std::vector<string> ppds;
536 std::string standardName = PrintUtil::StandardizePrinterName(printerName);
537 if (IsPrinterExist(printerUri.c_str(), standardName.c_str(), ppdName.c_str())) {
538 PRINT_HILOGI("add success, printer has added");
539 return E_PRINT_NONE;
540 }
541 ippSetPort(CUPS_SEVER_PORT);
542 _cupsSetError(IPP_STATUS_OK, NULL, 0);
543 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
544 if (request == nullptr) {
545 PRINT_HILOGW("request is null");
546 return E_PRINT_SERVER_FAILURE;
547 }
548 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s",
549 standardName.c_str());
550 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
551 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
552 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, standardName.c_str());
553 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, printerUri.c_str());
554 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
555 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
556 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared", 1);
557 PRINT_HILOGD("IPP_OP_CUPS_ADD_MODIFY_PRINTER cupsDoRequest");
558 http_status_t status = cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/admin/",
559 ippLength(request) + ppdData.length());
560 if (status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA) {
561 status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, ppdData.c_str(), ppdData.length());
562 } else {
563 ippDelete(request);
564 request = nullptr;
565 PRINT_HILOGW("ppd not send, status = %{public}d", static_cast<int>(status));
566 return E_PRINT_SERVER_FAILURE;
567 }
568 ippDelete(request);
569 request = nullptr;
570 if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE) {
571 PRINT_HILOGW("add error, status = %{public}d", static_cast<int>(status));
572 return E_PRINT_SERVER_FAILURE;
573 }
574 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
575 PRINT_HILOGE("add error: %s", cupsLastErrorString());
576 return E_PRINT_SERVER_FAILURE;
577 }
578 PRINT_HILOGI("add success");
579 return E_PRINT_NONE;
580 }
581
DeleteCupsPrinter(const char *printerName)582 int32_t PrintCupsClient::DeleteCupsPrinter(const char *printerName)
583 {
584 ipp_t *request;
585 char uri[HTTP_MAX_URI] = {0};
586
587 PRINT_HILOGD("PrintCupsClient DeleteCupsPrinter start: %{private}s", printerName);
588 if (printAbility_ == nullptr) {
589 PRINT_HILOGW("printAbility_ is null");
590 return E_PRINT_SERVER_FAILURE;
591 }
592 request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
593 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s", printerName);
594 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
595 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
596 ippDelete(printAbility_->DoRequest(NULL, request, "/admin/"));
597 if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
598 PRINT_HILOGW("DeleteCupsPrinter error: %{public}s", cupsLastErrorString());
599 }
600 return E_PRINT_NONE;
601 }
602
QueryPrinterAttributesByUri(const std::string &printerUri, const std::string &nic, int num, const char * const *pattrs)603 ipp_t *PrintCupsClient::QueryPrinterAttributesByUri(const std::string &printerUri, const std::string &nic, int num,
604 const char * const *pattrs)
605 {
606 ipp_t *request = nullptr; /* IPP Request */
607 ipp_t *response = nullptr; /* IPP Request */
608 http_t *http = nullptr;
609 char scheme[HTTP_MAX_URI] = {0}; /* Method portion of URI */
610 char username[HTTP_MAX_URI] = {0}; /* Username portion of URI */
611 char host[HTTP_MAX_URI] = {0}; /* Host portion of URI */
612 char resource[HTTP_MAX_URI] = {0}; /* Resource portion of URI */
613 int port = 0; /* Port portion of URI */
614 PRINT_HILOGD("QueryPrinterAttributesByUri enter");
615 if (printAbility_ == nullptr) {
616 PRINT_HILOGW("printAbility_ is null");
617 return nullptr;
618 }
619 httpSeparateURI(HTTP_URI_CODING_ALL, printerUri.c_str(), scheme, sizeof(scheme), username, sizeof(username), host,
620 sizeof(host), &port, resource, sizeof(resource));
621 if (nic.empty()) {
622 http = httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, TIME_OUT, NULL);
623 } else {
624 http = httpConnect3(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, TIME_OUT, NULL, nic.c_str());
625 }
626 if (http == nullptr) {
627 PRINT_HILOGW("connect printer failed");
628 return nullptr;
629 }
630 _cupsSetError(IPP_STATUS_OK, NULL, 0);
631 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
632 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printerUri.c_str());
633 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
634 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", num, NULL, pattrs);
635 response = printAbility_->DoRequest(http, request, "/");
636 httpClose(http);
637 http = nullptr;
638 if (response == nullptr) {
639 PRINT_HILOGW("response is null");
640 return nullptr;
641 }
642 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
643 PRINT_HILOGE("get printer attributes error: %{public}s", cupsLastErrorString());
644 ippDelete(response);
645 response = nullptr;
646 return nullptr;
647 }
648 return response;
649 }
650
QueryPrinterCapabilityByUri(const std::string &printerUri, const std::string &printerId, PrinterCapability &printerCaps)651 int32_t PrintCupsClient::QueryPrinterCapabilityByUri(const std::string &printerUri, const std::string &printerId,
652 PrinterCapability &printerCaps)
653 {
654 PRINT_HILOGD("PrintCupsClient QueryPrinterCapabilityByUri start.");
655 static const char * const pattrs[] = {
656 "all"
657 };
658 std::string nic;
659 IsIpConflict(printerId, nic);
660 ipp_t *response = QueryPrinterAttributesByUri(printerUri, nic, sizeof(pattrs) / sizeof(pattrs[0]), pattrs);
661 if (response == nullptr) {
662 PRINT_HILOGW("get attributes fail");
663 return E_PRINT_SERVER_FAILURE;
664 }
665 PRINT_HILOGD("get attributes success");
666 ParsePrinterAttributes(response, printerCaps);
667 ippDelete(response);
668 response = nullptr;
669 return E_PRINT_NONE;
670 }
671
QueryPrinterStatusByUri(const std::string &printerUri, PrinterStatus &status)672 int32_t PrintCupsClient::QueryPrinterStatusByUri(const std::string &printerUri, PrinterStatus &status)
673 {
674 PRINT_HILOGD("PrintCupsClient QueryPrinterStatusByUri start.");
675 static const char * const pattrs[] = {
676 "printer-state"
677 };
678 ipp_t *response = QueryPrinterAttributesByUri(printerUri, "", sizeof(pattrs) / sizeof(pattrs[0]), pattrs);
679 if (response == nullptr) {
680 PRINT_HILOGW("get attributes fail");
681 return E_PRINT_SERVER_FAILURE;
682 }
683 PRINT_HILOGD("get attributes success");
684 bool result = ParsePrinterStatusAttributes(response, status);
685 ippDelete(response);
686 response = nullptr;
687 if (!result) {
688 PRINT_HILOGW("parse state failed");
689 return E_PRINT_SERVER_FAILURE;
690 }
691 return E_PRINT_NONE;
692 }
693
QueryPrinterCapabilityFromPPD(const std::string &printerName, PrinterCapability &printerCaps)694 int32_t PrintCupsClient::QueryPrinterCapabilityFromPPD(const std::string &printerName, PrinterCapability &printerCaps)
695 {
696 std::string standardName = PrintUtil::StandardizePrinterName(printerName);
697 PRINT_HILOGI("QueryPrinterCapabilityFromPPD printerName: %{public}s", standardName.c_str());
698
699 cups_dest_t *dest = nullptr;
700 if (printAbility_ == nullptr) {
701 PRINT_HILOGW("printAbility_ is null");
702 return E_PRINT_SERVER_FAILURE;
703 }
704 dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, standardName.c_str(), NULL);
705 if (dest == nullptr) {
706 PRINT_HILOGE("the printer is not found");
707 return E_PRINT_SERVER_FAILURE;
708 }
709 cups_dinfo_t *dinfo = printAbility_->CopyDestInfo(CUPS_HTTP_DEFAULT, dest);
710 if (dinfo == nullptr) {
711 PRINT_HILOGE("cupsCopyDestInfo failed");
712 printAbility_->FreeDests(1, dest);
713 return E_PRINT_SERVER_FAILURE;
714 }
715
716 ParsePrinterAttributes(dinfo->attrs, printerCaps);
717 printerCaps.Dump();
718
719 printAbility_->FreeDestInfo(dinfo);
720 printAbility_->FreeDests(1, dest);
721 PRINT_HILOGI("QueryPrinterCapabilityFromPPD out\n");
722 return E_PRINT_NONE;
723 }
724
AddCupsPrintJob(const PrintJob &jobInfo)725 void PrintCupsClient::AddCupsPrintJob(const PrintJob &jobInfo)
726 {
727 JobParameters *jobParams = BuildJobParameters(jobInfo);
728 if (jobParams == nullptr) {
729 return;
730 }
731 DumpJobParameters(jobParams);
732 jobQueue_.push_back(jobParams);
733 StartNextJob();
734 }
735
GetNextJob()736 JobParameters *PrintCupsClient::GetNextJob()
737 {
738 if (jobQueue_.empty()) {
739 PRINT_HILOGE("no active job in jobQueue_");
740 return nullptr;
741 }
742 if (currentJob_ != nullptr) {
743 JobParameters *lastJob = jobQueue_.back();
744 if (lastJob != nullptr) {
745 PrintServiceAbility::GetInstance()->UpdatePrintJobState(lastJob->serviceJobId, PRINT_JOB_QUEUED,
746 PRINT_JOB_BLOCKED_UNKNOWN);
747 }
748 PRINT_HILOGE("a active job is running, job len: %{public}zd", jobQueue_.size());
749 return nullptr;
750 }
751 PRINT_HILOGI("start next job from queue");
752
753 std::lock_guard<std::mutex> lock(jobMutex);
754 currentJob_ = jobQueue_.at(0);
755 jobQueue_.erase(jobQueue_.begin());
756 return currentJob_;
757 }
758
StartNextJob()759 void PrintCupsClient::StartNextJob()
760 {
761 auto nextJob = GetNextJob();
762 if (nextJob == nullptr) {
763 PRINT_HILOGW("nextJob is nullptr");
764 return;
765 }
766 if (toCups_) {
767 auto self = shared_from_this();
768 CallbackFunc callback = [self]() { self->JobCompleteCallback(); };
769 std::thread StartPrintThread([self, callback] {self->StartCupsJob(self->currentJob_, callback);});
770 StartPrintThread.detach();
771 }
772 }
773
JobCompleteCallback()774 void PrintCupsClient::JobCompleteCallback()
775 {
776 PRINT_HILOGI("Previous job complete, start next job");
777 if (!currentJob_) {
778 delete currentJob_;
779 }
780 currentJob_ = nullptr;
781 StartNextJob();
782 }
783
FillBorderlessOptions(JobParameters *jobParams, int num_options, cups_option_t **options)784 int PrintCupsClient::FillBorderlessOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
785 {
786 if (jobParams == nullptr) {
787 PRINT_HILOGE("FillBorderlessOptions Params is nullptr");
788 return num_options;
789 }
790 if (jobParams->borderless == 1 && jobParams->mediaType == CUPS_MEDIA_TYPE_PHOTO_GLOSSY) {
791 PRINT_HILOGD("borderless job options");
792 std::vector<MediaSize> mediaSizes;
793 mediaSizes.push_back({ CUPS_MEDIA_4X6, 4000, 6000 });
794 mediaSizes.push_back({ CUPS_MEDIA_5X7, 5000, 7000 });
795 mediaSizes.push_back({ CUPS_MEDIA_A4, 8268, 11692 });
796 int sizeIndex = -1;
797 float meidaWidth = 0;
798 float mediaHeight = 0;
799 for (int i = 0; i < static_cast<int>(mediaSizes.size()); i++) {
800 if (mediaSizes[i].name == jobParams->mediaSize) {
801 sizeIndex = i;
802 break;
803 }
804 }
805 if (sizeIndex >= 0) {
806 meidaWidth = floorf(ConvertInchTo100MM(mediaSizes[sizeIndex].WidthInInches));
807 mediaHeight = floorf(ConvertInchTo100MM(mediaSizes[sizeIndex].HeightInInches));
808 } else {
809 meidaWidth = floorf(ConvertInchTo100MM(mediaSizes[0].WidthInInches));
810 mediaHeight = floorf(ConvertInchTo100MM(mediaSizes[0].HeightInInches));
811 }
812 PRINT_HILOGD("meidaWidth: %f, mediaHeight: %f", meidaWidth, mediaHeight);
813 std::stringstream value;
814 value << "{media-size={x-dimension=" << meidaWidth << " y-dimension=" << mediaHeight;
815 value << "} media-bottom-margin=" << 0 << " media-left-margin=" << 0 << " media-right-margin=" << 0;
816 value << " media-top-margin=" << 0 << " media-type=\"" << jobParams->mediaType << "\"}";
817 PRINT_HILOGD("value: %s", value.str().c_str());
818 num_options = cupsAddOption("media-col", value.str().c_str(), num_options, options);
819 } else {
820 PRINT_HILOGD("not borderless job options");
821 if (!jobParams->mediaSize.empty()) {
822 num_options = cupsAddOption(CUPS_MEDIA, jobParams->mediaSize.c_str(), num_options, options);
823 } else {
824 num_options = cupsAddOption(CUPS_MEDIA, CUPS_MEDIA_A4, num_options, options);
825 }
826 if (!jobParams->mediaType.empty()) {
827 num_options = cupsAddOption(CUPS_MEDIA_TYPE, jobParams->mediaType.c_str(), num_options, options);
828 } else {
829 num_options = cupsAddOption(CUPS_MEDIA_TYPE, CUPS_MEDIA_TYPE_PLAIN, num_options, options);
830 }
831 }
832 return num_options;
833 }
834
FillJobOptions(JobParameters *jobParams, int num_options, cups_option_t **options)835 int PrintCupsClient::FillJobOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
836 {
837 if (jobParams == nullptr) {
838 PRINT_HILOGE("FillJobOptions Params is nullptr");
839 return num_options;
840 }
841 if (jobParams->numCopies >= 1) {
842 num_options = cupsAddIntegerOption(CUPS_COPIES, jobParams->numCopies, num_options, options);
843 } else {
844 num_options = cupsAddIntegerOption(CUPS_COPIES, 1, num_options, options);
845 }
846
847 if (!jobParams->duplex.empty()) {
848 num_options = cupsAddOption(CUPS_SIDES, jobParams->duplex.c_str(), num_options, options);
849 } else {
850 num_options = cupsAddOption(CUPS_SIDES, CUPS_SIDES_ONE_SIDED, num_options, options);
851 }
852 if (!jobParams->printQuality.empty()) {
853 num_options = cupsAddOption(CUPS_PRINT_QUALITY, jobParams->printQuality.c_str(), num_options, options);
854 } else {
855 num_options = cupsAddOption(CUPS_PRINT_QUALITY, CUPS_PRINT_QUALITY_NORMAL, num_options, options);
856 }
857 if (!jobParams->color.empty()) {
858 num_options = cupsAddOption(CUPS_PRINT_COLOR_MODE, jobParams->color.c_str(), num_options, options);
859 } else {
860 num_options = cupsAddOption(CUPS_PRINT_COLOR_MODE, CUPS_PRINT_COLOR_MODE_AUTO, num_options, options);
861 }
862 std::string nic;
863 if (IsIpConflict(jobParams->printerId, nic)) {
864 num_options = cupsAddOption("nic", nic.c_str(), num_options, options);
865 }
866 num_options = FillBorderlessOptions(jobParams, num_options, options);
867 return num_options;
868 }
869
QueryAddedPrinterList(std::vector<std::string> &printerNameList)870 int32_t PrintCupsClient::QueryAddedPrinterList(std::vector<std::string> &printerNameList)
871 {
872 if (!IsCupsServerAlive()) {
873 PRINT_HILOGI("The cupsd process is not started, start it now.");
874 int32_t ret = StartCupsdService();
875 if (ret != 0) {
876 return E_PRINT_SERVER_FAILURE;
877 }
878 }
879 printerNameList.clear();
880 cups_dest_t *dests = NULL;
881 int num = cupsGetDests(&dests);
882 PRINT_HILOGI("QueryAddedPrinterList, num: %{public}d.", num);
883 for (int i = 0; i < num; i++) {
884 PRINT_HILOGD("QueryAddedPrinterList, printerIsDefault: %{public}d.", dests[i].is_default);
885 printerNameList.emplace_back(dests[i].name);
886 }
887 cupsFreeDests(num, dests);
888 return E_PRINT_NONE;
889 }
890
SetDefaultPrinter(const std::string &printerName)891 int32_t PrintCupsClient::SetDefaultPrinter(const std::string &printerName)
892 {
893 http_t *http;
894 if (printAbility_ == nullptr) {
895 PRINT_HILOGW("printAbility_ is null");
896 return E_PRINT_SERVER_FAILURE;
897 }
898 ippSetPort(CUPS_SEVER_PORT);
899 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, NULL);
900 if (http == nullptr) {
901 PRINT_HILOGE("cups server is not alive");
902 return E_PRINT_SERVER_FAILURE;
903 }
904 ipp_t *request; /* IPP Request */
905 char uri[HTTP_MAX_URI] = {0}; /* URI for printer/class */
906 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
907 "localhost", 0, "/printers/%s", printerName.c_str());
908 request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
909 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
910 "printer-uri", NULL, uri);
911 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
912 NULL, cupsUser());
913 ippDelete(printAbility_->DoRequest(http, request, "/admin/"));
914 httpClose(http);
915
916 const char* default_printer = cupsGetDefault();
917 PRINT_HILOGI("default_printer=%{public}s", default_printer);
918 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
919 PRINT_HILOGI("[ERROR] occur a error when do cups-request{setDefault}. error is:> ");
920 return E_PRINT_SERVER_FAILURE;
921 }
922 return E_PRINT_NONE;
923 }
924
GetPPDFile(const std::string &printerName)925 ppd_file_t* PrintCupsClient::GetPPDFile(const std::string &printerName)
926 {
927 if (!IsCupsServerAlive()) {
928 PRINT_HILOGI("The cupsd process is not started, start it now.");
929 int32_t ret = StartCupsdService();
930 if (ret != 0) {
931 return nullptr;
932 }
933 }
934 if (printerName.find("../") == 0) {
935 PRINT_HILOGE("GetPPDFile printerName is out of fileDir");
936 return nullptr;
937 }
938 ppd_file_t *ppd = 0;
939 std::string fileDir = "/data/service/el1/public/print_service/cups/ppd/";
940 std::string pName = printerName;
941 std::string filePath = fileDir + pName + ".ppd";
942 PRINT_HILOGI("GetPPDFile started filePath %{public}s", filePath.c_str());
943 char realPath[PATH_MAX] = {};
944 if (realpath(filePath.c_str(), realPath) == nullptr) {
945 PRINT_HILOGE("The realPidFile is null, errno:%{public}s", std::to_string(errno).c_str());
946 return nullptr;
947 }
948 int fd;
949 if ((fd = open(realPath, O_RDWR)) < 0) {
950 PRINT_HILOGE("Open ppdFile error!");
951 return nullptr;
952 }
953 PRINT_HILOGI("GetPPDFile %{public}d", fd);
954 ppd = ppdOpenFd(fd);
955 close(fd);
956 if (ppd == nullptr) {
957 PRINT_HILOGE("ppdfile open is nullptr");
958 } else {
959 PRINT_HILOGI("GetPPDFile groups:%{public}d,pagesize_num:%{public}d", ppd->num_groups, ppd->num_sizes);
960 }
961 return ppd;
962 }
963
QueryPrinterAttrList(const std::string &printerName, const std::vector<std::string> &keyList, std::vector<std::string> &valueList)964 int32_t PrintCupsClient::QueryPrinterAttrList(const std::string &printerName, const std::vector<std::string> &keyList,
965 std::vector<std::string> &valueList)
966 {
967 if (printAbility_ == nullptr) {
968 PRINT_HILOGW("printAbility_ is null");
969 return E_PRINT_SERVER_FAILURE;
970 }
971 cups_dest_t *dest = nullptr;
972 dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, printerName.c_str(), NULL);
973 if (dest == nullptr) {
974 PRINT_HILOGW("the printer is not found");
975 return E_PRINT_SERVER_FAILURE;
976 }
977 for (auto &key : keyList) {
978 const char *ret = cupsGetOption(key.c_str(), dest->num_options, dest->options);
979 if (ret != NULL) {
980 std::string valueStr = ret;
981 std::string value = key + "&" + valueStr;
982 valueList.emplace_back(value);
983 }
984 }
985 printAbility_->FreeDests(1, dest);
986 PRINT_HILOGI("QueryPrinterAttr end");
987 return E_PRINT_NONE;
988 }
989
QueryPrinterInfoByPrinterId(const std::string& printerId, PrinterInfo &info)990 int32_t PrintCupsClient::QueryPrinterInfoByPrinterId(const std::string& printerId, PrinterInfo &info)
991 {
992 PRINT_HILOGD("the printerInfo printerName %{public}s", info.GetPrinterName().c_str());
993 if (printAbility_ == nullptr) {
994 PRINT_HILOGW("printAbility_ is null");
995 return E_PRINT_SERVER_FAILURE;
996 }
997 cups_dest_t *dest = nullptr;
998 dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, info.GetPrinterName().c_str(), NULL);
999 if (dest == nullptr) {
1000 PRINT_HILOGW("the printer is not found");
1001 return E_PRINT_SERVER_FAILURE;
1002 }
1003 printAbility_->FreeDests(1, dest);
1004 if (info.HasOption()) {
1005 PRINT_HILOGI("the printerInfo option");
1006 PrinterCapability printerCaps;
1007 std::string infoOpt = info.GetOption();
1008 PRINT_HILOGD("the printerInfo option %{public}s", infoOpt.c_str());
1009 if (!json::accept(infoOpt)) {
1010 PRINT_HILOGE("infoOpt can not parse to json object");
1011 return E_PRINT_INVALID_PARAMETER;
1012 }
1013 nlohmann::json infoJson = nlohmann::json::parse(infoOpt);
1014 if (!infoJson.contains("printerUri") || !infoJson["printerUri"].is_string()) {
1015 PRINT_HILOGE("The infoJson does not have a necessary printerUri attribute.");
1016 return E_PRINT_INVALID_PARAMETER;
1017 }
1018 std::string printerUri = infoJson["printerUri"].get<std::string>();
1019 PRINT_HILOGD("QueryPrinterInfoByPrinterId in %{public}s", printerUri.c_str());
1020 if (infoJson.contains("printerName") && infoJson["printerName"].is_string()) {
1021 info.SetPrinterName(infoJson["printerName"].get<std::string>());
1022 }
1023 int32_t ret = QueryPrinterCapabilityByUri(printerUri, printerId, printerCaps);
1024 PRINT_HILOGI("QueryPrinterInfoByPrinterId out");
1025 if (ret != 0) {
1026 PRINT_HILOGE("QueryPrinterInfoByPrinterId QueryPrinterCapabilityByUri fail");
1027 return E_PRINT_SERVER_FAILURE;
1028 }
1029 nlohmann::json cupsOptionsJson = printerCaps.GetPrinterAttrGroupJson();
1030 infoJson["cupsOptions"] = cupsOptionsJson;
1031 info.SetOption(infoJson.dump());
1032 info.Dump();
1033 }
1034 return E_PRINT_NONE;
1035 }
1036
CheckPrinterMakeModel(JobParameters *jobParams)1037 bool PrintCupsClient::CheckPrinterMakeModel(JobParameters *jobParams)
1038 {
1039 cups_dest_t *dest = nullptr;
1040 bool isMakeModelRight = false;
1041 uint32_t retryCount = 0;
1042 PRINT_HILOGD("CheckPrinterMakeModel start.");
1043 if (jobParams == nullptr) {
1044 PRINT_HILOGE("The jobParams is null");
1045 return isMakeModelRight;
1046 }
1047 if (printAbility_ == nullptr) {
1048 PRINT_HILOGW("printAbility_ is null");
1049 return isMakeModelRight;
1050 }
1051 while (retryCount < MAX_RETRY_TIMES) {
1052 dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, jobParams->printerName.c_str(), NULL);
1053 if (dest != NULL) {
1054 const char *makeModel = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
1055 PRINT_HILOGD("makeModel=%{private}s", makeModel);
1056 if (makeModel != nullptr && strcmp(makeModel, "Local Raw Printer") != 0) {
1057 isMakeModelRight = true;
1058 printAbility_->FreeDests(1, dest);
1059 break;
1060 }
1061 printAbility_->FreeDests(1, dest);
1062 } else {
1063 PRINT_HILOGE("The dest is null");
1064 }
1065 retryCount++;
1066 sleep(INDEX_TWO);
1067 }
1068 return isMakeModelRight;
1069 }
1070
VerifyPrintJob(JobParameters *jobParams, int &num_options, uint32_t &jobId, cups_option_t *options, http_t *http)1071 bool PrintCupsClient::VerifyPrintJob(JobParameters *jobParams, int &num_options, uint32_t &jobId,
1072 cups_option_t *options, http_t *http)
1073 {
1074 if (jobParams == nullptr) {
1075 PRINT_HILOGE("The jobParams is null");
1076 return false;
1077 }
1078 uint32_t retryCount = 0;
1079 bool isPrinterOnline = false;
1080 JobMonitorParam *monitorParam = new (std::nothrow) JobMonitorParam { jobParams->serviceAbility,
1081 jobParams->serviceJobId, jobId, jobParams->printerUri, jobParams->printerName, jobParams->printerId };
1082 if (monitorParam == nullptr) {
1083 PRINT_HILOGE("monitorParam is null");
1084 return false;
1085 }
1086 while (retryCount < MAX_RETRY_TIMES) {
1087 if (CheckPrinterOnline(monitorParam)) {
1088 isPrinterOnline = true;
1089 break;
1090 }
1091 retryCount++;
1092 sleep(INDEX_ONE);
1093 }
1094 delete monitorParam;
1095 if (!isPrinterOnline) {
1096 jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1097 PRINT_JOB_BLOCKED_OFFLINE);
1098 return false;
1099 }
1100 if (!CheckPrinterMakeModel(jobParams)) {
1101 PRINT_HILOGE("VerifyPrintJob printer make model is error");
1102 jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1103 PRINT_JOB_BLOCKED_DRIVER_EXCEPTION);
1104 return false;
1105 }
1106 num_options = FillJobOptions(jobParams, num_options, &options);
1107 if ((jobId = static_cast<uint32_t>(cupsCreateJob(http, jobParams->printerName.c_str(), jobParams->jobName.c_str(),
1108 num_options, options))) == 0) {
1109 PRINT_HILOGE("Unable to cupsCreateJob: %s", cupsLastErrorString());
1110 jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1111 PRINT_JOB_BLOCKED_SERVER_CONNECTION_ERROR);
1112 return false;
1113 }
1114 return true;
1115 }
1116
HandleFiles(JobParameters *jobParams, uint32_t num_files, http_t *http, uint32_t jobId)1117 bool PrintCupsClient::HandleFiles(JobParameters *jobParams, uint32_t num_files, http_t *http, uint32_t jobId)
1118 {
1119 if (jobParams == nullptr) {
1120 PRINT_HILOGW("jobParams is null");
1121 return false;
1122 }
1123 cups_file_t *fp = nullptr;
1124 http_status_t status;
1125 char buffer[8192];
1126 ssize_t bytes = -1;
1127
1128 for (uint32_t i = 0; i < num_files; i++) {
1129 if ((fp = cupsFileOpenFd(jobParams->fdList[i], "rb")) == NULL) {
1130 PRINT_HILOGE("Unable to open print file, cancel the job");
1131 cupsCancelJob2(http, jobParams->printerName.c_str(), jobId, 0);
1132 UpdatePrintJobStateInJobParams(jobParams, PRINT_JOB_BLOCKED, PRINT_JOB_COMPLETED_FILE_CORRUPT);
1133 return false;
1134 }
1135 status = cupsStartDocument(http, jobParams->printerName.c_str(), jobId, jobParams->jobName.c_str(),
1136 jobParams->documentFormat.c_str(), i == (num_files - 1));
1137 if (status == HTTP_STATUS_CONTINUE) {
1138 bytes = cupsFileRead(fp, buffer, sizeof(buffer));
1139 }
1140 while (status == HTTP_STATUS_CONTINUE && bytes > 0) {
1141 status = cupsWriteRequestData(http, buffer, (size_t)bytes);
1142 bytes = cupsFileRead(fp, buffer, sizeof(buffer));
1143 }
1144 cupsFileClose(fp);
1145 if (status != HTTP_STATUS_CONTINUE || cupsFinishDocument(http, jobParams->printerName.c_str())
1146 != IPP_STATUS_OK) {
1147 PRINT_HILOGE("Unable to queue, error is %{public}s, cancel the job and return...", cupsLastErrorString());
1148 cupsCancelJob2(http, jobParams->printerUri.c_str(), jobId, 0);
1149 UpdatePrintJobStateInJobParams(jobParams, PRINT_JOB_BLOCKED, PRINT_JOB_BLOCKED_UNKNOWN);
1150 return false;
1151 }
1152 }
1153 return true;
1154 }
1155
StartCupsJob(JobParameters *jobParams, CallbackFunc callback)1156 void PrintCupsClient::StartCupsJob(JobParameters *jobParams, CallbackFunc callback)
1157 {
1158 http_t *http = nullptr;
1159 int num_options = 0;
1160 cups_option_t *options = nullptr;
1161 uint32_t jobId;
1162
1163 if (!VerifyPrintJob(jobParams, num_options, jobId, options, http)) {
1164 callback();
1165 return;
1166 }
1167 uint32_t num_files = jobParams->fdList.size();
1168 PRINT_HILOGD("StartCupsJob fill job options, num_files: %{public}d", num_files);
1169 if (!HandleFiles(jobParams, num_files, http, jobId)) {
1170 callback();
1171 return;
1172 }
1173 jobParams->cupsJobId = jobId;
1174 PRINT_HILOGD("start job success, jobId: %{public}d", jobId);
1175 JobMonitorParam *param = new (std::nothrow) JobMonitorParam { jobParams->serviceAbility,
1176 jobParams->serviceJobId, jobId, jobParams->printerUri, jobParams->printerName, jobParams->printerId };
1177 if (param == nullptr) {
1178 PRINT_HILOGW("param is null");
1179 callback();
1180 return;
1181 }
1182 g_isFirstQueryState = true;
1183 PRINT_HILOGD("MonitorJobState enter, cupsJobId: %{public}d", param->cupsJobId);
1184 MonitorJobState(param, callback);
1185 PRINT_HILOGI("FINISHED MONITORING JOB %{public}d\n", param->cupsJobId);
1186 delete param;
1187 }
1188
UpdatePrintJobStateInJobParams(JobParameters *jobParams, uint32_t state, uint32_t subState)1189 void PrintCupsClient::UpdatePrintJobStateInJobParams(JobParameters *jobParams, uint32_t state, uint32_t subState)
1190 {
1191 if (jobParams != nullptr && jobParams->serviceAbility != nullptr) {
1192 jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, state, subState);
1193 }
1194 }
1195
HandleJobState(http_t *http, JobMonitorParam *param, JobStatus *jobStatus, JobStatus *prevousJobStatus)1196 void PrintCupsClient::HandleJobState(http_t *http, JobMonitorParam *param, JobStatus *jobStatus,
1197 JobStatus *prevousJobStatus)
1198 {
1199 QueryJobState(http, param, jobStatus);
1200 if (g_isFirstQueryState) {
1201 QueryJobStateAgain(http, param, jobStatus);
1202 }
1203 if (jobStatus->job_state < IPP_JSTATE_CANCELED) {
1204 sleep(INTERVAL_FOR_QUERY);
1205 }
1206 if (jobStatus->job_state == 0) {
1207 PRINT_HILOGD("job_state is 0, continue");
1208 return;
1209 }
1210 if (prevousJobStatus != nullptr && prevousJobStatus->job_state == jobStatus->job_state &&
1211 strcmp(prevousJobStatus->printer_state_reasons, jobStatus->printer_state_reasons) == 0) {
1212 PRINT_HILOGD("the prevous jobState is the same as current, ignore");
1213 return;
1214 }
1215 UpdateJobStatus(prevousJobStatus, jobStatus);
1216 JobStatusCallback(param, jobStatus, false);
1217 }
1218
MonitorJobState(JobMonitorParam *param, CallbackFunc callback)1219 void PrintCupsClient::MonitorJobState(JobMonitorParam *param, CallbackFunc callback)
1220 {
1221 if (param == nullptr) {
1222 return;
1223 }
1224 http_t *http = NULL;
1225 uint32_t fail_connect_times = 0;
1226 ippSetPort(CUPS_SEVER_PORT);
1227 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, NULL);
1228 if (http == nullptr) {
1229 return;
1230 }
1231 JobStatus *jobStatus = new (std::nothrow) JobStatus { {'\0'}, (ipp_jstate_t)0, {'\0'}};
1232 if (jobStatus == nullptr) {
1233 httpClose(http);
1234 PRINT_HILOGE("new JobStatus returns nullptr");
1235 return;
1236 }
1237 JobStatus *prevousJobStatus = new (std::nothrow) JobStatus { {'\0'}, (ipp_jstate_t)0, {'\0'}};
1238 if (prevousJobStatus == nullptr) {
1239 httpClose(http);
1240 delete jobStatus;
1241 PRINT_HILOGE("new prevousJobStatus returns nullptr");
1242 return;
1243 }
1244 while (jobStatus != nullptr && jobStatus->job_state < IPP_JSTATE_CANCELED) {
1245 if (fail_connect_times > OFFLINE_RETRY_TIMES) {
1246 PRINT_HILOGE("_start(): The maximum number of connection failures has been exceeded");
1247 JobStatusCallback(param, jobStatus, true);
1248 break;
1249 }
1250 if (httpGetFd(http) < 0) {
1251 PRINT_HILOGE("http is NULL");
1252 httpReconnect2(http, LONG_LONG_TIME_OUT, NULL);
1253 }
1254 if (httpGetFd(http) < 0 || !CheckPrinterOnline(param)) {
1255 PRINT_HILOGE("unable connect to printer, retry: %{public}d", fail_connect_times);
1256 fail_connect_times++;
1257 sleep(INTERVAL_FOR_QUERY);
1258 continue;
1259 }
1260 fail_connect_times = 0;
1261 HandleJobState(http, param, jobStatus, prevousJobStatus);
1262 }
1263 httpClose(http);
1264 delete jobStatus;
1265 delete prevousJobStatus;
1266 callback();
1267 }
1268
QueryJobStateAgain(http_t *http, JobMonitorParam *param, JobStatus *jobStatus)1269 void PrintCupsClient::QueryJobStateAgain(http_t *http, JobMonitorParam *param, JobStatus *jobStatus)
1270 {
1271 sleep(INTERVAL_FOR_FIRST_QUERY);
1272 QueryJobState(http, param, jobStatus);
1273 g_isFirstQueryState = false;
1274 }
1275
UpdateJobStatus(JobStatus *prevousJobStatus, JobStatus *jobStatus)1276 void PrintCupsClient::UpdateJobStatus(JobStatus *prevousJobStatus, JobStatus *jobStatus)
1277 {
1278 if (prevousJobStatus != nullptr && jobStatus != nullptr) {
1279 prevousJobStatus->job_state = jobStatus->job_state;
1280 strlcpy(prevousJobStatus->printer_state_reasons,
1281 jobStatus->printer_state_reasons,
1282 sizeof(jobStatus->printer_state_reasons));
1283 }
1284 }
1285
JobStatusCallback(JobMonitorParam *param, JobStatus *jobStatus, bool isOffline)1286 void PrintCupsClient::JobStatusCallback(JobMonitorParam *param, JobStatus *jobStatus, bool isOffline)
1287 {
1288 if (param == nullptr || jobStatus == nullptr) {
1289 PRINT_HILOGE("JobStatusCallback param is nullptr");
1290 return;
1291 }
1292 PRINT_HILOGI("JobStatusCallback enter, job_state: %{public}d", jobStatus->job_state);
1293 PRINT_HILOGI("JobStatusCallback enter, printer_state_reasons: %{public}s", jobStatus->printer_state_reasons);
1294 if (isOffline) {
1295 cupsCancelJob2(CUPS_HTTP_DEFAULT, param->printerName.c_str(), param->cupsJobId, 0);
1296 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_BLOCKED,
1297 PRINT_JOB_BLOCKED_OFFLINE);
1298 return;
1299 }
1300 if (jobStatus->job_state == IPP_JOB_COMPLETED) {
1301 PRINT_HILOGD("IPP_JOB_COMPLETED");
1302 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_COMPLETED,
1303 PRINT_JOB_COMPLETED_SUCCESS);
1304 } else if (jobStatus->job_state == IPP_JOB_PROCESSING) {
1305 PRINT_HILOGD("IPP_JOB_PROCESSING");
1306 std::string printerState(jobStatus->printer_state_reasons);
1307 if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_ERROR.c_str()) == NULL) {
1308 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_RUNNING,
1309 PRINT_JOB_BLOCKED_BUSY);
1310 } else {
1311 ReportBlockedReason(param, jobStatus);
1312 }
1313 } else if (jobStatus->job_state == IPP_JOB_CANCELED || jobStatus->job_state == IPP_JOB_ABORTED ||
1314 jobStatus->job_state == IPP_JOB_STOPPED) {
1315 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_COMPLETED,
1316 PRINT_JOB_COMPLETED_CANCELLED);
1317 } else if (jobStatus->job_state == IPP_JOB_PENDING || jobStatus->job_state == IPP_JOB_HELD) {
1318 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_QUEUED,
1319 PRINT_JOB_BLOCKED_UNKNOWN);
1320 } else {
1321 PRINT_HILOGE("wrong job state: %{public}d", jobStatus->job_state);
1322 }
1323 }
1324
ReportBlockedReason(JobMonitorParam *param, JobStatus *jobStatus)1325 void PrintCupsClient::ReportBlockedReason(JobMonitorParam *param, JobStatus *jobStatus)
1326 {
1327 if (param == nullptr || param->serviceAbility == nullptr || jobStatus == nullptr) {
1328 PRINT_HILOGE("ReportBlockedReason parameter is nullptr");
1329 return;
1330 }
1331 if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_OFFLINE.c_str()) != NULL) {
1332 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_BLOCKED, PRINT_JOB_BLOCKED_OFFLINE);
1333 return;
1334 }
1335 if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_PAUSED.c_str()) != NULL) {
1336 param->serviceAbility->UpdatePrintJobState(
1337 param->serviceJobId, PRINT_JOB_BLOCKED, PRINT_JOB_BLOCKED_SERVICE_REQUEST);
1338 return;
1339 }
1340
1341 uint32_t substate = GetBlockedSubstate(jobStatus);
1342 if (substate > PRINT_JOB_COMPLETED_SUCCESS) {
1343 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_BLOCKED,
1344 substate);
1345 } else {
1346 param->serviceAbility->UpdatePrintJobState(param->serviceJobId, PRINT_JOB_BLOCKED,
1347 PRINT_JOB_BLOCKED_UNKNOWN);
1348 }
1349 }
1350
GetBlockedSubstate(JobStatus *jobStatus)1351 uint32_t PrintCupsClient::GetBlockedSubstate(JobStatus *jobStatus)
1352 {
1353 if (jobStatus == nullptr) {
1354 PRINT_HILOGE("GetBlockedSubstate param is nullptr");
1355 return PRINT_JOB_COMPLETED_FAILED;
1356 }
1357 uint32_t substate = PRINT_JOB_COMPLETED_SUCCESS;
1358 if ((strstr(jobStatus->printer_state_reasons, PRINTER_STATE_MEDIA_EMPTY.c_str()) != NULL) ||
1359 (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_MEDIA_NEEDED_ERROR.c_str()) != NULL)) {
1360 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_OUT_OF_PAPER;
1361 }
1362 if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_MEDIA_JAM.c_str()) != NULL) {
1363 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_JAMMED;
1364 }
1365 if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_TONER_EMPTY.c_str()) != NULL) {
1366 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_OUT_OF_TONER;
1367 } else if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_TONER_LOW.c_str()) != NULL) {
1368 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_LOW_ON_TONER;
1369 }
1370 if ((strstr(jobStatus->printer_state_reasons, PRINTER_STATE_MARKER_EMPTY.c_str()) != NULL) ||
1371 (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_INK_EMPTY.c_str()) != NULL)) {
1372 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_OUT_OF_INK;
1373 } else if (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_MARKER_LOW.c_str()) != NULL) {
1374 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_LOW_ON_INK;
1375 }
1376 if ((strstr(jobStatus->printer_state_reasons, PRINTER_STATE_DOOR_EMPTY.c_str()) != NULL) ||
1377 (strstr(jobStatus->printer_state_reasons, PRINTER_STATE_COVER_OPEN.c_str()) != NULL)) {
1378 substate = substate * NUMBER_FOR_SPLICING_SUBSTATE + PRINT_JOB_BLOCKED_DOOR_OPEN;
1379 }
1380 return substate;
1381 }
1382
QueryJobState(http_t *http, JobMonitorParam *param, JobStatus *jobStatus)1383 void PrintCupsClient::QueryJobState(http_t *http, JobMonitorParam *param, JobStatus *jobStatus)
1384 {
1385 ipp_t *request; /* IPP request */
1386 ipp_t *response; /* IPP response */
1387 ipp_attribute_t *attr; /* Attribute in response */
1388 int jattrsLen = 3;
1389 static const char * const jattrs[] = {
1390 "job-state",
1391 "job-state-reasons",
1392 "job-printer-state-reasons"
1393 };
1394 if (printAbility_ == nullptr) {
1395 PRINT_HILOGW("printAbility_ is null");
1396 return;
1397 }
1398 if (param == nullptr || jobStatus == nullptr) {
1399 PRINT_HILOGE("QueryJobState param is null");
1400 return;
1401 }
1402 if (param->cupsJobId > 0) {
1403 request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES);
1404 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, param->printerUri.c_str());
1405 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", param->cupsJobId);
1406 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, DEFAULT_USER.c_str());
1407 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", jattrsLen, NULL, jattrs);
1408 PRINT_HILOGD("get job state from cups service: start");
1409 response = printAbility_->DoRequest(http, request, "/");
1410 if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) {
1411 jobStatus->job_state = (ipp_jstate_t)ippGetInteger(attr, 0);
1412 }
1413 if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL) {
1414 ippAttributeString(attr, jobStatus->job_state_reasons, sizeof(jobStatus->job_state_reasons));
1415 }
1416 if ((attr = ippFindAttribute(response, "job-printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) {
1417 ippAttributeString(attr, jobStatus->printer_state_reasons, sizeof(jobStatus->printer_state_reasons));
1418 }
1419 PRINT_HILOGE("JOB %{public}d: %{public}s (%{public}s), PRINTER: %{public}s\n", param->cupsJobId,
1420 ippEnumString("job-state", (int)jobStatus->job_state), jobStatus->job_state_reasons,
1421 jobStatus->printer_state_reasons);
1422 ippDelete(response);
1423 }
1424 }
1425
CheckPrinterOnline(JobMonitorParam *param, const uint32_t timeout)1426 bool PrintCupsClient::CheckPrinterOnline(JobMonitorParam *param, const uint32_t timeout)
1427 {
1428 http_t *http;
1429 char scheme[32] = {0};
1430 char userpass[BUFFER_LEN] = {0};
1431 char host[BUFFER_LEN] = {0};
1432 char resource[BUFFER_LEN] = {0};
1433 int port;
1434 if (param == nullptr) {
1435 PRINT_HILOGE("param is null");
1436 return false;
1437 }
1438 const char* printerUri = param->printerUri.c_str();
1439 const std::string printerId = param->printerId;
1440 PRINT_HILOGD("CheckPrinterOnline printerId: %{public}s", printerId.c_str());
1441 bool isUsbPrinter = param->printerUri.length() > USB_PRINTER.length() &&
1442 param->printerUri.substr(INDEX_ZERO, INDEX_THREE) == USB_PRINTER;
1443 bool isCustomizedExtension = !(PrintUtil::startsWith(printerId, SPOOLER_BUNDLE_NAME) ||
1444 PrintUtil::startsWith(printerId, VENDOR_MANAGER_PREFIX));
1445 if ((isUsbPrinter || isCustomizedExtension) && param->serviceAbility != nullptr) {
1446 if (param->serviceAbility->QueryDiscoveredPrinterInfoById(printerId) == nullptr) {
1447 PRINT_HILOGI("printer offline");
1448 return false;
1449 } else {
1450 PRINT_HILOGI("printer online");
1451 return true;
1452 }
1453 } else {
1454 httpSeparateURI(HTTP_URI_CODING_ALL, printerUri, scheme, sizeof(scheme),
1455 userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource));
1456 }
1457 std::string nic;
1458 if (IsIpConflict(printerId, nic)) {
1459 http = httpConnect3(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, timeout, NULL,
1460 nic.c_str());
1461 } else {
1462 http = httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, timeout, NULL);
1463 }
1464 if (http == nullptr) {
1465 PRINT_HILOGE("httpConnect2 printer failed");
1466 return false;
1467 }
1468 httpClose(http);
1469 return true;
1470 }
1471
CancelCupsJob(std::string serviceJobId)1472 void PrintCupsClient::CancelCupsJob(std::string serviceJobId)
1473 {
1474 PRINT_HILOGD("CancelCupsJob(): Enter, serviceJobId: %{public}s", serviceJobId.c_str());
1475 int jobIndex = -1;
1476 for (int index = 0; index < static_cast<int>(jobQueue_.size()); index++) {
1477 PRINT_HILOGD("jobQueue_[index]->serviceJobId: %{public}s", jobQueue_[index]->serviceJobId.c_str());
1478 if (jobQueue_[index]->serviceJobId == serviceJobId) {
1479 jobIndex = index;
1480 break;
1481 }
1482 }
1483 PRINT_HILOGI("jobIndex: %{public}d", jobIndex);
1484 if (jobIndex >= 0) {
1485 PRINT_HILOGI("job in queue, delete");
1486 jobQueue_.erase(jobQueue_.begin() + jobIndex);
1487 PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_COMPLETED,
1488 PRINT_JOB_COMPLETED_CANCELLED);
1489 } else {
1490 // 任务正在运行中
1491 if (currentJob_ && currentJob_->serviceJobId == serviceJobId) {
1492 PRINT_HILOGI("cancel current job");
1493 if (cupsCancelJob2(CUPS_HTTP_DEFAULT, currentJob_->printerName.c_str(),
1494 currentJob_->cupsJobId, 0) != IPP_OK) {
1495 PRINT_HILOGE("cancel Joob Error %{public}s", cupsLastErrorString());
1496 PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_COMPLETED,
1497 PRINT_JOB_COMPLETED_CANCELLED);
1498 JobCompleteCallback();
1499 return;
1500 }
1501 } else {
1502 PRINT_HILOGI("job is not exist");
1503 PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_COMPLETED,
1504 PRINT_JOB_COMPLETED_CANCELLED);
1505 }
1506 }
1507 }
1508
UpdateBorderlessJobParameter(json& optionJson, JobParameters *params)1509 void PrintCupsClient::UpdateBorderlessJobParameter(json& optionJson, JobParameters *params)
1510 {
1511 if (params == nullptr) {
1512 return;
1513 }
1514 if (optionJson.contains("documentCategory") && optionJson["documentCategory"].is_number()) {
1515 params->borderless = optionJson["documentCategory"];
1516 } else if (optionJson.contains("borderless") && optionJson["borderless"].is_string()) {
1517 std::string isBorderless = optionJson["borderless"].get<std::string>();
1518 if (isBorderless == "true") {
1519 params->borderless = 1; // 1: borderless
1520 } else {
1521 params->borderless = 0;
1522 }
1523 } else {
1524 params->borderless = 0;
1525 }
1526 }
1527
BuildJobParameters(const PrintJob &jobInfo)1528 JobParameters* PrintCupsClient::BuildJobParameters(const PrintJob &jobInfo)
1529 {
1530 JobParameters *params = nullptr;
1531 if (!jobInfo.HasOption()) {
1532 PRINT_HILOGE("option is empty");
1533 return params;
1534 }
1535 std::string option = jobInfo.GetOption();
1536 if (!json::accept(option)) {
1537 PRINT_HILOGE("option can not parse to json object");
1538 return params;
1539 }
1540 json optionJson = json::parse(option);
1541 PRINT_HILOGD("test optionJson: %{private}s", optionJson.dump().c_str());
1542 if (!optionJson.contains("printerUri") || !optionJson.contains("printerName")
1543 || !optionJson.contains("documentFormat")) {
1544 PRINT_HILOGE("The option does not have a necessary attribute.");
1545 return params;
1546 }
1547 params = new (std::nothrow) JobParameters {};
1548 if (params == nullptr) {
1549 PRINT_HILOGE("new JobParameters returns nullptr");
1550 return params;
1551 }
1552 jobInfo.GetFdList(params->fdList);
1553 params->serviceJobId = jobInfo.GetJobId();
1554 params->numCopies = jobInfo.GetCopyNumber();
1555 params->duplex = GetDulpexString(jobInfo.GetDuplexMode());
1556 params->jobOriginatingUserName = DEFAULT_USER;
1557 params->mediaSize = GetMedieSize(jobInfo);
1558 params->color = GetColorString(jobInfo.GetColorMode());
1559 params->printerId = jobInfo.GetPrinterId();
1560 params->printerName = PrintUtil::StandardizePrinterName(optionJson["printerName"]);
1561 params->printerUri = optionJson["printerUri"];
1562 params->documentFormat = optionJson["documentFormat"];
1563 if (optionJson.contains("cupsOptions")) {
1564 params->printerAttrsOption_cupsOption = optionJson["cupsOptions"];
1565 }
1566 UpdateBorderlessJobParameter(optionJson, params);
1567 if (optionJson.contains("printQuality") && optionJson["printQuality"].is_string()) {
1568 params->printQuality = optionJson["printQuality"].get<std::string>();
1569 } else {
1570 params->printQuality = CUPS_PRINT_QUALITY_NORMAL;
1571 }
1572 params->jobName = optionJson.contains("jobName") ? optionJson["jobName"].get<std::string>() : DEFAULT_JOB_NAME;
1573 params->mediaType = optionJson.contains("mediaType") ?
1574 optionJson["mediaType"].get<std::string>() : CUPS_MEDIA_TYPE_PLAIN;
1575 params->serviceAbility = PrintServiceAbility::GetInstance();
1576 return params;
1577 }
1578
DumpJobParameters(JobParameters* jobParams)1579 void PrintCupsClient::DumpJobParameters(JobParameters* jobParams)
1580 {
1581 if (jobParams == nullptr) {
1582 return;
1583 }
1584 PRINT_HILOGD("jobParams->serviceJobId: %{public}s", jobParams->serviceJobId.c_str());
1585 PRINT_HILOGD("jobParams->borderless: %{public}d", jobParams->borderless);
1586 PRINT_HILOGD("jobParams->numCopies: %{public}d", jobParams->numCopies);
1587 PRINT_HILOGD("jobParams->duplex: %{public}s", jobParams->duplex.c_str());
1588 PRINT_HILOGD("jobParams->printQuality: %{public}s", jobParams->printQuality.c_str());
1589 PRINT_HILOGD("jobParams->jobName: %{public}s", jobParams->jobName.c_str());
1590 PRINT_HILOGD("jobParams->jobOriginatingUserName: %{public}s", jobParams->jobOriginatingUserName.c_str());
1591 PRINT_HILOGD("jobParams->printerId: %{private}s", jobParams->printerId.c_str());
1592 PRINT_HILOGD("jobParams->printerName: %{private}s", jobParams->printerName.c_str());
1593 PRINT_HILOGD("jobParams->printerUri: %{private}s", jobParams->printerUri.c_str());
1594 PRINT_HILOGD("jobParams->documentFormat: %{public}s", jobParams->documentFormat.c_str());
1595 PRINT_HILOGD("jobParams->mediaSize: %{public}s", jobParams->mediaSize.c_str());
1596 PRINT_HILOGD("jobParams->mediaType: %{public}s", jobParams->mediaType.c_str());
1597 PRINT_HILOGD("jobParams->color: %{public}s", jobParams->color.c_str());
1598 PRINT_HILOGD("jobParams->printerAttrsOption_cupsOption: %{public}s",
1599 jobParams->printerAttrsOption_cupsOption.c_str());
1600 }
1601
1602
GetMedieSize(const PrintJob &jobInfo)1603 std::string PrintCupsClient::GetMedieSize(const PrintJob &jobInfo)
1604 {
1605 PrintPageSize pageSize;
1606 jobInfo.GetPageSize(pageSize);
1607 return pageSize.GetName();
1608 }
1609
GetDulpexString(uint32_t duplexCode)1610 std::string PrintCupsClient::GetDulpexString(uint32_t duplexCode)
1611 {
1612 DuplexModeCode duplex = static_cast<DuplexModeCode>(duplexCode);
1613 switch (duplex) {
1614 case DUPLEX_MODE_ONE_SIDED:
1615 return CUPS_SIDES_ONE_SIDED;
1616 case DUPLEX_MODE_TWO_SIDED_LONG_EDGE:
1617 return CUPS_SIDES_TWO_SIDED_PORTRAIT;
1618 case DUPLEX_MODE_TWO_SIDED_SHORT_EDGE:
1619 return CUPS_SIDES_TWO_SIDED_LANDSCAPE;
1620 default:
1621 return CUPS_SIDES_ONE_SIDED;
1622 }
1623 }
1624
GetColorString(uint32_t colorCode)1625 std::string PrintCupsClient::GetColorString(uint32_t colorCode)
1626 {
1627 ColorModeCode color = static_cast<ColorModeCode>(colorCode);
1628 switch (color) {
1629 case COLOR_MODE_MONOCHROME:
1630 return CUPS_PRINT_COLOR_MODE_MONOCHROME;
1631 case COLOR_MODE_COLOR:
1632 return CUPS_PRINT_COLOR_MODE_COLOR;
1633 default:
1634 return CUPS_PRINT_COLOR_MODE_AUTO;
1635 }
1636 }
1637
IsCupsServerAlive()1638 bool PrintCupsClient::IsCupsServerAlive()
1639 {
1640 http_t *http;
1641 ippSetPort(CUPS_SEVER_PORT);
1642 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, NULL);
1643 if (http == nullptr) {
1644 PRINT_HILOGE("cups server is not alive");
1645 return false;
1646 }
1647 httpClose(http);
1648 return true;
1649 }
1650
1651 /**
1652 * @brief check printer is exist
1653 * @param printerName printer name
1654 * @return true printer exist
1655 * @return false printer is not exist
1656 */
IsPrinterExist(const char *printerUri, const char *printerName, const char *ppdName)1657 bool PrintCupsClient::IsPrinterExist(const char *printerUri, const char *printerName, const char *ppdName)
1658 {
1659 bool printerExist = false;
1660 cups_dest_t *dest;
1661 PRINT_HILOGD("IsPrinterExist enter");
1662 if (printAbility_ == nullptr) {
1663 PRINT_HILOGW("printAbility_ is null");
1664 return printerExist;
1665 }
1666 dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, printerName, NULL);
1667 if (dest != NULL) {
1668 const char *deviceUri = cupsGetOption("device-uri", dest->num_options, dest->options);
1669 PRINT_HILOGD("deviceUri=%{private}s", deviceUri);
1670 const char *makeModel = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
1671 PRINT_HILOGD("makeModel=%{private}s", makeModel);
1672 int printerState = cupsGetIntegerOption("printer-state", dest->num_options, dest->options);
1673 PRINT_HILOGD("printerState=%{private}d", printerState);
1674 if (printerState == IPP_PRINTER_STOPPED || makeModel == nullptr || strcmp(deviceUri, printerUri) != 0) {
1675 printAbility_->FreeDests(1, dest);
1676 PRINT_HILOGI("Printer information needs to be modified");
1677 return printerExist;
1678 }
1679 if (strcmp(ppdName, DEFAULT_PPD_NAME.c_str()) == 0) {
1680 // 查到everywhere或remote printer驱动
1681 printerExist = (strstr(makeModel, DEFAULT_MAKE_MODEL.c_str()) != NULL) ||
1682 (strstr(makeModel, REMOTE_PRINTER_MAKE_MODEL.c_str()) != NULL);
1683 } else {
1684 // 查到驱动
1685 printerExist = !(strstr(makeModel, DEFAULT_MAKE_MODEL.c_str()) != NULL);
1686 if (!printerExist) {
1687 // 私有驱动已卸载,需要先删除打印机再添加,不然下发任务找不到驱动
1688 DeleteCupsPrinter(printerName);
1689 }
1690 }
1691 printAbility_->FreeDests(1, dest);
1692 }
1693 return printerExist;
1694 }
1695
ConvertInchTo100MM(float num)1696 float PrintCupsClient::ConvertInchTo100MM(float num)
1697 {
1698 return ((num / THOUSAND_INCH) * CONVERSION_UNIT);
1699 }
1700
IsIpConflict(const std::string &printerId, std::string &nic)1701 bool PrintCupsClient::IsIpConflict(const std::string &printerId, std::string &nic) __attribute__((no_sanitize("cfi")))
1702 {
1703 if (printerId.find(P2P_PRINTER) == std::string::npos) {
1704 PRINT_HILOGD("The printer is not p2p: %{private}s", printerId.c_str());
1705 return false;
1706 }
1707 bool isWifiConnected = false;
1708 auto wifiDevice = Wifi::WifiDevice::GetInstance(OHOS::WIFI_DEVICE_SYS_ABILITY_ID);
1709 if (!wifiDevice) {
1710 PRINT_HILOGE("wifiDevice GetInstance failed.");
1711 return false;
1712 }
1713 wifiDevice->IsConnected(isWifiConnected);
1714 PRINT_HILOGD("isWifiConnected: %{public}d", isWifiConnected);
1715 Wifi::WifiP2pLinkedInfo p2pLinkedInfo;
1716 Wifi::WifiP2p::GetInstance(OHOS::WIFI_P2P_SYS_ABILITY_ID)->QueryP2pLinkedInfo(p2pLinkedInfo);
1717 PRINT_HILOGD("P2pConnectedState: %{public}d", p2pLinkedInfo.GetConnectState());
1718 if (isWifiConnected && p2pLinkedInfo.GetConnectState() == Wifi::P2pConnectedState::P2P_CONNECTED) {
1719 Wifi::IpInfo info;
1720 auto wifiDevice = Wifi::WifiDevice::GetInstance(OHOS::WIFI_DEVICE_SYS_ABILITY_ID);
1721 if (!wifiDevice) {
1722 PRINT_HILOGE("wifiDevice GetInstance failed.");
1723 return false;
1724 }
1725 wifiDevice->GetIpInfo(info);
1726 PRINT_HILOGD("wifi server ip: %{private}s", GetIpAddress(info.serverIp).c_str());
1727 PRINT_HILOGD("p2p go ip: %{private}s", p2pLinkedInfo.GetGroupOwnerAddress().c_str());
1728 if (GetIpAddress(info.serverIp) == p2pLinkedInfo.GetGroupOwnerAddress()) {
1729 Wifi::WifiP2pGroupInfo group;
1730 Wifi::WifiP2p::GetInstance(OHOS::WIFI_P2P_SYS_ABILITY_ID)->GetCurrentGroup(group);
1731 nic = group.GetInterface();
1732 PRINT_HILOGI("The P2P ip conflicts with the wlan ip, p2p nic: %{public}s", nic.c_str());
1733 return true;
1734 }
1735 }
1736 return false;
1737 }
1738
GetIpAddress(unsigned int number)1739 std::string PrintCupsClient::GetIpAddress(unsigned int number)
1740 {
1741 unsigned int ip3 = (number << IP_RIGHT_SHIFT_0) >> IP_RIGHT_SHIFT_24;
1742 unsigned int ip2 = (number << IP_RIGHT_SHIFT_8) >> IP_RIGHT_SHIFT_24;
1743 unsigned int ip1 = (number << IP_RIGHT_SHIFT_16) >> IP_RIGHT_SHIFT_24;
1744 unsigned int ip0 = (number << IP_RIGHT_SHIFT_24) >> IP_RIGHT_SHIFT_24;
1745 return std::to_string(ip3) + "." + std::to_string(ip2) + "." + std::to_string(ip1) + "." + std::to_string(ip0);
1746 }
1747
DiscoverUsbPrinters(std::vector<PrinterInfo> &printers)1748 int32_t PrintCupsClient::DiscoverUsbPrinters(std::vector<PrinterInfo> &printers)
1749 {
1750 int longStatus = 0;
1751 const char* include_schemes = CUPS_INCLUDE_ALL;
1752 const char* exclude_schemes = CUPS_EXCLUDE_NONE;
1753 int timeout = CUPS_TIMEOUT_DEFAULT;
1754 PRINT_HILOGD("DiscoverUsbPrinters cupsGetDevices");
1755 usbPrinters.clear();
1756 if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes, exclude_schemes,
1757 DeviceCb, &longStatus) != IPP_OK) {
1758 PRINT_HILOGE("lpinfo error : %{public}s", cupsLastErrorString());
1759 return E_PRINT_SERVER_FAILURE;
1760 }
1761 printers = usbPrinters;
1762 return E_PRINT_NONE;
1763 }
1764 }