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 }