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