• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
24 #include <semaphore.h>
25 #include <csignal>
26 #include <cstdlib>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <wifi_device.h>
31 #include <wifi_p2p.h>
32 #include <wifi_p2p_msg.h>
33 #include <arpa/inet.h>
34 #include <fstream>
35 #include <sstream>
36 #include <iomanip>
37 
38 #include "system_ability_definition.h"
39 #include "parameter.h"
40 #include <json/json.h>
41 #include "print_service_ability.h"
42 #include "print_log.h"
43 #include "print_constant.h"
44 #include "print_utils.h"
45 #include "print_service_converter.h"
46 #include "print_cups_attribute.h"
47 #include "print_cups_ppd.h"
48 
49 namespace OHOS::Print {
50 using namespace std;
51 
52 const uint32_t THOUSAND_INCH = 1000;
53 const uint32_t CUPS_SEVER_PORT = 1631;
54 const uint32_t TIME_OUT = 2000;
55 const uint32_t CONVERSION_UNIT = 2540;
56 const uint32_t LONG_TIME_OUT = 3000;
57 const uint32_t LONG_LONG_TIME_OUT = 30000;
58 const uint32_t RESOURCE_COUNT = 2;
59 const uint32_t DIR_COUNT = 3;
60 const uint32_t INDEX_ZERO = 0;
61 const uint32_t INDEX_ONE = 1;
62 const uint32_t INDEX_TWO = 2;
63 const uint32_t INDEX_THREE = 3;
64 const uint32_t MAX_RETRY_TIMES = 5;
65 const uint32_t BUFFER_LEN = 256;
66 const uint32_t DIR_MODE = 0771;
67 const uint32_t IP_RIGHT_SHIFT_0 = 0;
68 const uint32_t IP_RIGHT_SHIFT_8 = 8;
69 const uint32_t IP_RIGHT_SHIFT_16 = 16;
70 const uint32_t IP_RIGHT_SHIFT_24 = 24;
71 const uint32_t NUMBER_FOR_SPLICING_SUBSTATE = 100;
72 const uint32_t SERIAL_LENGTH = 6;
73 const uint32_t CUPSD_CONTROL_PARAM_SIZE = 96;
74 const uint32_t FREE_ONE_PRINTER = 1;
75 const uint32_t DEFAULT_BUFFER_SIZE_8K = 8192;
76 const uint32_t DEFAULT_BUFFER_SIZE_4K = 4096;
77 const uint32_t ISO_A4_WIDTH = 8268;
78 const uint32_t ISO_A4_HEIGHT = 11692;
79 const uint32_t PHOTO_5R_WIDTH = 5000;
80 const uint32_t PHOTO_5R_HEIGHT = 7000;
81 const uint32_t PHOTO_4R_WIDTH = 4000;
82 const uint32_t PHOTO_4R_HEIGHT = 6000;
83 const uint32_t MONITOR_STEP_TIME_MS = 2000;
84 const int32_t STATE_UPDATE_STEP = 5;
85 
86 static const std::string CUPS_ROOT_DIR = "/data/service/el1/public/print_service/cups";
87 static const std::string DEFAULT_MAKE_MODEL = "IPP Everywhere";
88 static const std::string REMOTE_PRINTER_MAKE_MODEL = "Remote Printer";
89 static const std::string LOCAL_RAW_PRINTER_PPD_NAME = "Local Raw Printer";
90 static const std::string PRINTER_STATE_WAITING_COMPLETE = "cups-waiting-for-job-completed";
91 static const std::string PRINTER_STATE_WIFI_NOT_CONFIGURED = "wifi-not-configured-report";
92 static const std::string PRINTER_STATE_MEDIA_LOW_WARNING = "media-low-warning";
93 static const std::string PRINTER_STATE_TONER_LOW_WARNING = "toner-low-warning";
94 static const std::string PRINTER_STATE_TONER_LOW_REPORT = "toner-low-report";
95 static const std::string PRINTER_STATE_IGNORE_HP = "wifi-not-configured-report,cups-waiting-for-job-completed";
96 static const std::string PRINTER_STATE_IGNORE_BUSY =
97     "cups-ipp-conformance-failure-report,cups-ipp-missing-job-history,cups-waiting-for-job-completed";
98 static const std::string PRINTER_STATE_IGNORE_BUSY_COMPLETED =
99     "cups-ipp-conformance-failure-report,cups-ipp-missing-job-history";
100 static const std::string PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE =
101     "cups-ipp-conformance-failure-report,cups-ipp-missing-job-state";
102 static const std::string PRINTER_STATE_IGNORE_BUSY_MISSING_JOB_STATE_COMPLETED =
103     "cups-ipp-conformance-failure-report,cups-ipp-missing-job-state,cups-waiting-for-job-completed";
104 static const std::string PRINTER_STATE_IGNORE_TONER_LOW_JOB_STATE_COMPLETED =
105     "toner-low-warning,cups-waiting-for-job-completed";
106 static const std::string PRINTER_STATE_IGNORE_MEDIA_LOW_JOB_STATE_COMPLETED =
107     "media-low-warning,cups-waiting-for-job-completed";
108 static const std::string PRINTER_STATE_IGNORE_BUSY_WAITING_COMPLETE_OTHER_REPORT =
109     "cups-waiting-for-job-completed,other-report";
110 static const std::string PRINTER_STATE_IGNORE_BUSY_OTHER_REPORT = "other-report";
111 static const std::string PRINTER_STATE_MARKER_LOW_WARNING = "marker-supply-low-warning";
112 static const std::string PRINTER_STATE_MEDIA_EMPTY_WARNING = "media-empty-warning";
113 static const std::string PRINTER_STATE_NONE = "none";
114 static const std::string PRINTER_STATE_EMPTY = "";
115 static const std::string PRINTER_STATE_ERROR = "-error";
116 static const std::string PRINTER_STATE_WARNING = "-warning";
117 static const std::string PRINTER_STATE_REPORT = "-report";
118 static const std::string PRINTER_STATE_MEDIA_EMPTY = "media-empty";
119 static const std::string PRINTER_STATE_MEDIA_JAM = "media-jam";
120 static const std::string PRINTER_STATE_PAUSED = "paused";
121 static const std::string PRINTER_STATE_TONER_LOW = "toner-low";
122 static const std::string PRINTER_STATE_TONER_EMPTY = "toner-empty";
123 static const std::string PRINTER_STATE_DOOR_EMPTY = "door-open";
124 static const std::string PRINTER_STATE_MEDIA_NEEDED = "media-needed";
125 static const std::string PRINTER_STATE_MARKER_LOW = "marker-supply-low";
126 static const std::string PRINTER_STATE_MARKER_EMPTY = "marker-supply-empty";
127 static const std::string PRINTER_STATE_INK_EMPTY = "marker-ink-almost-empty";
128 static const std::string PRINTER_STATE_COVER_OPEN = "cover-open";
129 static const std::string PRINTER_STATE_OTHER = "other";
130 static const std::string PRINTER_STATE_OFFLINE = "offline";
131 static const std::string PRINTER_STATE_TIMED_OUT = "timed-out";
132 static const std::string PRINTER_SPOOL_AREA_FULL = "spool-area-full";
133 static const std::string JOB_STATE_REASON_PRINTER_STOP = "printer-stopped";
134 static const std::string DEFAULT_JOB_NAME = "test";
135 static const std::string CUPSD_CONTROL_PARAM = "print.cupsd.ready";
136 static const std::string USB_PRINTER = "usb";
137 static const std::string SERIAL = "serial=";
138 static const std::string PRINTER_ID_USB_PREFIX = "USB";
139 static const std::string PRINTER_MAKE_UNKNOWN = "Unknown";
140 static const std::string SPOOLER_BUNDLE_NAME = "com.ohos.spooler";
141 static const std::string VENDOR_MANAGER_PREFIX = "fwk.";
142 static const std::string DEFAULT_POLICY = "default";
143 #ifdef ENTERPRISE_ENABLE
144 static const std::string CUPS_ENTERPRISE_ROOT_DIR = "/data/service/el1/public/print_service/cups_enterprise";
145 static const std::string CUPSD_ENTERPRISE_CONTROL_PARAM = "print.cupsd_enterprise.ready";
146 #endif // ENTERPRISE_ENABLE
147 
148 static const std::map<std::string, PrintJobSubState> FOLLOW_STATE_LIST {
149     { PRINTER_STATE_MEDIA_EMPTY,    PRINT_JOB_BLOCKED_OUT_OF_PAPER },
150     { PRINTER_STATE_MEDIA_NEEDED,   PRINT_JOB_BLOCKED_OUT_OF_PAPER },
151     { PRINTER_STATE_MEDIA_JAM,      PRINT_JOB_BLOCKED_JAMMED },
152     { PRINTER_STATE_TONER_EMPTY,    PRINT_JOB_BLOCKED_OUT_OF_TONER },
153     { PRINTER_STATE_TONER_LOW,      PRINT_JOB_BLOCKED_LOW_ON_TONER },
154     { PRINTER_STATE_MARKER_EMPTY,   PRINT_JOB_BLOCKED_OUT_OF_INK },
155     { PRINTER_STATE_INK_EMPTY,      PRINT_JOB_BLOCKED_OUT_OF_INK },
156     { PRINTER_STATE_DOOR_EMPTY,     PRINT_JOB_BLOCKED_DOOR_OPEN },
157     { PRINTER_STATE_COVER_OPEN,     PRINT_JOB_BLOCKED_DOOR_OPEN },
158     { PRINTER_STATE_OTHER,          PRINT_JOB_BLOCKED_UNKNOWN },
159     { PRINTER_STATE_TIMED_OUT,      PRINT_JOB_BLOCKED_UNKNOWN },
160     { PRINTER_SPOOL_AREA_FULL,      PRINT_JOB_BLOCKED_UNKNOWN },
161 };
162 
163 static const std::map<std::string, map<std::string, StatePolicy>> SPECIAL_PRINTER_POLICY {
164     { "default", {{PRINTER_STATE_MEDIA_EMPTY,   STATE_POLICY_BLOCK},
165                   {PRINTER_STATE_MEDIA_JAM,     STATE_POLICY_BLOCK}} },
166 };
167 
168 std::mutex jobMutex;
169 
GetUsbPrinterSerial(const std::string & deviceUri)170 std::string GetUsbPrinterSerial(const std::string &deviceUri)
171 {
172     auto pos = deviceUri.find(SERIAL);
173     if (pos == std::string::npos || pos + SERIAL.length() >= deviceUri.length()) {
174         return "";
175     }
176     std::string serial = deviceUri.substr(pos + SERIAL.length());
177     pos = serial.find("&");
178     if (pos != std::string::npos) {
179         serial = serial.substr(0, pos);
180     }
181     if (serial.length() > SERIAL_LENGTH) {
182         serial = serial.substr(serial.length() - SERIAL_LENGTH);
183     }
184     return serial;
185 }
186 
187 static std::mutex g_usbPrintersLock;
188 static std::vector<PrinterInfo> g_usbPrinters;
GetUsbPrinters()189 std::vector<PrinterInfo>& GetUsbPrinters()
190 {
191     std::lock_guard<std::mutex> lock(g_usbPrintersLock);
192     return g_usbPrinters;
193 }
AddUsbPrinter(PrinterInfo & info)194 void AddUsbPrinter(PrinterInfo &info)
195 {
196     std::lock_guard<std::mutex> lock(g_usbPrintersLock);
197     g_usbPrinters.emplace_back(info);
198 }
ClearUsbPrinters()199 void ClearUsbPrinters()
200 {
201     std::lock_guard<std::mutex> lock(g_usbPrintersLock);
202     g_usbPrinters.clear();
203 }
204 
205 static std::mutex g_backendPrintersLock;
206 static std::vector<PrinterInfo> g_backendPrinters;
GetBackendPrinters()207 std::vector<PrinterInfo>& GetBackendPrinters()
208 {
209     std::lock_guard<std::mutex> lock(g_backendPrintersLock);
210     return g_backendPrinters;
211 }
AddVendorPrinter(PrinterInfo & info)212 void AddVendorPrinter(PrinterInfo &info)
213 {
214     std::lock_guard<std::mutex> lock(g_backendPrintersLock);
215     g_backendPrinters.emplace_back(info);
216 }
ClearBackendPrinters()217 void ClearBackendPrinters()
218 {
219     std::lock_guard<std::mutex> lock(g_backendPrintersLock);
220     g_backendPrinters.clear();
221 }
222 
ParseDeviceInfo(const char * deviceLocation,Json::Value & infoOps)223 static void ParseDeviceInfo(const char *deviceLocation, Json::Value &infoOps)
224 {
225     if (deviceLocation == nullptr) {
226         PRINT_HILOGW("deviceLocation is nullptr");
227         return;
228     }
229     PRINT_HILOGI("location = %{private}s\n", deviceLocation);
230     std::string location(deviceLocation);
231     auto pos = location.find("-");
232     if (pos == std::string::npos || pos + 1 >= location.length()) {
233         PRINT_HILOGE("can not find vid and pid");
234         return;
235     }
236     std::string vidStr = location.substr(0, pos);
237     std::string pidStr = location.substr(pos + 1);
238     std::stringstream ssVid(vidStr);
239     int vid = 0;
240     ssVid >> std::hex >> vid;
241     std::stringstream ssPid(pidStr);
242     int pid = 0;
243     ssPid >> std::hex >> pid;
244     PRINT_HILOGI("vid = %{private}d, pid = %{private}d", vid, pid);
245     infoOps["vendorId"] = vid;
246     infoOps["productId"] = pid;
247 }
248 
DeviceCb(const char * deviceClass,const char * deviceId,const char * deviceInfo,const char * deviceMakeAndModel,const char * deviceUri,const char * deviceLocation,void * userData)249 void DeviceCb(const char *deviceClass, const char *deviceId, const char *deviceInfo,
250     const char *deviceMakeAndModel, const char *deviceUri, const char *deviceLocation, void *userData)
251 {
252     if  (deviceClass == nullptr || deviceId == nullptr || deviceInfo == nullptr || deviceMakeAndModel == nullptr ||
253         deviceUri == nullptr) {
254         PRINT_HILOGW("null params");
255         return;
256     }
257     PRINT_HILOGD("Device: uri = %{private}s\n", deviceUri);
258     PRINT_HILOGD("class = %{private}s\n", deviceClass);
259     PRINT_HILOGD("make-and-model = %{private}s\n", deviceMakeAndModel);
260     std::string printerUri(deviceUri);
261     std::string printerMake(deviceMakeAndModel);
262     if (printerUri.length() > SERIAL_LENGTH && printerMake != PRINTER_MAKE_UNKNOWN) {
263         std::string id(deviceInfo);
264         std::string serial = GetUsbPrinterSerial(printerUri);
265         PRINT_HILOGD("serial = %{private}s\n", serial.c_str());
266         bool isUsbBackend = printerUri.substr(INDEX_ZERO, INDEX_THREE) == USB_PRINTER;
267         if (isUsbBackend) {
268             id = PRINTER_ID_USB_PREFIX + "-" + id;
269         }
270         if (!serial.empty()) {
271             id += "-" + serial;
272         }
273         PrinterInfo info;
274         info.SetPrinterId(id);
275         info.SetPrinterName(id);
276         info.SetPrinterMake(printerMake);
277         info.SetUri(printerUri);
278         info.SetPrinterState(PRINTER_ADDED);
279         PrinterCapability printerCapability;
280         info.SetCapability(printerCapability);
281         Json::Value infoOps;
282         infoOps["printerUri"] = printerUri;
283         infoOps["make"] = printerMake;
284         ParseDeviceInfo(deviceLocation, infoOps);
285         info.SetOption(PrintJsonUtil::WriteString(infoOps));
286         if (isUsbBackend) {
287             info.SetDescription("usb");
288             AddUsbPrinter(info);
289         } else {
290             info.SetDescription("vendor");
291             AddVendorPrinter(info);
292         }
293     } else {
294         PRINT_HILOGW("verify uri or make failed");
295     }
296 }
297 
StandardizePrinterUri(const std::string & printerUri,const std::string & ppdName)298 std::string StandardizePrinterUri(const std::string &printerUri, const std::string &ppdName)
299 {
300     if (ppdName != BSUNI_PPD_NAME) {
301         return printerUri;
302     }
303     auto pos = printerUri.find("://");
304     if (pos == std::string::npos) {
305         return printerUri;
306     }
307     return "bsUniBackend" + printerUri.substr(pos);
308 }
309 
PrintCupsClient()310 PrintCupsClient::PrintCupsClient()
311 {
312     printAbility_ = new (std::nothrow) PrintCupsWrapper();
313 }
314 
~PrintCupsClient()315 PrintCupsClient::~PrintCupsClient()
316 {
317     if (printAbility_ != nullptr) {
318         delete printAbility_;
319         printAbility_ = nullptr;
320     }
321     for (auto jobItem : jobQueue_) {
322         if (jobItem != nullptr) {
323             delete jobItem;
324             jobItem = nullptr;
325         }
326     }
327     if (currentJob_ != nullptr) {
328         delete currentJob_;
329         currentJob_ = nullptr;
330     }
331     jobMonitorList_.clear();
332 }
333 
334 
StartCupsdServiceNotAlive()335 int32_t PrintCupsClient::StartCupsdServiceNotAlive()
336 {
337     PRINT_HILOGI("The cupsd process is not started, start it now.");
338     std::string param = GetCurCupsdControlParam();
339     int result = SetParameter(param.c_str(), "true");
340     if (result) {
341         PRINT_HILOGD("SetParameter failed: %{public}d.", result);
342         return E_PRINT_SERVER_FAILURE;
343     }
344     char value[CUPSD_CONTROL_PARAM_SIZE] = {0};
345     GetParameter(param.c_str(), "", value, CUPSD_CONTROL_PARAM_SIZE - 1);
346     PRINT_HILOGD("%{public}s value: %{public}s.", param.c_str(), value);
347     return E_PRINT_NONE;
348 }
349 
StartCupsdService()350 int32_t PrintCupsClient::StartCupsdService()
351 {
352     PRINT_HILOGD("StartCupsdService enter");
353     if (!IsCupsServerAlive()) {
354         return StartCupsdServiceNotAlive();
355     }
356     std::string pidFile = GetCurCupsRootDir() + "/run/cupsd.pid";
357     struct stat sb;
358     if (stat(pidFile.c_str(), &sb) != 0) {
359         PRINT_HILOGI("stat pidFile failed.");
360         return E_PRINT_SERVER_FAILURE;
361     }
362     char realPidFile[PATH_MAX] = {};
363     if (realpath(pidFile.c_str(), realPidFile) == nullptr) {
364         PRINT_HILOGE("The realPidFile is null, errno:%{public}s", std::to_string(errno).c_str());
365         return E_PRINT_SERVER_FAILURE;
366     }
367     if (access(realPidFile, F_OK) != 0) {
368         PRINT_HILOGE("realPidFile is not exist");
369         return E_PRINT_SERVER_FAILURE;
370     }
371     FILE *file = fopen(realPidFile, "r");
372     if (file == nullptr) {
373         PRINT_HILOGE("Open pidFile error!");
374         return E_PRINT_SERVER_FAILURE;
375     }
376     if (fseek(file, 0, SEEK_SET) != 0) {
377         PRINT_HILOGE("Seek pidFile!");
378         int fcloseResult = fclose(file);
379         if (fcloseResult != 0) {
380             PRINT_HILOGE("Close File Failure.");
381         }
382         return E_PRINT_SERVER_FAILURE;
383     }
384     char buf[BUFFER_LEN] = {0};
385     if ((fread(buf, 1, BUFFER_LEN, file)) < 0) {
386         PRINT_HILOGE("Read pidFile error!");
387         int fcloseResult = fclose(file);
388         if (fcloseResult != 0) {
389             PRINT_HILOGE("Close File Failure.");
390         }
391         return E_PRINT_SERVER_FAILURE;
392     }
393     int fcloseResult = fclose(file);
394     if (fcloseResult != 0) {
395         PRINT_HILOGE("Close File Failure.");
396         return E_PRINT_SERVER_FAILURE;
397     }
398     PRINT_HILOGD("The Process of CUPSD has existed, pid: %{public}s.", buf);
399     return E_PRINT_NONE;
400 }
401 
ChangeFilterPermission(const std::string & path,mode_t mode)402 bool PrintCupsClient::ChangeFilterPermission(const std::string &path, mode_t mode)
403 {
404     if (path.empty() || access(path.c_str(), F_OK) != 0) {
405         PRINT_HILOGE("File is not exist");
406         return false;
407     }
408     DIR *dir = opendir(path.c_str());
409     if (dir == nullptr) {
410         PRINT_HILOGE("Failed to open Dir: %{private}s", path.c_str());
411         return false;
412     }
413     struct dirent *entry;
414     while ((entry = readdir(dir)) != nullptr) {
415         std::string fileName = entry->d_name;
416         if (fileName == "." || fileName == "..") {
417             continue;
418         }
419         std::string filePath = path + "/" + fileName;
420         struct stat fileStat;
421         if (stat(filePath.c_str(), &fileStat) != 0) {
422             continue;
423         }
424         if (S_ISDIR(fileStat.st_mode)) {
425             ChangeFilterPermission(filePath.c_str(), mode);
426         } else if (S_ISREG(fileStat.st_mode)) {
427             if (chmod(filePath.c_str(), mode) == -1) {
428                 PRINT_HILOGE("Failed to change mode");
429             }
430         }
431     }
432     closedir(dir);
433     return true;
434 }
435 
SymlinkFile(std::string & srcFilePath,std::string & destFilePath)436 void PrintCupsClient::SymlinkFile(std::string &srcFilePath, std::string &destFilePath)
437 {
438     int ret = symlink(srcFilePath.c_str(), destFilePath.c_str());
439     if (!ret) {
440         PRINT_HILOGD("symlink success, ret = %{public}d, errno = %{public}d", ret, errno);
441     } else {
442         PRINT_HILOGE("symlink failed, ret = %{public}d, errno = %{public}d", ret, errno);
443     }
444 }
445 
SymlinkDirectory(const char * srcDir,const char * destDir)446 void PrintCupsClient::SymlinkDirectory(const char *srcDir, const char *destDir)
447 {
448     DIR *dir = opendir(srcDir);
449     if (dir == nullptr) {
450         PRINT_HILOGE("Failed to open Dir: %{private}s", srcDir);
451         return;
452     }
453     if (access(destDir, F_OK)) {
454         mkdir(destDir, DIR_MODE);
455     } else {
456         PRINT_HILOGW("check directory failed");
457     }
458     struct dirent *file;
459     struct stat filestat = {};
460     struct stat destFilestat = {};
461     while ((file = readdir(dir)) != nullptr) {
462         if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
463             continue;
464         }
465         std::string srcFilePath = std::string(srcDir) + "/" + std::string(file->d_name);
466         std::string destFilePath = std::string(destDir) + "/" + std::string(file->d_name);
467 
468         stat(srcFilePath.c_str(), &filestat);
469         if (S_ISDIR(filestat.st_mode)) {
470             SymlinkDirectory(srcFilePath.c_str(), destFilePath.c_str());
471         } else if (lstat(destFilePath.c_str(), &destFilestat) == 0) {
472             PRINT_HILOGD("symlink lstat %{public}s err: %{public}s", destFilePath.c_str(), strerror(errno));
473 
474             if (S_ISLNK(destFilestat.st_mode)) {
475                 PRINT_HILOGW("symlink already exists, continue.");
476                 continue;
477             }
478             if (std::remove(destFilePath.c_str()) != 0) {
479                 PRINT_HILOGE("error deleting file %{public}s err: %{public}s",
480                     destFilePath.c_str(), strerror(errno));
481                 continue;
482             } else {
483                 PRINT_HILOGW("file successfully deleted");
484             }
485             SymlinkFile(srcFilePath, destFilePath);
486         } else {
487             PRINT_HILOGE("symlink lstat %{public}s err: %{public}s", destFilePath.c_str(), strerror(errno));
488             SymlinkFile(srcFilePath, destFilePath);
489         }
490     }
491     closedir(dir);
492 }
493 
CopyDirectory(const char * srcDir,const char * destDir)494 void PrintCupsClient::CopyDirectory(const char *srcDir, const char *destDir)
495 {
496     DIR *dir = opendir(srcDir);
497     if (dir == nullptr) {
498         PRINT_HILOGE("Failed to open Dir: %{private}s", srcDir);
499         return;
500     }
501     if (access(destDir, F_OK) != 0) {
502         mkdir(destDir, DIR_MODE);
503     }
504     struct dirent *file;
505     struct stat filestat;
506     while ((file = readdir(dir)) != nullptr) {
507         if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0) {
508             continue;
509         }
510         std::string srcFilePath = std::string(srcDir) + "/" + std::string(file->d_name);
511         std::string destFilePath = std::string(destDir) + "/" + std::string(file->d_name);
512 
513         stat(srcFilePath.c_str(), &filestat);
514         if (S_ISDIR(filestat.st_mode)) {
515             CopyDirectory(srcFilePath.c_str(), destFilePath.c_str());
516             chmod(destFilePath.c_str(), filestat.st_mode);
517         } else {
518             char realSrc[PATH_MAX] = {};
519             char destSrc[PATH_MAX] = {};
520             if (realpath(srcFilePath.c_str(), realSrc) == nullptr ||
521                 realpath(destDir, destSrc) == nullptr) {
522                 PRINT_HILOGE("The realSrc is null, errno:%{public}s", std::to_string(errno).c_str());
523                 continue;
524             }
525             FILE *srcFile = fopen(realSrc, "rb");
526             if (srcFile == nullptr) {
527                 continue;
528             }
529             FILE *destFile = fopen(destFilePath.c_str(), "wb");
530             if (destFile == nullptr) {
531                 fclose(srcFile);
532                 continue;
533             }
534             char buffer[DEFAULT_BUFFER_SIZE_4K];
535             size_t bytesRead;
536             while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
537                 fwrite(buffer, 1, bytesRead, destFile);
538             }
539             fclose(srcFile);
540             fclose(destFile);
541             chmod(destFilePath.c_str(), filestat.st_mode);
542         }
543     }
544     closedir(dir);
545 }
546 
GetCurCupsRootDir()547 const std::string& PrintCupsClient::GetCurCupsRootDir()
548 {
549 #ifdef ENTERPRISE_ENABLE
550     if (PrintServiceAbility::GetInstance()->IsEnterpriseEnable() &&
551         PrintServiceAbility::GetInstance()->IsEnterprise()) {
552         return CUPS_ENTERPRISE_ROOT_DIR;
553     }
554 #endif // ENTERPRISE_ENABLE
555     return CUPS_ROOT_DIR;
556 }
557 
GetCurCupsdControlParam()558 const std::string& PrintCupsClient::GetCurCupsdControlParam()
559 {
560 #ifdef ENTERPRISE_ENABLE
561     if (PrintServiceAbility::GetInstance()->IsEnterpriseEnable() &&
562         PrintServiceAbility::GetInstance()->IsEnterprise()) {
563         return CUPSD_ENTERPRISE_CONTROL_PARAM;
564     }
565 #endif // ENTERPRISE_ENABLE
566     return CUPSD_CONTROL_PARAM;
567 }
568 
InitCupsResources()569 int32_t PrintCupsClient::InitCupsResources()
570 {
571     std::string curDir = GetCurCupsRootDir();
572     string array[RESOURCE_COUNT][DIR_COUNT] = {
573         {"/system/bin/cups/", curDir + "/serverbin", curDir + "/serverbin/daemon"},
574         {"/system/etc/cups/share/", curDir + "/datadir", curDir + "/datadir/mime"}
575     };
576     for (uint32_t i = 0; i < RESOURCE_COUNT; i++) {
577         if (!i) {
578             SymlinkDirectory(array[i][INDEX_ZERO].c_str(), array[i][INDEX_ONE].c_str());
579         } else {
580             CopyDirectory(array[i][INDEX_ZERO].c_str(), array[i][INDEX_ONE].c_str());
581         }
582     }
583     const std::string driverDir = "/system/bin/uni_print_driver";
584     std::string srcDir = driverDir + "/filter";
585     std::string dstDir = curDir + "/serverbin/filter";
586     SymlinkDirectory(srcDir.c_str(), dstDir.c_str());
587     srcDir = driverDir + "/backend";
588     dstDir = curDir + "/serverbin/backend";
589     SymlinkDirectory(srcDir.c_str(), dstDir.c_str());
590     srcDir = "/system/bin/cups/backend/ipp";
591     dstDir = curDir + "/serverbin/backend/http";
592     SymlinkFile(srcDir, dstDir);
593     dstDir = curDir + "/serverbin/backend/ipps";
594     SymlinkFile(srcDir, dstDir);
595     return StartCupsdService();
596 }
597 
StopCupsdService()598 void PrintCupsClient::StopCupsdService()
599 {
600     PRINT_HILOGD("StopCupsdService enter");
601     if (!IsCupsServerAlive()) {
602         PRINT_HILOGI("The cupsd process is not started, no need stop.");
603         return;
604     }
605     PRINT_HILOGI("The cupsd process is started, stop it now.");
606     int result = SetParameter(CUPSD_CONTROL_PARAM.c_str(), "false");
607     if (result) {
608         PRINT_HILOGD("SetParameter failed: %{public}d.", result);
609         return;
610     }
611     const int bufferSize = 96;
612     char value[bufferSize] = {0};
613     GetParameter(CUPSD_CONTROL_PARAM.c_str(), "", value, bufferSize - 1);
614     PRINT_HILOGD("print.cupsd.ready value: %{public}s.", value);
615 }
616 
617 #ifdef ENTERPRISE_ENABLE
StopCupsdEnterpriseService()618 void PrintCupsClient::StopCupsdEnterpriseService()
619 {
620     PRINT_HILOGD("StopCupsdEnterpriseService enter");
621     if (!IsCupsServerAlive()) {
622         PRINT_HILOGI("The cupsd process is not started, no need stop.");
623         return;
624     }
625 
626     PRINT_HILOGI("The cupsd_enterprise process is started, stop it now.");
627     int result = SetParameter(CUPSD_ENTERPRISE_CONTROL_PARAM.c_str(), "false");
628     if (result) {
629         PRINT_HILOGD("SetParameter failed: %{public}d.", result);
630         return;
631     }
632     const int bufferSize = 96;
633     char enterprise_value[bufferSize] = {0};
634     GetParameter(CUPSD_ENTERPRISE_CONTROL_PARAM.c_str(), "", enterprise_value, bufferSize - 1);
635     PRINT_HILOGD("print.cupsd_enterprise.ready value: %{public}s.", enterprise_value);
636 }
637 #endif // ENTERPRISE_ENABLE
638 
QueryPPDInformation(const std::string & makeModel,std::string & ppdName)639 bool PrintCupsClient::QueryPPDInformation(const std::string &makeModel, std::string &ppdName)
640 {
641     ipp_t *request = nullptr;
642     ipp_t *response = nullptr;
643 
644     if (printAbility_ == nullptr) {
645         PRINT_HILOGW("printAbility_ is null");
646         return false;
647     }
648     request = ippNewRequest(CUPS_GET_PPDS);
649     if (request == nullptr) {
650         return false;
651     }
652     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model", nullptr, makeModel.c_str());
653 
654     PRINT_HILOGD("CUPS_GET_PPDS start.");
655     response = printAbility_->DoRequest(CUPS_HTTP_DEFAULT, request, "/");
656     if (response == nullptr) {
657         PRINT_HILOGE("GetAvaiablePPDS failed: %{public}s", cupsLastErrorString());
658         return false;
659     }
660     if (response->request.status.status_code > IPP_OK_CONFLICT) {
661         PRINT_HILOGE("GetAvaiablePPDS failed: %{public}s", cupsLastErrorString());
662         printAbility_->FreeRequest(response);
663         return false;
664     }
665     std::vector<std::string> ppds;
666     ParsePPDInfo(response, ppds);
667     printAbility_->FreeRequest(response);
668     if (ppds.empty()) {
669         PRINT_HILOGI("cannot find any matched ppds");
670         return false;
671     }
672     ppdName = ppds[0];
673     return true;
674 }
675 
ParsePPDInfo(ipp_t * response,std::vector<std::string> & ppds)676 void PrintCupsClient::ParsePPDInfo(ipp_t *response, std::vector<std::string> &ppds)
677 {
678     if (response == nullptr) {
679         PRINT_HILOGE("ParsePPDInfo response is nullptr");
680         return;
681     }
682     for (ipp_attribute_t *attr = response->attrs; attr != nullptr; attr = attr->next) {
683         while (attr != nullptr && attr->group_tag != IPP_TAG_PRINTER) {
684             attr = attr->next;
685         }
686         if (attr == nullptr) {
687             break;
688         }
689         const char* ppd_make_model = nullptr;
690         const char* ppd_name = nullptr;
691 
692         while (attr != nullptr && attr->group_tag == IPP_TAG_PRINTER) {
693             if (!strcmp(attr->name, "ppd-make-and-model") && attr->value_tag == IPP_TAG_TEXT) {
694                 ppd_make_model = attr->values[0].string.text;
695             } else if (!strcmp(attr->name, "ppd-name") && attr->value_tag == IPP_TAG_NAME) {
696                 ppd_name = attr->values[0].string.text;
697             }
698             attr = attr->next;
699         }
700         if (ppd_make_model != nullptr && ppd_name != nullptr) {
701             ppds.push_back(std::string(ppd_name));
702             PRINT_HILOGI("ppd: name = %{private}s, make-and-model = %{private}s", ppd_name, ppd_make_model);
703         }
704         if (attr == nullptr) {
705             break;
706         }
707     }
708 }
709 
AddPrinterToCups(const std::string & printerUri,const std::string & printerName,const std::string & printerMake)710 int32_t PrintCupsClient::AddPrinterToCups(const std::string &printerUri, const std::string &printerName,
711     const std::string &printerMake)
712 {
713     PRINT_HILOGD("PrintCupsClient AddPrinterToCups start, printerMake: %{public}s", printerMake.c_str());
714     std::string ppdName = DEFAULT_PPD_NAME;
715     QueryPPDInformation(printerMake, ppdName);
716     PRINT_HILOGI("ppd driver: %{public}s", ppdName.c_str());
717     return AddPrinterToCupsWithSpecificPpd(printerUri, printerName, ppdName);
718 }
719 
AddPrinterToCupsWithSpecificPpd(const std::string & printerUri,const std::string & printerName,const std::string & ppdName)720 int32_t PrintCupsClient::AddPrinterToCupsWithSpecificPpd(const std::string &printerUri, const std::string &printerName,
721     const std::string &ppdName)
722 {
723     std::string curDir = GetCurCupsRootDir();
724     if (ppdName != DEFAULT_PPD_NAME) {
725         std::string serverBin = curDir + "/serverbin";
726         mode_t permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH;
727         int ret = ChangeFilterPermission(serverBin, permissions);
728         PRINT_HILOGI("ChangeFilterPermission result: %{public}d", ret);
729     }
730     PRINT_HILOGI("ppd driver: %{public}s", ppdName.c_str());
731     std::string standardName = PrintUtil::StandardizePrinterName(printerName);
732     if (IsPrinterExist(printerUri.c_str(), standardName.c_str(), ppdName.c_str())) {
733         PRINT_HILOGI("add success, printer has added");
734         return E_PRINT_NONE;
735     }
736     if (printAbility_ == nullptr) {
737         PRINT_HILOGW("printAbility_ is null");
738         return E_PRINT_SERVER_FAILURE;
739     }
740 
741     ipp_t *request = nullptr;
742     char uri[HTTP_MAX_URI] = {0};
743     ippSetPort(CUPS_SEVER_PORT);
744     request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
745     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", nullptr, "localhost", 0, "/printers/%s",
746                      standardName.c_str());
747     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, uri);
748     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
749     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", nullptr, standardName.c_str());
750     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", nullptr, printerUri.c_str());
751     ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
752     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", nullptr, ppdName.c_str());
753     ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
754     PRINT_HILOGD("IPP_OP_CUPS_ADD_MODIFY_PRINTER cupsDoRequest");
755     ippDelete(printAbility_->DoRequest(nullptr, request, "/admin/"));
756     if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
757         PRINT_HILOGE("add error: %{public}s", cupsLastErrorString());
758         return E_PRINT_SERVER_FAILURE;
759     }
760     PRINT_HILOGI("add success");
761     return E_PRINT_NONE;
762 }
763 
AddPrinterToCupsWithPpd(const std::string & printerUri,const std::string & printerName,const std::string & ppdName,const std::string & ppdData)764 int32_t PrintCupsClient::AddPrinterToCupsWithPpd(const std::string &printerUri, const std::string &printerName,
765     const std::string &ppdName, const std::string &ppdData)
766 {
767     PRINT_HILOGD("AddPrinterToCupsWithPpd, ppdName: %{public}s", ppdName.c_str());
768     ipp_t *request = nullptr;
769     char uri[HTTP_MAX_URI] = {0};
770     std::vector<string> ppds;
771     std::string standardName = PrintUtil::StandardizePrinterName(printerName);
772     std::string standardUri = StandardizePrinterUri(printerUri, ppdName);
773     if (IsPrinterExist(standardUri.c_str(), standardName.c_str(), ppdName.c_str())) {
774         PRINT_HILOGI("add success, printer has added");
775         return E_PRINT_NONE;
776     }
777     ippSetPort(CUPS_SEVER_PORT);
778     _cupsSetError(IPP_STATUS_OK, nullptr, 0);
779     request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
780     if (request == nullptr) {
781         PRINT_HILOGW("request is null");
782         return E_PRINT_SERVER_FAILURE;
783     }
784     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", nullptr, "localhost", 0, "/printers/%s",
785         standardName.c_str());
786     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, uri);
787     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
788     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", nullptr, standardName.c_str());
789     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", nullptr, standardUri.c_str());
790     ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
791     ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
792     ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared", 1);
793     http_status_t status = cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/admin/",
794         ippLength(request) + ppdData.length());
795     if (status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA) {
796         status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, ppdData.c_str(), ppdData.length());
797     } else {
798         ippDelete(request);
799         request = nullptr;
800         PRINT_HILOGW("ppd not send, status = %{public}d", static_cast<int>(status));
801         return E_PRINT_SERVER_FAILURE;
802     }
803     ippDelete(request);
804     request = nullptr;
805     if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE) {
806         PRINT_HILOGW("add error, status = %{public}d", static_cast<int>(status));
807         return E_PRINT_SERVER_FAILURE;
808     }
809     if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
810         PRINT_HILOGE("add error: %{public}s", cupsLastErrorString());
811         return E_PRINT_SERVER_FAILURE;
812     }
813     PRINT_HILOGI("add success");
814     return E_PRINT_NONE;
815 }
816 
DeleteCupsPrinter(const char * printerName)817 int32_t PrintCupsClient::DeleteCupsPrinter(const char *printerName)
818 {
819     ipp_t *request = nullptr;
820     char uri[HTTP_MAX_URI] = {0};
821 
822     PRINT_HILOGD("PrintCupsClient DeleteCupsPrinter start: %{private}s", printerName);
823     if (printAbility_ == nullptr) {
824         PRINT_HILOGW("printAbility_ is null");
825         return E_PRINT_SERVER_FAILURE;
826     }
827     request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
828     if (request == nullptr) {
829         PRINT_HILOGW("request is null");
830         return E_PRINT_SERVER_FAILURE;
831     }
832     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
833         "ipp", nullptr, "localhost", 0, "/printers/%s", printerName);
834     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, uri);
835     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
836     ippDelete(printAbility_->DoRequest(nullptr, request, "/admin/"));
837     if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
838         PRINT_HILOGW("DeleteCupsPrinter error: %{public}s", cupsLastErrorString());
839     }
840     return E_PRINT_NONE;
841 }
842 
QueryPrinterAttributesByUri(const std::string & printerUri,const std::string & nic,int num,const char * const * pattrs)843 ipp_t *PrintCupsClient::QueryPrinterAttributesByUri(const std::string &printerUri, const std::string &nic, int num,
844     const char * const *pattrs)
845 {
846     ipp_t *request = nullptr; /* IPP Request */
847     ipp_t *response = nullptr; /* IPP Request */
848     http_t *http = nullptr;
849     char scheme[HTTP_MAX_URI] = {0}; /* Method portion of URI */
850     char username[HTTP_MAX_URI] = {0}; /* Username portion of URI */
851     char host[HTTP_MAX_URI] = {0}; /* Host portion of URI */
852     char resource[HTTP_MAX_URI] = {0}; /* Resource portion of URI */
853     int port = 0; /* Port portion of URI */
854     PRINT_HILOGD("QueryPrinterAttributesByUri enter");
855     if (printAbility_ == nullptr) {
856         PRINT_HILOGW("printAbility_ is null");
857         return nullptr;
858     }
859     httpSeparateURI(HTTP_URI_CODING_ALL, printerUri.c_str(), scheme, sizeof(scheme), username, sizeof(username), host,
860         sizeof(host), &port, resource, sizeof(resource));
861     if (host[0] == '\0' || (port != IPP_PORT && strcasestr(scheme, "ipp") == nullptr) || !IsIpAddress(host)) {
862         PRINT_HILOGW("host is empty or not ipp protocol");
863         return nullptr;
864     }
865     if (nic.empty()) {
866         http = httpConnect2(host, port, nullptr, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, TIME_OUT, nullptr);
867     } else {
868         http = httpConnect3(host, port, nullptr, AF_UNSPEC,
869             HTTP_ENCRYPTION_IF_REQUESTED, 1, TIME_OUT, nullptr, nic.c_str());
870     }
871     if (http == nullptr) {
872         PRINT_HILOGW("connect printer failed");
873         return nullptr;
874     }
875     _cupsSetError(IPP_STATUS_OK, nullptr, 0);
876     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
877     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, printerUri.c_str());
878     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
879     ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", num, nullptr, pattrs);
880     response = printAbility_->DoRequest(http, request, "/");
881     httpClose(http);
882     http = nullptr;
883     if (response == nullptr) {
884         PRINT_HILOGW("response is null");
885         return nullptr;
886     }
887     if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
888         PRINT_HILOGE("get printer attributes error: %{public}s", cupsLastErrorString());
889         ippDelete(response);
890         response = nullptr;
891         return nullptr;
892     }
893     return response;
894 }
895 
QueryPrinterCapabilityByUri(const std::string & printerUri,const std::string & printerId,PrinterCapability & printerCaps)896 int32_t PrintCupsClient::QueryPrinterCapabilityByUri(const std::string &printerUri, const std::string &printerId,
897     PrinterCapability &printerCaps)
898 {
899     PRINT_HILOGD("PrintCupsClient QueryPrinterCapabilityByUri start.");
900     static const char * const pattrs[] = { "all" };
901     std::string nic;
902     IsIpConflict(printerId, nic);
903     ipp_t *response = QueryPrinterAttributesByUri(printerUri, nic, sizeof(pattrs) / sizeof(pattrs[0]), pattrs);
904     if (response == nullptr) {
905         PRINT_HILOGW("get attributes fail");
906         return E_PRINT_SERVER_FAILURE;
907     }
908     PRINT_HILOGD("get attributes success");
909     ParsePrinterAttributesFromIPP(response, printerCaps);
910     ippDelete(response);
911     response = nullptr;
912     return E_PRINT_NONE;
913 }
914 
QueryPrinterStatusByUri(const std::string & printerUri,PrinterStatus & status)915 int32_t PrintCupsClient::QueryPrinterStatusByUri(const std::string &printerUri, PrinterStatus &status)
916 {
917     PRINT_HILOGD("PrintCupsClient QueryPrinterStatusByUri start.");
918     static const char * const pattrs[] = { "printer-state" };
919     ipp_t *response = QueryPrinterAttributesByUri(printerUri, "", sizeof(pattrs) / sizeof(pattrs[0]), pattrs);
920     if (response == nullptr) {
921         PRINT_HILOGW("get attributes fail");
922         return E_PRINT_SERVER_FAILURE;
923     }
924     PRINT_HILOGD("get attributes success");
925     bool result = ParsePrinterStatusAttributes(response, status);
926     ippDelete(response);
927     response = nullptr;
928     if (!result) {
929         PRINT_HILOGW("parse state failed");
930         return E_PRINT_SERVER_FAILURE;
931     }
932     return E_PRINT_NONE;
933 }
934 
QueryPrinterCapabilityFromPPD(const std::string & printerName,PrinterCapability & printerCaps,const std::string & ppdName)935 int32_t PrintCupsClient::QueryPrinterCapabilityFromPPD(const std::string &printerName, PrinterCapability &printerCaps,
936     const std::string &ppdName)
937 {
938     if (!ppdName.empty()) {
939         return QueryPrinterCapabilityFromPPDFile(printerCaps, GetCurCupsRootDir() + "/datadir/model/" + ppdName);
940     }
941     std::string standardName = PrintUtil::StandardizePrinterName(printerName);
942     PRINT_HILOGI("QueryPrinterCapabilityFromPPD printerName: %{private}s", standardName.c_str());
943 
944     cups_dest_t *dest = nullptr;
945     if (printAbility_ == nullptr) {
946         PRINT_HILOGW("printAbility_ is null");
947         return E_PRINT_SERVER_FAILURE;
948     }
949     dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, standardName.c_str(), nullptr);
950     if (dest == nullptr) {
951         PRINT_HILOGE("the printer is not found");
952         return E_PRINT_SERVER_FAILURE;
953     }
954     cups_dinfo_t *dinfo = printAbility_->CopyDestInfo(CUPS_HTTP_DEFAULT, dest);
955     if (dinfo == nullptr) {
956         PRINT_HILOGE("cupsCopyDestInfo failed");
957         printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
958         return E_PRINT_SERVER_FAILURE;
959     }
960 
961     ParsePrinterAttributesFromIPP(dinfo->attrs, printerCaps);
962     printerCaps.Dump();
963 
964     printAbility_->FreeDestInfo(dinfo);
965     printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
966     PRINT_HILOGI("QueryPrinterCapabilityFromPPD out\n");
967     return E_PRINT_NONE;
968 }
969 
AddCupsPrintJob(const PrintJob & jobInfo,const std::string & userName)970 void PrintCupsClient::AddCupsPrintJob(const PrintJob &jobInfo, const std::string &userName)
971 {
972     JobParameters *jobParams =  BuildJobParameters(jobInfo, userName);
973     if (jobParams == nullptr) {
974         PRINT_HILOGE("AddCupsPrintJob Params is nullptr");
975         return;
976     }
977     DumpJobParameters(jobParams);
978     jobQueue_.push_back(jobParams);
979     StartNextJob();
980 }
981 
GetNextJob()982 JobParameters *PrintCupsClient::GetNextJob()
983 {
984     if (jobQueue_.empty()) {
985         PRINT_HILOGE("no active job in jobQueue_");
986         return nullptr;
987     }
988     if (currentJob_ != nullptr) {
989         JobParameters *lastJob = jobQueue_.back();
990         if (lastJob != nullptr) {
991             PrintServiceAbility::GetInstance()->UpdatePrintJobState(lastJob->serviceJobId, PRINT_JOB_QUEUED,
992                 PRINT_JOB_BLOCKED_UNKNOWN);
993         }
994         PRINT_HILOGE("a active job is sending, job len: %{public}zd", jobQueue_.size());
995         return nullptr;
996     }
997     PRINT_HILOGI("start next job from queue");
998 
999     std::lock_guard<std::mutex> lock(jobMutex);
1000     currentJob_ = jobQueue_.at(0);
1001     jobQueue_.erase(jobQueue_.begin());
1002     return currentJob_;
1003 }
1004 
StartNextJob()1005 void PrintCupsClient::StartNextJob()
1006 {
1007     auto nextJob = GetNextJob();
1008     if (nextJob == nullptr) {
1009         PRINT_HILOGW("nextJob is nullptr");
1010         return;
1011     }
1012     if (toCups_) {
1013         auto self = shared_from_this();
1014         CallbackFunc callback = [self]() { self->JobSentCallback(); };
1015         std::thread StartPrintThread([self, callback] {self->StartCupsJob(self->currentJob_, callback);});
1016         StartPrintThread.detach();
1017     }
1018 }
1019 
JobSentCallback()1020 void PrintCupsClient::JobSentCallback()
1021 {
1022     PRINT_HILOGI("Previous job send success, start next job");
1023     if (currentJob_ != nullptr) {
1024         PrintServiceAbility::GetInstance()->FlushCacheFileToUserData(currentJob_->serviceJobId);
1025         delete currentJob_;
1026         currentJob_ = nullptr;
1027     }
1028     StartNextJob();
1029 }
1030 
FillBorderlessOptions(JobParameters * jobParams,int num_options,cups_option_t ** options)1031 int PrintCupsClient::FillBorderlessOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
1032 {
1033     if (jobParams == nullptr) {
1034         PRINT_HILOGE("FillBorderlessOptions Params is nullptr");
1035         return num_options;
1036     }
1037     if (jobParams->mediaType.find(CUPS_MEDIA_TYPE_PHOTO) != std::string::npos && jobParams->borderless) {
1038         PRINT_HILOGD("borderless job options");
1039         num_options = cupsAddOption("print-scaling", "fill", num_options, options);
1040         std::vector<MediaSize> mediaSizes;
1041         mediaSizes.push_back({ CUPS_MEDIA_A4, ISO_A4_WIDTH, ISO_A4_HEIGHT });
1042         mediaSizes.push_back({ CUPS_MEDIA_4X6, PHOTO_4R_WIDTH, PHOTO_4R_HEIGHT });
1043         mediaSizes.push_back({ CUPS_MEDIA_5X7, PHOTO_5R_WIDTH, PHOTO_5R_HEIGHT });
1044         int sizeIndex = -1;
1045         float meidaWidth = 0;
1046         float mediaHeight = 0;
1047         for (int i = 0; i < static_cast<int>(mediaSizes.size()); i++) {
1048             if (mediaSizes[i].name == jobParams->mediaSize) {
1049                 sizeIndex = i;
1050                 break;
1051             }
1052         }
1053         if (sizeIndex >= 0) {
1054             meidaWidth = floorf(ConvertInchTo100MM(mediaSizes[sizeIndex].WidthInInches));
1055             mediaHeight = floorf(ConvertInchTo100MM(mediaSizes[sizeIndex].HeightInInches));
1056         } else {
1057             meidaWidth = floorf(ConvertInchTo100MM(mediaSizes[0].WidthInInches));
1058             mediaHeight = floorf(ConvertInchTo100MM(mediaSizes[0].HeightInInches));
1059         }
1060         std::stringstream value;
1061         value << "{media-size={x-dimension=" << meidaWidth << " y-dimension=" << mediaHeight;
1062         value << "} media-bottom-margin=" << 0 << " media-left-margin=" << 0 << " media-right-margin=" << 0;
1063         value << " media-top-margin=" << 0 << " media-type=\"" << jobParams->mediaType << "\"}";
1064         PRINT_HILOGD("value: %s", value.str().c_str());
1065         num_options = cupsAddOption("media-col", value.str().c_str(), num_options, options);
1066     } else {
1067         PRINT_HILOGD("not borderless job options");
1068         num_options = cupsAddOption("fit-to-page", "true", num_options, options);
1069         if (!jobParams->mediaSize.empty()) {
1070             num_options = cupsAddOption(CUPS_MEDIA, jobParams->mediaSize.c_str(), num_options, options);
1071         } else {
1072             num_options = cupsAddOption(CUPS_MEDIA, CUPS_MEDIA_A4, num_options, options);
1073         }
1074         if (!jobParams->mediaType.empty()) {
1075             num_options = cupsAddOption(CUPS_MEDIA_TYPE, jobParams->mediaType.c_str(), num_options, options);
1076         } else {
1077             num_options = cupsAddOption(CUPS_MEDIA_TYPE, CUPS_MEDIA_TYPE_PLAIN, num_options, options);
1078         }
1079     }
1080     return num_options;
1081 }
1082 
FillLandscapeOptions(JobParameters * jobParams,int num_options,cups_option_t ** options)1083 int PrintCupsClient::FillLandscapeOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
1084 {
1085     if (jobParams->isAutoRotate) {
1086         PRINT_HILOGE("AutoRotate is Open, skip FillLandscapeOptions");
1087         return num_options;
1088     }
1089     num_options = cupsAddOption("pdfAutoRotate", "false", num_options, options);
1090     if (jobParams->isLandscape) {
1091         num_options = cupsAddOption(CUPS_ORIENTATION, CUPS_ORIENTATION_LANDSCAPE, num_options, options);
1092     } else {
1093         num_options = cupsAddOption(CUPS_ORIENTATION, CUPS_ORIENTATION_PORTRAIT, num_options, options);
1094     }
1095     return num_options;
1096 }
1097 
FillJobOptions(JobParameters * jobParams,int num_options,cups_option_t ** options)1098 int PrintCupsClient::FillJobOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
1099 {
1100     if (jobParams == nullptr) {
1101         PRINT_HILOGE("FillJobOptions Params is nullptr");
1102         return num_options;
1103     }
1104     if (jobParams->numCopies >= 1) {
1105         num_options = cupsAddIntegerOption(CUPS_COPIES, jobParams->numCopies, num_options, options);
1106     } else {
1107         num_options = cupsAddIntegerOption(CUPS_COPIES, 1, num_options, options);
1108     }
1109 
1110     if (!jobParams->duplex.empty()) {
1111         num_options = cupsAddOption(CUPS_SIDES, jobParams->duplex.c_str(), num_options, options);
1112     } else {
1113         num_options = cupsAddOption(CUPS_SIDES, CUPS_SIDES_ONE_SIDED, num_options, options);
1114     }
1115     if (!jobParams->printQuality.empty()) {
1116         num_options = cupsAddOption(CUPS_PRINT_QUALITY, jobParams->printQuality.c_str(), num_options, options);
1117     } else {
1118         num_options = cupsAddOption(CUPS_PRINT_QUALITY, CUPS_PRINT_QUALITY_NORMAL, num_options, options);
1119     }
1120     if (!jobParams->color.empty()) {
1121         num_options = cupsAddOption(CUPS_PRINT_COLOR_MODE, jobParams->color.c_str(), num_options, options);
1122     } else {
1123         num_options = cupsAddOption(CUPS_PRINT_COLOR_MODE, CUPS_PRINT_COLOR_MODE_AUTO, num_options, options);
1124     }
1125 
1126     num_options = FillLandscapeOptions(jobParams, num_options, options);
1127 
1128     if (jobParams->isCollate) {
1129         num_options = cupsAddOption("Collate", "true", num_options, options);
1130     } else {
1131         num_options = cupsAddOption("Collate", "false", num_options, options);
1132     }
1133     if (jobParams->isReverse) {
1134         num_options = cupsAddOption("OutputOrder", "Reverse", num_options, options);
1135     } else {
1136         num_options = cupsAddOption("OutputOrder", "Normal", num_options, options);
1137     }
1138     std::string nic;
1139     if (IsIpConflict(jobParams->printerId, nic)) {
1140         num_options = cupsAddOption("nic", nic.c_str(), num_options, options);
1141     }
1142     num_options = FillBorderlessOptions(jobParams, num_options, options);
1143     num_options = FillAdvancedOptions(jobParams, num_options, options);
1144     return num_options;
1145 }
1146 
FillAdvancedOptions(JobParameters * jobParams,int num_options,cups_option_t ** options)1147 int PrintCupsClient::FillAdvancedOptions(JobParameters *jobParams, int num_options, cups_option_t **options)
1148 {
1149     if (jobParams->advancedOpsJson.isNull()) {
1150         PRINT_HILOGE("advanced options are null.");
1151         return num_options;
1152     }
1153 
1154     Json::Value::Members keys = jobParams->advancedOpsJson.getMemberNames();
1155     for (auto key = keys.begin(); key != keys.end(); key++) {
1156         std::string keyStr = *key;
1157         if (jobParams->advancedOpsJson.isMember(keyStr) || jobParams->advancedOpsJson[keyStr].isString()) {
1158             std::string valueStr = jobParams->advancedOpsJson[keyStr].asString();
1159             num_options = cupsAddOption(keyStr.c_str(), valueStr.c_str(), num_options, options);
1160         }
1161     }
1162     return num_options;
1163 }
1164 
QueryAddedPrinterList(std::vector<std::string> & printerNameList)1165 int32_t PrintCupsClient::QueryAddedPrinterList(std::vector<std::string> &printerNameList)
1166 {
1167     if (!IsCupsServerAlive()) {
1168         PRINT_HILOGI("The cupsd process is not started, start it now.");
1169         int32_t ret = StartCupsdService();
1170         if (ret != 0) {
1171             return E_PRINT_SERVER_FAILURE;
1172         }
1173     }
1174     printerNameList.clear();
1175     cups_dest_t *dests = nullptr;
1176     int num = cupsGetDests(&dests);
1177     PRINT_HILOGI("QueryAddedPrinterList, num: %{public}d.", num);
1178     for (int i = 0; i < num; i++) {
1179         PRINT_HILOGD("QueryAddedPrinterList, printerIsDefault: %{public}d.", dests[i].is_default);
1180         printerNameList.emplace_back(dests[i].name);
1181     }
1182     cupsFreeDests(num, dests);
1183     return E_PRINT_NONE;
1184 }
1185 
SetDefaultPrinter(const std::string & printerName)1186 int32_t PrintCupsClient::SetDefaultPrinter(const std::string &printerName)
1187 {
1188     http_t *http = nullptr;
1189     if (printAbility_ == nullptr) {
1190         PRINT_HILOGW("printAbility_ is null");
1191         return E_PRINT_SERVER_FAILURE;
1192     }
1193     ippSetPort(CUPS_SEVER_PORT);
1194     http = httpConnect2(cupsServer(), ippPort(), nullptr,
1195         AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, nullptr);
1196     if (http == nullptr) {
1197         PRINT_HILOGE("cups server is not alive");
1198         return E_PRINT_SERVER_FAILURE;
1199     }
1200     ipp_t *request = nullptr;         /* IPP Request */
1201     char uri[HTTP_MAX_URI] = {0}; /* URI for printer/class */
1202     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", nullptr,
1203         "localhost", 0, "/printers/%s", printerName.c_str());
1204     request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
1205     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1206         "printer-uri", nullptr, uri);
1207     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1208         nullptr, cupsUser());
1209     ippDelete(printAbility_->DoRequest(http, request, "/admin/"));
1210     httpClose(http);
1211 
1212     const char* default_printer = cupsGetDefault();
1213     PRINT_HILOGI("default_printer=%{public}s", default_printer);
1214     if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
1215         PRINT_HILOGI("[ERROR] occur a error when do cups-request{setDefault}. error is:> ");
1216         return E_PRINT_SERVER_FAILURE;
1217     }
1218     return E_PRINT_NONE;
1219 }
1220 
GetPPDFile(const std::string & printerName)1221 ppd_file_t* PrintCupsClient::GetPPDFile(const std::string &printerName)
1222 {
1223     if (!IsCupsServerAlive()) {
1224         PRINT_HILOGI("The cupsd process is not started, start it now.");
1225         int32_t ret = StartCupsdService();
1226         if (ret != 0) {
1227             PRINT_HILOGE("The cupsd process start fail.");
1228             return nullptr;
1229         }
1230     }
1231     if (printerName.find("../") == 0) {
1232         PRINT_HILOGE("GetPPDFile printerName is out of fileDir");
1233         return nullptr;
1234     }
1235     ppd_file_t *ppd = 0;
1236     std::string fileDir = GetCurCupsRootDir() + "/ppd/";
1237     std::string pName = printerName;
1238     std::string filePath = fileDir + pName + ".ppd";
1239     PRINT_HILOGI("GetPPDFile started filePath %{public}s", filePath.c_str());
1240     char realPath[PATH_MAX] = {};
1241     if (realpath(filePath.c_str(), realPath) == nullptr) {
1242         PRINT_HILOGE("The realPidFile is null, errno:%{public}s", std::to_string(errno).c_str());
1243         return nullptr;
1244     }
1245     int fd;
1246     if ((fd = open(realPath, O_RDWR)) < 0) {
1247         PRINT_HILOGE("Open ppdFile error!");
1248         return nullptr;
1249     }
1250     fdsan_exchange_owner_tag(fd, 0, PRINT_LOG_DOMAIN);
1251     PRINT_HILOGI("GetPPDFile %{public}d", fd);
1252     ppd = ppdOpenFd(fd);
1253     fdsan_close_with_tag(fd, PRINT_LOG_DOMAIN);
1254     if (ppd == nullptr) {
1255         PRINT_HILOGE("ppdfile open is nullptr");
1256     } else {
1257         PRINT_HILOGI("GetPPDFile groups:%{public}d,pagesize_num:%{public}d", ppd->num_groups, ppd->num_sizes);
1258     }
1259     return ppd;
1260 }
1261 
QueryPrinterAttrList(const std::string & printerName,const std::vector<std::string> & keyList,std::vector<std::string> & valueList)1262 int32_t PrintCupsClient::QueryPrinterAttrList(const std::string &printerName, const std::vector<std::string> &keyList,
1263     std::vector<std::string> &valueList)
1264 {
1265     if (printAbility_ == nullptr) {
1266         PRINT_HILOGW("printAbility_ is null");
1267         return E_PRINT_SERVER_FAILURE;
1268     }
1269     cups_dest_t *dest = nullptr;
1270     dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, printerName.c_str(), nullptr);
1271     if (dest == nullptr) {
1272         PRINT_HILOGW("the printer is not found");
1273         return E_PRINT_SERVER_FAILURE;
1274     }
1275     for (const auto &key : keyList) {
1276         const char *ret = cupsGetOption(key.c_str(), dest->num_options, dest->options);
1277         if (ret != nullptr) {
1278             std::string valueStr = ret;
1279             std::string value = key + "&" + valueStr;
1280             valueList.emplace_back(value);
1281         }
1282     }
1283     printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
1284     PRINT_HILOGI("QueryPrinterAttr end");
1285     return E_PRINT_NONE;
1286 }
1287 
QueryPrinterInfoByPrinterId(const std::string & printerId,PrinterInfo & info)1288 int32_t PrintCupsClient::QueryPrinterInfoByPrinterId(const std::string &printerId, PrinterInfo &info)
1289 {
1290     PRINT_HILOGD("the printerInfo printerName %{public}s", info.GetPrinterName().c_str());
1291     if (printAbility_ == nullptr) {
1292         PRINT_HILOGW("printAbility_ is null");
1293         return E_PRINT_SERVER_FAILURE;
1294     }
1295     cups_dest_t *dest = nullptr;
1296     dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, info.GetPrinterName().c_str(), nullptr);
1297     if (dest == nullptr) {
1298         PRINT_HILOGW("the printer is not found");
1299         return E_PRINT_SERVER_FAILURE;
1300     }
1301     printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
1302     if (info.HasOption()) {
1303         PRINT_HILOGI("the printerInfo option");
1304         PrinterCapability printerCaps;
1305         std::string infoOpt = info.GetOption();
1306         PRINT_HILOGD("the printerInfo option %{public}s", infoOpt.c_str());
1307         Json::Value infoJson;
1308         if (!PrintJsonUtil::Parse(infoOpt, infoJson)) {
1309             PRINT_HILOGE("infoOpt can not parse to json object");
1310             return E_PRINT_INVALID_PARAMETER;
1311         }
1312         if (!PrintJsonUtil::IsMember(infoJson, "printerUri") || !infoJson["printerUri"].isString()) {
1313             PRINT_HILOGE("The infoJson does not have a necessary printerUri attribute.");
1314             return E_PRINT_INVALID_PARAMETER;
1315         }
1316         std::string printerUri = infoJson["printerUri"].asString();
1317         PRINT_HILOGD("QueryPrinterInfoByPrinterId in %{public}s", printerUri.c_str());
1318         if (PrintJsonUtil::IsMember(infoJson, "printerName") && infoJson["printerName"].isString()) {
1319             info.SetPrinterName(infoJson["printerName"].asString());
1320         }
1321         int32_t ret = QueryPrinterCapabilityByUri(printerUri, printerId, printerCaps);
1322         PRINT_HILOGI("QueryPrinterInfoByPrinterId out");
1323         if (ret != 0) {
1324             PRINT_HILOGE("QueryPrinterInfoByPrinterId QueryPrinterCapabilityByUri fail");
1325             return E_PRINT_SERVER_FAILURE;
1326         }
1327         Json::Value cupsOptionsJson = printerCaps.GetPrinterAttrGroupJson();
1328         infoJson["cupsOptions"] = cupsOptionsJson;
1329         info.SetOption(PrintJsonUtil::WriteString(infoJson));
1330         info.Dump();
1331     }
1332     return E_PRINT_NONE;
1333 }
1334 
CheckPrinterMakeModel(JobParameters * jobParams,bool & driverMissing)1335 bool PrintCupsClient::CheckPrinterMakeModel(JobParameters *jobParams, bool &driverMissing)
1336 {
1337     cups_dest_t *dest = nullptr;
1338     bool isMakeModelRight = false;
1339     uint32_t retryCount = 0;
1340     PRINT_HILOGD("CheckPrinterMakeModel start.");
1341     if (jobParams == nullptr) {
1342         PRINT_HILOGE("The jobParams is null");
1343         return isMakeModelRight;
1344     }
1345     if (printAbility_ == nullptr) {
1346         PRINT_HILOGW("printAbility_ is null");
1347         return isMakeModelRight;
1348     }
1349     const uint32_t GET_OPTION_TIMES = 40;
1350     while (retryCount < GET_OPTION_TIMES) {
1351         dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, jobParams->printerName.c_str(), nullptr);
1352         if (dest != nullptr) {
1353             const char *makeModel = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
1354             if (makeModel == nullptr || strcmp(makeModel, "Local Raw Printer") == 0) {
1355                 printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
1356                 retryCount++;
1357                 sleep(INDEX_TWO);
1358                 continue;
1359             }
1360             PRINT_HILOGD("makeModel=%{private}s", makeModel);
1361             if (!CheckPrinterDriverExist(std::string(makeModel))) {
1362                 driverMissing = true;
1363                 break;
1364             }
1365             isMakeModelRight = true;
1366             printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
1367             break;
1368         } else {
1369             PRINT_HILOGE("The dest is null");
1370         }
1371         retryCount++;
1372         sleep(INDEX_TWO);
1373     }
1374     return isMakeModelRight;
1375 }
1376 
CheckPrinterDriverExist(const std::string & makeModel)1377 bool PrintCupsClient::CheckPrinterDriverExist(const std::string &makeModel)
1378 {
1379     if (makeModel.empty()) {
1380         PRINT_HILOGE("makeModel empty");
1381         return false;
1382     }
1383     if (strstr(makeModel.c_str(), DEFAULT_MAKE_MODEL.c_str()) != nullptr ||
1384         strstr(makeModel.c_str(), BSUNI_PPD_NAME.c_str()) != nullptr) {
1385         PRINT_HILOGI("skip check printer driver exist");
1386         return true;
1387     }
1388     std::string ppdName;
1389     QueryPPDInformation(makeModel, ppdName);
1390     return !ppdName.empty();
1391 }
1392 
VerifyPrintJob(JobParameters * jobParams,int & num_options,uint32_t & jobId,cups_option_t * options,http_t * http)1393 bool PrintCupsClient::VerifyPrintJob(JobParameters *jobParams, int &num_options, uint32_t &jobId,
1394     cups_option_t *options, http_t *http)
1395 {
1396     if (jobParams == nullptr) {
1397         PRINT_HILOGE("The jobParams is null");
1398         return false;
1399     }
1400     uint32_t retryCount = 0;
1401     bool isPrinterOnline = false;
1402     auto monitorParams = std::make_shared<JobMonitorParam>(jobParams->serviceAbility, jobParams->serviceJobId,
1403         jobId, jobParams->printerUri, jobParams->printerName, jobParams->printerId, http);
1404     while (retryCount < MAX_RETRY_TIMES) {
1405         if (CheckPrinterOnline(monitorParams)) {
1406             isPrinterOnline = true;
1407             break;
1408         }
1409         retryCount++;
1410         sleep(INDEX_ONE);
1411     }
1412     if (!isPrinterOnline) {
1413         PRINT_HILOGE("VerifyPrintJob printer is offline.");
1414         jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1415             PRINT_JOB_BLOCKED_OFFLINE);
1416         return false;
1417     }
1418     bool driverMissing = false;
1419     if (!CheckPrinterMakeModel(jobParams, driverMissing)) {
1420         PRINT_HILOGE("VerifyPrintJob printer make model is error");
1421         jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1422             driverMissing ? PRINT_JOB_BLOCKED_DRIVER_MISSING : PRINT_JOB_BLOCKED_DRIVER_EXCEPTION);
1423         return false;
1424     }
1425     num_options = FillJobOptions(jobParams, num_options, &options);
1426     cupsSetUser(jobParams->jobOriginatingUserName.c_str());
1427     if ((jobId = static_cast<uint32_t>(cupsCreateJob(http, jobParams->printerName.c_str(), jobParams->jobName.c_str(),
1428         num_options, options))) == 0) {
1429         PRINT_HILOGE("Unable to cupsCreateJob: %{public}s", cupsLastErrorString());
1430         jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, PRINT_JOB_BLOCKED,
1431             PRINT_JOB_BLOCKED_SERVER_CONNECTION_ERROR);
1432         return false;
1433     }
1434     return true;
1435 }
1436 
HandleFiles(JobParameters * jobParams,uint32_t num_files,http_t * http,uint32_t jobId)1437 bool PrintCupsClient::HandleFiles(JobParameters *jobParams, uint32_t num_files, http_t *http, uint32_t jobId)
1438 {
1439     if (jobParams == nullptr) {
1440         PRINT_HILOGW("jobParams is null");
1441         return false;
1442     }
1443     cups_file_t *fp = nullptr;
1444     http_status_t status;
1445     char buffer[DEFAULT_BUFFER_SIZE_8K];
1446     ssize_t bytes = -1;
1447 
1448     for (uint32_t i = 0; i < num_files; i++) {
1449         if ((fp = cupsFileOpenFd(jobParams->fdList[i], "rb")) == nullptr) {
1450             PRINT_HILOGE("Unable to open print file, cancel the job");
1451             cupsCancelJob2(http, jobParams->printerName.c_str(), jobId, 0);
1452             UpdatePrintJobStateInJobParams(jobParams, PRINT_JOB_BLOCKED, PRINT_JOB_COMPLETED_FILE_CORRUPT);
1453             return false;
1454         }
1455         status = cupsStartDocument(http, jobParams->printerName.c_str(), jobId, jobParams->jobName.c_str(),
1456             jobParams->documentFormat.c_str(), i == (num_files - 1));
1457         if (status == HTTP_STATUS_CONTINUE) {
1458             bytes = cupsFileRead(fp, buffer, sizeof(buffer));
1459         }
1460         while (status == HTTP_STATUS_CONTINUE && bytes > 0) {
1461             status = cupsWriteRequestData(http, buffer, (size_t)bytes);
1462             bytes = cupsFileRead(fp, buffer, sizeof(buffer));
1463         }
1464         cupsFileClose(fp);
1465         if (status != HTTP_STATUS_CONTINUE || cupsFinishDocument(http, jobParams->printerName.c_str())
1466             != IPP_STATUS_OK) {
1467             PRINT_HILOGE("Unable to queue, error is %{public}s, cancel the job and return...", cupsLastErrorString());
1468             cupsCancelJob2(http, jobParams->printerUri.c_str(), jobId, 0);
1469             UpdatePrintJobStateInJobParams(jobParams, PRINT_JOB_BLOCKED, PRINT_JOB_BLOCKED_UNKNOWN);
1470             return false;
1471         }
1472     }
1473     return true;
1474 }
1475 
StartCupsJob(JobParameters * jobParams,CallbackFunc callback)1476 void PrintCupsClient::StartCupsJob(JobParameters *jobParams, CallbackFunc callback)
1477 {
1478     http_t *http = nullptr;
1479     int num_options = 0;
1480     cups_option_t *options = nullptr;
1481     uint32_t jobId = 0;
1482 
1483     if (!VerifyPrintJob(jobParams, num_options, jobId, options, http)) {
1484         callback();
1485         PRINT_HILOGE("verify print job failed");
1486         return;
1487     }
1488     if (ResumePrinter(jobParams->printerName)) {
1489         PRINT_HILOGW("ResumePrinter fail");
1490     }
1491     uint32_t num_files = jobParams->fdList.size();
1492     PRINT_HILOGD("StartCupsJob fill job options, num_files: %{public}d", num_files);
1493     if (jobParams->isCanceled || !HandleFiles(jobParams, num_files, http, jobId)) {
1494         callback();
1495         return;
1496     }
1497     http_t *monitorHttp = nullptr;
1498     ippSetPort(CUPS_SEVER_PORT);
1499     monitorHttp = httpConnect2(cupsServer(), ippPort(), nullptr, AF_UNSPEC,
1500         HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, nullptr);
1501     if (monitorHttp == nullptr) {
1502         return;
1503     }
1504     jobParams->cupsJobId = jobId;
1505     PRINT_HILOGD("start job success, jobId: %{public}d", jobId);
1506     auto monitorParams = std::make_shared<JobMonitorParam>(jobParams->serviceAbility, jobParams->serviceJobId,
1507         jobId, jobParams->printerUri, jobParams->printerName, jobParams->printerId, monitorHttp);
1508     BuildMonitorPolicy(monitorParams);
1509     PRINT_HILOGD("MonitorJobState enter, cupsJobId: %{public}d", monitorParams->cupsJobId);
1510     monitorParams->jobOriginatingUserName = jobParams->jobOriginatingUserName;
1511     {
1512         std::lock_guard<std::mutex> lock(jobMonitorMutex_);
1513         if (jobMonitorList_.empty()) {
1514             jobMonitorList_.push_back(monitorParams);
1515             auto self = shared_from_this();
1516             std::thread startMonitotThread([self] { self->StartMonitor(); });
1517             startMonitotThread.detach();
1518         } else {
1519             jobMonitorList_.push_back(monitorParams);
1520         }
1521     }
1522     callback();
1523 }
1524 
BuildMonitorPolicy(std::shared_ptr<JobMonitorParam> monitorParams)1525 void PrintCupsClient::BuildMonitorPolicy(std::shared_ptr<JobMonitorParam> monitorParams)
1526 {
1527     if (monitorParams == nullptr) {
1528         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1529         return;
1530     }
1531     PrinterInfo addedPrinterInfo;
1532     if (PrintServiceAbility::GetInstance()->QueryPrinterInfoByPrinterId(monitorParams->printerId,
1533         addedPrinterInfo) != E_PRINT_NONE) {
1534         PRINT_HILOGW("printer make is empty, use default policy");
1535         return;
1536     }
1537     auto policyPair = SPECIAL_PRINTER_POLICY.find(addedPrinterInfo.GetPrinterMake());
1538     if (policyPair == SPECIAL_PRINTER_POLICY.end()) {
1539         PRINT_HILOGI("normal printer, use default policy");
1540         policyPair = SPECIAL_PRINTER_POLICY.find(DEFAULT_POLICY);
1541     }
1542     PRINT_HILOGI("special printer, update policy");
1543     int32_t index = 0;
1544     for (auto stateItem = FOLLOW_STATE_LIST.begin(); stateItem != FOLLOW_STATE_LIST.end(); stateItem++) {
1545         auto statePair = policyPair->second.find(stateItem->first);
1546         if (statePair != policyPair->second.end()) {
1547             monitorParams->policyArray[index] = statePair->second;
1548         }
1549         index++;
1550     }
1551 }
1552 
StartMonitor()1553 void PrintCupsClient::StartMonitor()
1554 {
1555     PRINT_HILOGI("state monitor start");
1556     ippSetPort(CUPS_SEVER_PORT);
1557     std::vector<std::shared_ptr<JobMonitorParam>> jobMonitorList;
1558     while (!jobMonitorList_.empty()) {
1559         uint64_t lastUpdateTime = GetNowTime();
1560         {
1561             std::lock_guard<std::mutex> lock(jobMonitorMutex_);
1562             jobMonitorList = jobMonitorList_;
1563         }
1564         for (auto monitorParams : jobMonitorList) {
1565             if (!IfContinueToHandleJobState(monitorParams)) {
1566                 PRINT_HILOGI("delete a completed job");
1567                 std::lock_guard<std::mutex> lock(jobMonitorMutex_);
1568                 auto item = find(jobMonitorList_.begin(), jobMonitorList_.end(), monitorParams);
1569                 jobMonitorList_.erase(item);
1570             }
1571         }
1572         uint64_t currentTime = GetNowTime();
1573         if (currentTime < lastUpdateTime + MONITOR_STEP_TIME_MS) {
1574             std::this_thread::sleep_for(std::chrono::milliseconds(lastUpdateTime + MONITOR_STEP_TIME_MS - currentTime));
1575         }
1576     }
1577     PRINT_HILOGI("jobMonitorList is empty, exit monitor");
1578 }
1579 
UpdatePrintJobStateInJobParams(JobParameters * jobParams,uint32_t state,uint32_t subState)1580 void PrintCupsClient::UpdatePrintJobStateInJobParams(JobParameters *jobParams, uint32_t state, uint32_t subState)
1581 {
1582     if (jobParams != nullptr && jobParams->serviceAbility != nullptr) {
1583         jobParams->serviceAbility->UpdatePrintJobState(jobParams->serviceJobId, state, subState);
1584     } else {
1585         PRINT_HILOGE("UpdatePrintJobStateInJobParams has nullptr parameter.");
1586     }
1587 }
1588 
IfContinueToHandleJobState(std::shared_ptr<JobMonitorParam> monitorParams)1589 bool PrintCupsClient::IfContinueToHandleJobState(std::shared_ptr<JobMonitorParam> monitorParams)
1590 {
1591     if (monitorParams == nullptr) {
1592         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1593         return false;
1594     }
1595     if (monitorParams->isCanceled) {
1596         PRINT_HILOGI("cancel job and stop monitor it");
1597         if (!CancelPrinterJob(monitorParams->cupsJobId, monitorParams->printerName,
1598             monitorParams->jobOriginatingUserName)) {
1599             PRINT_HILOGE("cancel Job Error");
1600             monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_COMPLETED,
1601                 PRINT_JOB_COMPLETED_CANCELLED);
1602             return false;
1603         }
1604     }
1605     if (monitorParams->isInterrupt) {
1606         PRINT_HILOGI("Interrupt job and stop monitor it");
1607         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_BLOCKED,
1608             PRINT_JOB_BLOCKED_INTERRUPT);
1609         return false;
1610     }
1611     return QueryJobStateAndCallback(monitorParams);
1612 }
1613 
QueryJobStateAndCallback(std::shared_ptr<JobMonitorParam> monitorParams)1614 bool PrintCupsClient::QueryJobStateAndCallback(std::shared_ptr<JobMonitorParam> monitorParams)
1615 {
1616     if (httpGetFd(monitorParams->http) < 0) {
1617         PRINT_HILOGE("http is nullptr");
1618         httpReconnect2(monitorParams->http, LONG_LONG_TIME_OUT, nullptr);
1619     }
1620     if (httpGetFd(monitorParams->http) < 0 || !CheckPrinterOnline(monitorParams)) {
1621         PRINT_HILOGE("unable connect to printer");
1622         if (monitorParams->serviceAbility == nullptr) {
1623             PRINT_HILOGE("serviceAbility is null");
1624             return false;
1625         }
1626         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_BLOCKED,
1627             PRINT_JOB_BLOCKED_OFFLINE);
1628         return true;
1629     }
1630     if (monitorParams->isFirstQueryState) {
1631         PRINT_HILOGD("skip first query state");
1632         monitorParams->isFirstQueryState = false;
1633         return true;
1634     }
1635     if (!QueryJobState(monitorParams->http, monitorParams)) {
1636         return true;
1637     }
1638     monitorParams->isPrinterStopped = IsPrinterStopped(monitorParams);
1639     ParseStateReasons(monitorParams);
1640     if (JobStatusCallback(monitorParams)) {
1641         PRINT_HILOGD("the job is processing");
1642         return true;
1643     }
1644     PRINT_HILOGI("the job is completed or canceled");
1645     return false;
1646 }
1647 
IsPrinterStopped(std::shared_ptr<JobMonitorParam> monitorParams)1648 bool PrintCupsClient::IsPrinterStopped(std::shared_ptr<JobMonitorParam> monitorParams)
1649 {
1650     if (monitorParams == nullptr) {
1651         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1652         return false;
1653     }
1654     PrinterStatus printerStatus = PRINTER_STATUS_BUSY;
1655     bool isPrinterStatusAvailable = QueryPrinterStatusByUri(monitorParams->printerUri, printerStatus) == E_PRINT_NONE;
1656     PRINT_HILOGD("is printer status available: %{public}d, state:%{public}d",
1657         isPrinterStatusAvailable, printerStatus);
1658     if (isPrinterStatusAvailable && printerStatus == PRINTER_STATUS_UNAVAILABLE) {
1659         return true;
1660     }
1661     return false;
1662 }
1663 
JobStatusCallback(std::shared_ptr<JobMonitorParam> monitorParams)1664 bool PrintCupsClient::JobStatusCallback(std::shared_ptr<JobMonitorParam> monitorParams)
1665 {
1666     if (monitorParams == nullptr) {
1667         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1668         return false;
1669     }
1670     PRINT_HILOGI("JOB %{public}d: %{public}s (%{public}s), PRINTER: %{public}s\n", monitorParams->cupsJobId,
1671         ippEnumString("job-state", (int)monitorParams->job_state), monitorParams->job_state_reasons,
1672         monitorParams->job_printer_state_reasons);
1673 
1674     if (monitorParams->job_state == IPP_JOB_PROCESSING) {
1675         if (!monitorParams->isBlock) {
1676             PRINT_HILOGI("job is running");
1677             monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1678                 PRINT_JOB_RUNNING, monitorParams->substate);
1679             return true;
1680         }
1681         PRINT_HILOGI("job is blocked");
1682         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1683             PRINT_JOB_BLOCKED, monitorParams->substate);
1684         return true;
1685     }
1686 
1687     if (monitorParams->job_state == IPP_JOB_PENDING || monitorParams->job_state == IPP_JOB_HELD) {
1688         PRINT_HILOGI("job is queued");
1689         if (monitorParams->job_state_reasons == JOB_STATE_REASON_PRINTER_STOP) {
1690             monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_BLOCKED,
1691                 PRINT_JOB_BLOCKED_PRINTER_UNAVAILABLE);
1692             return true;
1693         }
1694         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_QUEUED,
1695             PRINT_JOB_COMPLETED_SUCCESS);
1696         return true;
1697     }
1698 
1699     if (monitorParams->job_state == IPP_JOB_STOPPED) {
1700         if (CancelPrinterJob(monitorParams->cupsJobId)) {
1701             PRINT_HILOGI("cancel PrinterJob because stopped");
1702             return true;
1703         }
1704         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_COMPLETED,
1705             GetNewSubstate(monitorParams->substate, PRINT_JOB_COMPLETED_CANCELLED));
1706         return false;
1707     }
1708     return SpecialJobStatusCallback(monitorParams);
1709 }
1710 
SpecialJobStatusCallback(std::shared_ptr<JobMonitorParam> monitorParams)1711 bool PrintCupsClient::SpecialJobStatusCallback(std::shared_ptr<JobMonitorParam> monitorParams)
1712 {
1713     if (monitorParams == nullptr) {
1714         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1715         return false;
1716     }
1717 
1718     if (monitorParams->job_state == IPP_JOB_COMPLETED) {
1719         if (!monitorParams->isBlock) {
1720             PRINT_HILOGI("job complete success");
1721             monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1722                 PRINT_JOB_COMPLETED, PRINT_JOB_COMPLETED_SUCCESS);
1723             return false;
1724         }
1725         PRINT_HILOGI("job complete with error");
1726         if (monitorParams->timesOfSameState < STATE_UPDATE_STEP) {
1727             monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1728                 PRINT_JOB_BLOCKED, monitorParams->substate);
1729             return true;
1730         }
1731         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1732             PRINT_JOB_COMPLETED, PRINT_JOB_COMPLETED_SUCCESS);
1733         return false;
1734     }
1735 
1736     // IPP_JOB_CANCELED or IPP_JOB_ABORTED
1737     if (!monitorParams->isBlock) {
1738         PRINT_HILOGI("job is canceled");
1739         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_COMPLETED,
1740             PRINT_JOB_COMPLETED_CANCELLED);
1741         return false;
1742     }
1743     PRINT_HILOGI("job cancel with error");
1744     if (monitorParams->timesOfSameState < STATE_UPDATE_STEP) {
1745         monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId,
1746             PRINT_JOB_BLOCKED, monitorParams->substate);
1747         return true;
1748     }
1749     monitorParams->serviceAbility->UpdatePrintJobState(monitorParams->serviceJobId, PRINT_JOB_COMPLETED,
1750         PRINT_JOB_COMPLETED_CANCELLED);
1751     return false;
1752 }
1753 
ParseStateReasons(std::shared_ptr<JobMonitorParam> monitorParams)1754 void PrintCupsClient::ParseStateReasons(std::shared_ptr<JobMonitorParam> monitorParams)
1755 {
1756     if (monitorParams == nullptr) {
1757         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1758         return;
1759     }
1760     monitorParams->isBlock = monitorParams->isPrinterStopped;
1761     monitorParams->substate = 0;
1762     int32_t index = 0;
1763     for (auto stateItem = FOLLOW_STATE_LIST.begin(); stateItem != FOLLOW_STATE_LIST.end(); stateItem++) {
1764         monitorParams->isBlock |= GetBlockedAndUpdateSubstate(monitorParams, monitorParams->policyArray[index],
1765             stateItem->first, stateItem->second);
1766         index++;
1767     }
1768     if (monitorParams->isBlock && monitorParams->substate == 0) {
1769         monitorParams->substate = GetNewSubstate(monitorParams->substate, PRINT_JOB_BLOCKED_UNKNOWN);
1770     }
1771     PRINT_HILOGI("state reasons parse result: isblocked(%{public}d), substate(%{public}d)",
1772         monitorParams->isBlock, monitorParams->substate);
1773 }
1774 
GetBlockedAndUpdateSubstate(std::shared_ptr<JobMonitorParam> monitorParams,StatePolicy policy,std::string substateString,PrintJobSubState jobSubstate)1775 bool PrintCupsClient::GetBlockedAndUpdateSubstate(std::shared_ptr<JobMonitorParam> monitorParams, StatePolicy policy,
1776     std::string substateString, PrintJobSubState jobSubstate)
1777 {
1778     if (monitorParams == nullptr) {
1779         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1780         return true;
1781     }
1782     char* result = strstr(monitorParams->job_printer_state_reasons, substateString.c_str());
1783     if (result != nullptr) {
1784         PRINT_HILOGI("match %{public}s reason success", substateString.c_str());
1785         monitorParams->substate = GetNewSubstate(monitorParams->substate, jobSubstate);
1786         substateString.append(PRINTER_STATE_ERROR);
1787         if (strstr(monitorParams->job_printer_state_reasons, substateString.c_str()) != nullptr) {
1788             PRINT_HILOGD("error state reason");
1789             if (policy == STATE_POLICY_HINT) { return false; }
1790             if (policy == STATE_POLICY_DELAY && monitorParams->timesOfSameState == 0) { return false; }
1791             return true; // STATE_POLICY_STANDARD
1792         } else {
1793             PRINT_HILOGD("warning/report state reason");
1794             if (policy == STATE_POLICY_BLOCK) { return true; }
1795             return false; // STATE_POLICY_STANDARD
1796         }
1797     }
1798     return false;
1799 }
1800 
GetNewSubstate(uint32_t substate,PrintJobSubState singleSubstate)1801 uint32_t PrintCupsClient::GetNewSubstate(uint32_t substate, PrintJobSubState singleSubstate)
1802 {
1803     PRINT_HILOGD("add new substate(%{public}d) to substate(%{public}d)", singleSubstate, substate);
1804     return substate * NUMBER_FOR_SPLICING_SUBSTATE + singleSubstate;
1805 }
1806 
QueryJobState(http_t * http,std::shared_ptr<JobMonitorParam> monitorParams)1807 bool PrintCupsClient::QueryJobState(http_t *http, std::shared_ptr<JobMonitorParam> monitorParams)
1808 {
1809     ipp_t *request = nullptr; /* IPP request */
1810     ipp_t *response = nullptr; /* IPP response */
1811     int jattrsLen = 3;
1812     bool needUpdate = false;
1813     static const char * const jattrs[] = {
1814         "job-state",
1815         "job-state-reasons",
1816         "job-printer-state-reasons",
1817     };
1818     if (printAbility_ == nullptr) {
1819         PRINT_HILOGW("printAbility_ is null");
1820         return false;
1821     }
1822     if (http == nullptr || monitorParams == nullptr) {
1823         PRINT_HILOGE("QueryJobState monitorParams is null");
1824         return false;
1825     }
1826     if (monitorParams->cupsJobId > 0) {
1827         request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES);
1828         if (request == nullptr) {
1829             PRINT_HILOGE("Failed to create IPP request.");
1830             return false;
1831         }
1832         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr,
1833             monitorParams->printerUri.c_str());
1834         ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitorParams->cupsJobId);
1835         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr,
1836             monitorParams->jobOriginatingUserName.c_str());
1837         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", jattrsLen, nullptr, jattrs);
1838         PRINT_HILOGD("get job state from cups service: start");
1839         response = printAbility_->DoRequest(http, request, "/");
1840         if (response == nullptr) {
1841             PRINT_HILOGE("Failed to get response from CUPS service.");
1842             ippDelete(request);
1843             return false;
1844         }
1845         needUpdate = UpdateJobState(monitorParams, response);
1846         ippDelete(response);
1847     }
1848     return needUpdate;
1849 }
1850 
UpdateJobState(std::shared_ptr<JobMonitorParam> monitorParams,ipp_t * response)1851 bool PrintCupsClient::UpdateJobState(std::shared_ptr<JobMonitorParam> monitorParams, ipp_t *response)
1852 {
1853     if (monitorParams == nullptr) {
1854         PRINT_HILOGE("monitor job state failed, monitorParams is nullptr");
1855         return false;
1856     }
1857     ipp_attribute_t *attr = nullptr; /* Attribute in response */
1858     if (response == nullptr) {
1859         PRINT_HILOGE("Failed to get response from CUPS service.");
1860         return false;
1861     }
1862     ipp_jstate_t job_state = IPP_JOB_PENDING;
1863     char job_state_reasons[1024];
1864     char job_printer_state_reasons[1024];
1865     if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != nullptr) {
1866         job_state = (ipp_jstate_t)ippGetInteger(attr, 0);
1867     }
1868     if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != nullptr) {
1869         ippAttributeString(attr, job_state_reasons, sizeof(job_state_reasons));
1870     }
1871     if ((attr = ippFindAttribute(response, "job-printer-state-reasons", IPP_TAG_KEYWORD)) != nullptr) {
1872         ippAttributeString(attr, job_printer_state_reasons, sizeof(job_printer_state_reasons));
1873     }
1874     if (monitorParams->job_state == job_state &&
1875         strcmp(monitorParams->job_printer_state_reasons, job_printer_state_reasons) == 0) {
1876         monitorParams->timesOfSameState++;
1877         if (monitorParams->timesOfSameState % STATE_UPDATE_STEP != 0) {
1878             PRINT_HILOGD("the prevous jobState is the same as current, ignore");
1879             return false;
1880         } else {
1881             return true;
1882         }
1883     }
1884     monitorParams->timesOfSameState = -1;
1885     monitorParams->job_state = job_state;
1886     strlcpy(monitorParams->job_state_reasons, job_state_reasons, sizeof(monitorParams->job_state_reasons));
1887     strlcpy(monitorParams->job_printer_state_reasons, job_printer_state_reasons,
1888         sizeof(monitorParams->job_printer_state_reasons));
1889     return true;
1890 }
1891 
CheckPrinterOnline(std::shared_ptr<JobMonitorParam> monitorParams,const uint32_t timeout)1892 bool PrintCupsClient::CheckPrinterOnline(std::shared_ptr<JobMonitorParam> monitorParams, const uint32_t timeout)
1893 {
1894     http_t *http = nullptr;
1895     char scheme[32] = {0};
1896     char userpass[BUFFER_LEN] = {0};
1897     char host[BUFFER_LEN] = {0};
1898     char resource[BUFFER_LEN] = {0};
1899     int port = 0;
1900     if (monitorParams == nullptr) {
1901         PRINT_HILOGE("monitorParams is null");
1902         return false;
1903     }
1904     const char* printerUri = monitorParams->printerUri.c_str();
1905     const std::string printerId = monitorParams->printerId;
1906     PRINT_HILOGD("CheckPrinterOnline printerId: %{public}s", printerId.c_str());
1907     bool isUsbPrinter = monitorParams->printerUri.length() > USB_PRINTER.length() &&
1908                         monitorParams->printerUri.substr(INDEX_ZERO, INDEX_THREE) == USB_PRINTER;
1909     bool isVendorPrinter = strstr(printerId.c_str(), VENDOR_PPD_DRIVER.c_str()) != nullptr;
1910     bool isCustomizedExtension = !(PrintUtil::startsWith(printerId, SPOOLER_BUNDLE_NAME) ||
1911                                    PrintUtil::startsWith(printerId, VENDOR_MANAGER_PREFIX));
1912     if ((isUsbPrinter || isCustomizedExtension || isVendorPrinter) && monitorParams->serviceAbility != nullptr) {
1913         if (monitorParams->serviceAbility->QueryDiscoveredPrinterInfoById(printerId) == nullptr) {
1914             PRINT_HILOGI("printer offline");
1915             return false;
1916         } else {
1917             PRINT_HILOGI("printer online");
1918             return true;
1919         }
1920     } else {
1921         httpSeparateURI(HTTP_URI_CODING_ALL, printerUri, scheme, sizeof(scheme),
1922             userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource));
1923     }
1924     if (host[0] == '\0') {
1925         PRINT_HILOGE("host is empty");
1926         return false;
1927     }
1928     std::string nic;
1929     if (IsIpConflict(printerId, nic)) {
1930         http = httpConnect3(host, port, nullptr, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, timeout, nullptr,
1931             nic.c_str());
1932     } else {
1933         http = httpConnect2(host, port, nullptr, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, timeout, nullptr);
1934     }
1935     if (http == nullptr) {
1936         PRINT_HILOGE("httpConnect2 printer failed");
1937         return false;
1938     }
1939     httpClose(http);
1940     return true;
1941 }
1942 
ModifyCupsPrinterUri(const std::string & printerName,const std::string & printerUri)1943 bool PrintCupsClient::ModifyCupsPrinterUri(const std::string &printerName, const std::string &printerUri)
1944 {
1945     PRINT_HILOGI("ModifyCupsPrinterUri enter");
1946     if (printAbility_ == nullptr) {
1947         PRINT_HILOGW("printAbility_ is null");
1948         return false;
1949     }
1950     cups_dest_t *dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, printerName.c_str(), nullptr);
1951     if (dest == nullptr) {
1952         PRINT_HILOGW("failed to find printer");
1953         return false;
1954     }
1955     std::string standardUri = printerUri;
1956     const char *makeModel = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
1957     if (makeModel != nullptr) {
1958         PRINT_HILOGD("makeModel=%{public}s", makeModel);
1959         if (strstr(makeModel, BSUNI_PPD_NAME.c_str()) != nullptr) {
1960             standardUri = StandardizePrinterUri(printerUri, BSUNI_PPD_NAME);
1961         }
1962     }
1963     printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
1964     dest = nullptr;
1965 
1966     ipp_t *request = nullptr;
1967     char uri[HTTP_MAX_URI] = {0};
1968     ippSetPort(CUPS_SEVER_PORT);
1969     request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1970     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", nullptr, "localhost", 0, "/printers/%s",
1971                      printerName.c_str());
1972     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, uri);
1973     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
1974     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", nullptr, standardUri.c_str());
1975     ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
1976     printAbility_->FreeRequest(printAbility_->DoRequest(nullptr, request, "/admin/"));
1977     if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
1978         PRINT_HILOGE("modify printer error: %{public}s", cupsLastErrorString());
1979         return false;
1980     }
1981     PRINT_HILOGI("modify printer success");
1982     return true;
1983 }
1984 
CancelCupsJob(std::string serviceJobId)1985 void PrintCupsClient::CancelCupsJob(std::string serviceJobId)
1986 {
1987     PRINT_HILOGD("CancelCupsJob(): Enter, serviceJobId: %{public}s", serviceJobId.c_str());
1988     int jobIndex = -1;
1989     for (int index = 0; index < static_cast<int>(jobQueue_.size()); index++) {
1990         PRINT_HILOGD("jobQueue_[index]->serviceJobId: %{public}s", jobQueue_[index]->serviceJobId.c_str());
1991         if (jobQueue_[index]->serviceJobId == serviceJobId) {
1992             jobIndex = index;
1993             break;
1994         }
1995     }
1996     PRINT_HILOGI("jobIndex: %{public}d", jobIndex);
1997     if (jobIndex >= 0) {
1998         PRINT_HILOGI("job in queue, delete");
1999         JobParameters* erasedJob = jobQueue_.at(jobIndex);
2000         if (erasedJob != nullptr) {
2001             delete erasedJob;
2002         }
2003         jobQueue_.erase(jobQueue_.begin() + jobIndex);
2004         PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_COMPLETED,
2005             PRINT_JOB_COMPLETED_CANCELLED);
2006     } else {
2007         // job is processing
2008         if (currentJob_ != nullptr && currentJob_->serviceJobId == serviceJobId) { currentJob_->isCanceled = true; }
2009         std::lock_guard<std::mutex> lock(jobMonitorMutex_);
2010         auto cmp = [serviceJobId](std::shared_ptr<JobMonitorParam> monitorParams) {
2011             return (monitorParams != nullptr && monitorParams->serviceJobId == serviceJobId);
2012         };
2013         auto monitorItem = std::find_if(jobMonitorList_.begin(), jobMonitorList_.end(), cmp);
2014         if (monitorItem == jobMonitorList_.end()) {
2015             PRINT_HILOGW("job is not exist");
2016             PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_COMPLETED,
2017                 PRINT_JOB_COMPLETED_CANCELLED);
2018             return;
2019         }
2020         auto canceledMonitor = *monitorItem;
2021         canceledMonitor->isCanceled = true;
2022     }
2023 }
2024 
InterruptCupsJob(std::string serviceJobId)2025 void PrintCupsClient::InterruptCupsJob(std::string serviceJobId)
2026 {
2027     PRINT_HILOGD("InterruptCupsJob(): Enter, serviceJobId: %{public}s", serviceJobId.c_str());
2028     int jobIndex = -1;
2029     for (int index = 0; index < static_cast<int>(jobQueue_.size()); index++) {
2030         PRINT_HILOGD("jobQueue_[index]->serviceJobId: %{public}s", jobQueue_[index]->serviceJobId.c_str());
2031         if (jobQueue_[index]->serviceJobId == serviceJobId) {
2032             jobIndex = index;
2033             break;
2034         }
2035     }
2036     PRINT_HILOGI("jobIndex: %{public}d", jobIndex);
2037     if (jobIndex >= 0) {
2038         PRINT_HILOGI("job in queue, delete");
2039         JobParameters* erasedJob = jobQueue_.at(jobIndex);
2040         if (erasedJob != nullptr) {
2041             delete erasedJob;
2042         }
2043         jobQueue_.erase(jobQueue_.begin() + jobIndex);
2044         PrintServiceAbility::GetInstance()->UpdatePrintJobState(serviceJobId, PRINT_JOB_BLOCKED,
2045             PRINT_JOB_BLOCKED_INTERRUPT);
2046     } else {
2047         // job is processing
2048         if (currentJob_ != nullptr && currentJob_->serviceJobId == serviceJobId) {
2049             currentJob_->isCanceled = true;
2050         }
2051         std::lock_guard<std::mutex> lock(jobMonitorMutex_);
2052         auto cmp = [serviceJobId](std::shared_ptr<JobMonitorParam> monitorParams) {
2053             return (monitorParams != nullptr && monitorParams->serviceJobId == serviceJobId);
2054         };
2055         auto monitorItem = std::find_if(jobMonitorList_.begin(), jobMonitorList_.end(), cmp);
2056         if (monitorItem == jobMonitorList_.end()) {
2057             PRINT_HILOGW("job is not exist");
2058             return;
2059         }
2060         auto interruptMonitor = *monitorItem;
2061         if (!CancelPrinterJob(interruptMonitor->cupsJobId, interruptMonitor->printerName,
2062             interruptMonitor->jobOriginatingUserName)) {
2063             PRINT_HILOGE("cancel Job Error");
2064         }
2065         interruptMonitor->isInterrupt = true;
2066     }
2067 }
2068 
UpdateJobParameterByBoolOption(Json::Value & optionJson,JobParameters * params)2069 void PrintCupsClient::UpdateJobParameterByBoolOption(Json::Value& optionJson, JobParameters *params)
2070 {
2071     if (optionJson.isMember("isBorderless") && optionJson["isBorderless"].isBool()) {
2072         bool isBorderless = optionJson["isBorderless"].asBool();
2073         params->borderless = isBorderless ? TRUE : FALSE;
2074     } else {
2075         params->borderless = TRUE;
2076     }
2077 
2078     if (optionJson.isMember("isAutoRotate") && optionJson["isAutoRotate"].isBool()) {
2079         params->isAutoRotate = optionJson["isAutoRotate"].asBool();
2080     } else {
2081         // default autoRotate if option dont't contains it
2082         params->isAutoRotate = true;
2083     }
2084 
2085     if (optionJson.isMember("isReverse") && optionJson["isReverse"].isBool()) {
2086         params->isReverse = optionJson["isReverse"].asBool();
2087     } else {
2088         params->isReverse = false;
2089     }
2090 
2091     if (optionJson.isMember("isCollate") && optionJson["isCollate"].isBool()) {
2092         params->isCollate = optionJson["isCollate"].asBool();
2093     } else {
2094         params->isCollate = true;
2095     }
2096 }
2097 
UpdateJobParameterByOption(Json::Value & optionJson,JobParameters * params)2098 void PrintCupsClient::UpdateJobParameterByOption(Json::Value& optionJson, JobParameters *params)
2099 {
2100     if (optionJson.isMember("cupsOptions") && optionJson["cupsOptions"].isString()) {
2101         params->printerAttrsOptionCupsOption = optionJson["cupsOptions"].asString();
2102     }
2103 
2104     if (optionJson.isMember("printQuality") && optionJson["printQuality"].isString()) {
2105         params->printQuality = optionJson["printQuality"].asString();
2106     } else {
2107         params->printQuality = CUPS_PRINT_QUALITY_NORMAL;
2108     }
2109 
2110     if (optionJson.isMember("jobName") && optionJson["jobName"].isString()) {
2111         params->jobName = optionJson["jobName"].asString();
2112     } else {
2113         params->jobName = DEFAULT_JOB_NAME;
2114     }
2115 
2116     if (optionJson.isMember("mediaType") && optionJson["mediaType"].isString()) {
2117         params->mediaType = optionJson["mediaType"].asString();
2118     } else {
2119         params->mediaType = CUPS_MEDIA_TYPE_PLAIN;
2120     }
2121 
2122     UpdateJobParameterByBoolOption(optionJson, params);
2123 
2124     if (PrintJsonUtil::IsMember(optionJson, "advancedOptions") && optionJson["advancedOptions"].isObject()) {
2125         params->advancedOpsJson = optionJson["advancedOptions"];
2126     }
2127 }
2128 
BuildJobParameters(const PrintJob & jobInfo,const std::string & userName)2129 JobParameters* PrintCupsClient::BuildJobParameters(const PrintJob &jobInfo, const std::string &userName)
2130 {
2131     JobParameters *params = nullptr;
2132     if (!jobInfo.HasOption()) {
2133         PRINT_HILOGE("option is empty");
2134         return params;
2135     }
2136     std::string option = jobInfo.GetOption();
2137     Json::Value optionJson;
2138     if (!PrintJsonUtil::Parse(option, optionJson)) {
2139         PRINT_HILOGE("option can not parse to json object");
2140         return params;
2141     }
2142     PRINT_HILOGD("test optionJson: %{private}s", (PrintJsonUtil::WriteString(optionJson)).c_str());
2143     if (!PrintJsonUtil::IsMember(optionJson, "printerUri") || !optionJson["printerUri"].isString() ||
2144         !PrintJsonUtil::IsMember(optionJson, "printerName") || !optionJson["printerName"].isString() ||
2145         !PrintJsonUtil::IsMember(optionJson, "documentFormat") || !optionJson["documentFormat"].isString()) {
2146         PRINT_HILOGE("The option does not have a necessary attribute.");
2147         return params;
2148     }
2149     params = new (std::nothrow) JobParameters {};
2150     if (params == nullptr) {
2151         PRINT_HILOGE("new JobParameters returns nullptr");
2152         return params;
2153     }
2154     jobInfo.DupFdList(params->fdList);
2155     params->serviceJobId = jobInfo.GetJobId();
2156     params->numCopies = jobInfo.GetCopyNumber();
2157     params->duplex = GetDulpexString(jobInfo.GetDuplexMode());
2158     params->jobOriginatingUserName = userName;
2159     params->mediaSize = GetMedieSize(jobInfo);
2160     params->color = GetColorString(jobInfo.GetColorMode());
2161     params->printerId = jobInfo.GetPrinterId();
2162     params->printerName = PrintUtil::StandardizePrinterName(optionJson["printerName"].asString());
2163     params->printerUri = optionJson["printerUri"].asString();
2164     params->documentFormat = optionJson["documentFormat"].asString();
2165     params->isLandscape = jobInfo.GetIsLandscape();
2166     UpdateJobParameterByOption(optionJson, params);
2167     params->serviceAbility = PrintServiceAbility::GetInstance();
2168     return params;
2169 }
2170 
DumpJobParameters(JobParameters * jobParams)2171 void PrintCupsClient::DumpJobParameters(JobParameters* jobParams)
2172 {
2173     if (jobParams == nullptr) {
2174         PRINT_HILOGE("DumpJobParameters fail.");
2175         return;
2176     }
2177     PRINT_HILOGD("jobParams->serviceJobId: %{public}s", jobParams->serviceJobId.c_str());
2178     PRINT_HILOGD("jobParams->borderless: %{public}d", jobParams->borderless);
2179     PRINT_HILOGD("jobParams->numCopies: %{public}d", jobParams->numCopies);
2180     PRINT_HILOGD("jobParams->duplex: %{public}s", jobParams->duplex.c_str());
2181     PRINT_HILOGD("jobParams->printQuality: %{public}s", jobParams->printQuality.c_str());
2182     PRINT_HILOGD("jobParams->jobName: %{public}s", jobParams->jobName.c_str());
2183     PRINT_HILOGD("jobParams->jobOriginatingUserName: %{public}s", jobParams->jobOriginatingUserName.c_str());
2184     PRINT_HILOGD("jobParams->printerId: %{private}s", jobParams->printerId.c_str());
2185     PRINT_HILOGD("jobParams->printerName: %{private}s", jobParams->printerName.c_str());
2186     PRINT_HILOGD("jobParams->printerUri: %{private}s", jobParams->printerUri.c_str());
2187     PRINT_HILOGD("jobParams->documentFormat: %{public}s", jobParams->documentFormat.c_str());
2188     PRINT_HILOGD("jobParams->mediaSize: %{public}s", jobParams->mediaSize.c_str());
2189     PRINT_HILOGD("jobParams->mediaType: %{public}s", jobParams->mediaType.c_str());
2190     PRINT_HILOGD("jobParams->color: %{public}s", jobParams->color.c_str());
2191     PRINT_HILOGD("jobParams->isLandscape: %{public}d", jobParams->isLandscape);
2192     PRINT_HILOGD("jobParams->isAutoRotate: %{public}d", jobParams->isAutoRotate);
2193     PRINT_HILOGD("jobParams->isReverse: %{public}d", jobParams->isReverse);
2194     PRINT_HILOGD("jobParams->isCollate: %{public}d", jobParams->isCollate);
2195     PRINT_HILOGD("jobParams->printerAttrsOptionCupsOption: %{public}s",
2196         jobParams->printerAttrsOptionCupsOption.c_str());
2197 }
2198 
2199 
GetMedieSize(const PrintJob & jobInfo)2200 std::string PrintCupsClient::GetMedieSize(const PrintJob &jobInfo)
2201 {
2202     PrintPageSize pageSize;
2203     jobInfo.GetPageSize(pageSize);
2204     return pageSize.GetName();
2205 }
2206 
GetDulpexString(uint32_t duplexCode)2207 std::string PrintCupsClient::GetDulpexString(uint32_t duplexCode)
2208 {
2209     DuplexModeCode duplex = static_cast<DuplexModeCode>(duplexCode);
2210     switch (duplex) {
2211         case DUPLEX_MODE_ONE_SIDED:
2212             return CUPS_SIDES_ONE_SIDED;
2213         case DUPLEX_MODE_TWO_SIDED_LONG_EDGE:
2214             return CUPS_SIDES_TWO_SIDED_PORTRAIT;
2215         case DUPLEX_MODE_TWO_SIDED_SHORT_EDGE:
2216             return CUPS_SIDES_TWO_SIDED_LANDSCAPE;
2217         default:
2218             return CUPS_SIDES_ONE_SIDED;
2219     }
2220 }
2221 
GetColorString(uint32_t colorCode)2222 std::string PrintCupsClient::GetColorString(uint32_t colorCode)
2223 {
2224     ColorModeCode color = static_cast<ColorModeCode>(colorCode);
2225     switch (color) {
2226         case COLOR_MODE_MONOCHROME:
2227             return CUPS_PRINT_COLOR_MODE_MONOCHROME;
2228         case COLOR_MODE_COLOR:
2229             return CUPS_PRINT_COLOR_MODE_COLOR;
2230         default:
2231             return CUPS_PRINT_COLOR_MODE_AUTO;
2232     }
2233 }
2234 
IsCupsServerAlive()2235 bool PrintCupsClient::IsCupsServerAlive()
2236 {
2237     http_t *http = nullptr;
2238     ippSetPort(CUPS_SEVER_PORT);
2239     http = httpConnect2(cupsServer(), ippPort(), nullptr, AF_UNSPEC,
2240         HTTP_ENCRYPTION_IF_REQUESTED, 1, LONG_TIME_OUT, nullptr);
2241     if (http == nullptr) {
2242         PRINT_HILOGE("cups server is not alive");
2243         return false;
2244     }
2245     httpClose(http);
2246     return true;
2247 }
2248 
2249 /**
2250  * @brief check printer is exist
2251  * @param printerName printer name
2252  * @return true printer exist
2253  * @return false printer is not exist
2254  */
IsPrinterExist(const char * printerUri,const char * standardPrinterName,const char * ppdName)2255 bool PrintCupsClient::IsPrinterExist(const char *printerUri, const char *standardPrinterName, const char *ppdName)
2256 {
2257     bool printerExist = false;
2258     cups_dest_t *dest;
2259     PRINT_HILOGD("IsPrinterExist enter");
2260     if (printAbility_ == nullptr) {
2261         PRINT_HILOGW("printAbility_ is null");
2262         return printerExist;
2263     }
2264     dest = printAbility_->GetNamedDest(CUPS_HTTP_DEFAULT, standardPrinterName, nullptr);
2265     if (dest != nullptr) {
2266         const char *deviceUri = cupsGetOption("device-uri", dest->num_options, dest->options);
2267         if (deviceUri == nullptr) {
2268             PRINT_HILOGD("deviceUri is null");
2269             return false;
2270         }
2271         PRINT_HILOGD("deviceUri=%{private}s", deviceUri);
2272         const char *makeModel = cupsGetOption("printer-make-and-model", dest->num_options, dest->options);
2273         if (makeModel == nullptr) {
2274             PRINT_HILOGD("makeModel is null");
2275             return false;
2276         }
2277         PRINT_HILOGD("makeModel=%{private}s", makeModel);
2278         int printerState = cupsGetIntegerOption("printer-state", dest->num_options, dest->options);
2279         PRINT_HILOGD("printerState=%{private}d", printerState);
2280         if (printerState == IPP_PRINTER_STOPPED || makeModel == nullptr || strcmp(deviceUri, printerUri) != 0) {
2281             printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
2282             PRINT_HILOGI("Printer information needs to be modified");
2283             return printerExist;
2284         }
2285         if (strcmp(ppdName, DEFAULT_PPD_NAME.c_str()) == 0) {
2286             // find everywhere or remote printr driver
2287             printerExist = (strstr(makeModel, DEFAULT_MAKE_MODEL.c_str()) != nullptr) ||
2288                            (strstr(makeModel, REMOTE_PRINTER_MAKE_MODEL.c_str()) != nullptr);
2289         } else if (strcmp(ppdName, BSUNI_PPD_NAME.c_str()) == 0) {
2290             printerExist = (strstr(makeModel, BSUNI_PPD_NAME.c_str()) != nullptr);
2291         } else {
2292             // vendor ppd need to be checked
2293             if (!PrintServiceAbility::GetInstance()->IsPrinterPpdUpdateRequired(standardPrinterName,
2294                 GetPpdHashCode(ppdName))) {
2295                 printerExist = true;
2296                 PRINT_HILOGD("no need to update ppd");
2297             }
2298         }
2299         printAbility_->FreeDests(FREE_ONE_PRINTER, dest);
2300     }
2301     return printerExist;
2302 }
2303 
ConvertInchTo100MM(float num)2304 float PrintCupsClient::ConvertInchTo100MM(float num)
2305 {
2306     return ((num / THOUSAND_INCH) * CONVERSION_UNIT);
2307 }
2308 
IsIpConflict(const std::string & printerId,std::string & nic)2309 bool PrintCupsClient::IsIpConflict(const std::string &printerId, std::string &nic) __attribute__((no_sanitize("cfi")))
2310 {
2311     if (printerId.find(P2P_PRINTER) == std::string::npos) {
2312         PRINT_HILOGD("The printer is not p2p: %{private}s", printerId.c_str());
2313         return false;
2314     }
2315     bool isWifiConnected = false;
2316     auto wifiDevice = Wifi::WifiDevice::GetInstance(OHOS::WIFI_DEVICE_SYS_ABILITY_ID);
2317     if (!wifiDevice) {
2318         PRINT_HILOGE("wifiDevice GetInstance failed.");
2319         return false;
2320     }
2321     wifiDevice->IsConnected(isWifiConnected);
2322     PRINT_HILOGD("isWifiConnected: %{public}d", isWifiConnected);
2323     Wifi::WifiP2pLinkedInfo p2pLinkedInfo;
2324     Wifi::WifiP2p::GetInstance(OHOS::WIFI_P2P_SYS_ABILITY_ID)->QueryP2pLinkedInfo(p2pLinkedInfo);
2325     PRINT_HILOGD("P2pConnectedState: %{public}d", p2pLinkedInfo.GetConnectState());
2326     if (isWifiConnected && p2pLinkedInfo.GetConnectState() == Wifi::P2pConnectedState::P2P_CONNECTED) {
2327         Wifi::IpInfo info;
2328         auto wifiDevice = Wifi::WifiDevice::GetInstance(OHOS::WIFI_DEVICE_SYS_ABILITY_ID);
2329         if (!wifiDevice) {
2330             PRINT_HILOGE("wifiDevice GetInstance failed.");
2331             return false;
2332         }
2333         wifiDevice->GetIpInfo(info);
2334         PRINT_HILOGD("wifi server ip: %{private}s", GetIpAddress(info.serverIp).c_str());
2335         PRINT_HILOGD("p2p go ip: %{private}s", p2pLinkedInfo.GetGroupOwnerAddress().c_str());
2336         if (GetIpAddress(info.serverIp) == p2pLinkedInfo.GetGroupOwnerAddress()) {
2337             Wifi::WifiP2pGroupInfo group;
2338             Wifi::WifiP2p::GetInstance(OHOS::WIFI_P2P_SYS_ABILITY_ID)->GetCurrentGroup(group);
2339             nic = group.GetInterface();
2340             PRINT_HILOGI("The P2P ip conflicts with the wlan ip, p2p nic: %{public}s", nic.c_str());
2341             return true;
2342         }
2343     }
2344     return false;
2345 }
2346 
GetIpAddress(unsigned int number)2347 std::string PrintCupsClient::GetIpAddress(unsigned int number)
2348 {
2349     unsigned int ip3 = (number << IP_RIGHT_SHIFT_0) >> IP_RIGHT_SHIFT_24;
2350     unsigned int ip2 = (number << IP_RIGHT_SHIFT_8) >> IP_RIGHT_SHIFT_24;
2351     unsigned int ip1 = (number << IP_RIGHT_SHIFT_16) >> IP_RIGHT_SHIFT_24;
2352     unsigned int ip0 = (number << IP_RIGHT_SHIFT_24) >> IP_RIGHT_SHIFT_24;
2353     return std::to_string(ip3) + "." + std::to_string(ip2) + "." + std::to_string(ip1) + "." + std::to_string(ip0);
2354 }
2355 
DiscoverUsbPrinters(std::vector<PrinterInfo> & printers)2356 int32_t PrintCupsClient::DiscoverUsbPrinters(std::vector<PrinterInfo> &printers)
2357 {
2358     int longStatus = 0;
2359     const char* include_schemes = CUPS_INCLUDE_ALL;
2360     const char* exclude_schemes = CUPS_EXCLUDE_NONE;
2361     int timeout = CUPS_TIMEOUT_DEFAULT;
2362     PRINT_HILOGD("DiscoverUsbPrinters cupsGetDevices");
2363     ClearUsbPrinters();
2364     if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes, exclude_schemes,
2365         DeviceCb, &longStatus) != IPP_OK) {
2366         PRINT_HILOGE("lpinfo error : %{public}s", cupsLastErrorString());
2367         return E_PRINT_SERVER_FAILURE;
2368     }
2369     printers = GetUsbPrinters();
2370     return E_PRINT_NONE;
2371 }
2372 
DiscoverBackendPrinters(std::vector<PrinterInfo> & printers)2373 int32_t PrintCupsClient::DiscoverBackendPrinters(std::vector<PrinterInfo> &printers)
2374 {
2375     int longStatus = 0;
2376     const char* include_schemes = CUPS_INCLUDE_ALL;
2377     const char* exclude_schemes = CUPS_EXCLUDE_NONE;
2378     int timeout = CUPS_TIMEOUT_DEFAULT;
2379     PRINT_HILOGD("DiscoverBackendPrinters cupsGetDevices");
2380     ClearBackendPrinters();
2381     if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes, exclude_schemes,
2382         DeviceCb, &longStatus) != IPP_OK) {
2383         PRINT_HILOGE("lpinfo error : %{public}s", cupsLastErrorString());
2384         return E_PRINT_SERVER_FAILURE;
2385     }
2386     printers = GetBackendPrinters();
2387     return E_PRINT_NONE;
2388 }
2389 
ResumePrinter(const std::string & printerName)2390 bool PrintCupsClient::ResumePrinter(const std::string &printerName)
2391 {
2392     if (printAbility_ == nullptr) {
2393         PRINT_HILOGE("printAbility is null");
2394         return false;
2395     }
2396     ipp_t *request = nullptr;
2397     char uri[HTTP_MAX_URI] = {0};
2398     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", nullptr, "localhost", 0, "/printers/%s",
2399                      printerName.c_str());
2400     request = ippNewRequest(IPP_OP_RESUME_PRINTER);
2401     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr, uri);
2402     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", nullptr, cupsUser());
2403     PRINT_HILOGD("IPP_OP_RESUME_PRINTER cupsDoRequest");
2404     ippDelete(printAbility_->DoRequest(nullptr, request, "/admin/"));
2405     if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
2406         PRINT_HILOGE("resume printer error: %{public}s", cupsLastErrorString());
2407         return false;
2408     }
2409     PRINT_HILOGI("resume printer success");
2410     return true;
2411 }
2412 
CancelPrinterJob(int cupsJobId)2413 bool PrintCupsClient::CancelPrinterJob(int cupsJobId)
2414 {
2415     char job_uri[1024];
2416     httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", nullptr,
2417                      "localhost", 0, "/jobs/%d", cupsJobId);
2418     PRINT_HILOGE("cancel job_uri: %s", job_uri);
2419     ipp_t *cancel_request = ippNewRequest(IPP_OP_CANCEL_JOB);
2420     ippAddString(cancel_request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", nullptr, job_uri);
2421     ippDelete(printAbility_->DoRequest(nullptr, cancel_request, "/admin/"));
2422     if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) {
2423         PRINT_HILOGE("cancel printJob error: %{public}s", cupsLastErrorString());
2424         return false;
2425     }
2426     PRINT_HILOGI("cancel printJob success");
2427     return true;
2428 }
2429 
CancelPrinterJob(int cupsJobId,const std::string & name,const std::string & user)2430 bool PrintCupsClient::CancelPrinterJob(int cupsJobId, const std::string &name, const std::string &user)
2431 {
2432     ipp_t *request = ippNewRequest(IPP_OP_CANCEL_JOB);
2433     char uri[HTTP_MAX_URI] = {0};
2434     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s",
2435                      name.c_str());
2436     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
2437     ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", cupsJobId);
2438     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, user.c_str());
2439     ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs/"));
2440     if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) {
2441         PRINT_HILOGW("Cancel of job %{public}d failed: %{public}s", cupsJobId, cupsLastErrorString());
2442         return false;
2443     } else {
2444         PRINT_HILOGI("Job %{public}d canceled", cupsJobId);
2445         return true;
2446     }
2447 }
2448 
IsIpAddress(const char * host)2449 bool PrintCupsClient::IsIpAddress(const char* host)
2450 {
2451     if (host == NULL) {
2452         PRINT_HILOGW("host is null");
2453         return false;
2454     }
2455     struct in_addr addr4;
2456     struct in6_addr addr6;
2457     if ((inet_pton(AF_INET, host, &addr4) == 1) ||
2458         (inet_pton(AF_INET6, host, &addr6) == 1)) {
2459         return true;
2460     } else {
2461         PRINT_HILOGW("not ipv4 or ipv6");
2462         return false;
2463     }
2464 }
2465 
GetPpdHashCode(const std::string & ppdName)2466 std::string PrintCupsClient::GetPpdHashCode(const std::string& ppdName)
2467 {
2468     std::string ppdFilePath = GetCurCupsRootDir() + "/datadir/model/" + ppdName;
2469 
2470     std::ifstream file(ppdFilePath, std::ios::binary | std::ios::ate);
2471     if (!file.is_open()) {
2472         PRINT_HILOGE("ppd %{private}s open failed", ppdName.c_str());
2473         return "";
2474     }
2475 
2476     std::streamsize size = file.tellg();
2477     file.seekg(0, std::ios::beg);
2478 
2479     std::vector<char> buffer(size);
2480     if (!file.read(buffer.data(), size)) {
2481         PRINT_HILOGE("ppd %{private}s read failed", ppdName.c_str());
2482         return "";
2483     }
2484 
2485     int32_t HASH_BUFFER_SIZE = 32;
2486     unsigned char hash[HASH_BUFFER_SIZE];
2487     size_t hashSize = sizeof(hash);
2488 
2489     const char* HASH_ALGORITHM = "sha2-256";
2490     ssize_t result = cupsHashData(HASH_ALGORITHM, buffer.data(), size, hash, hashSize);
2491     if (result <= 0) {
2492         PRINT_HILOGE("cupsHashData fail, ret = %{public}d", result);
2493         return "";
2494     }
2495 
2496     std::ostringstream oss;
2497     constexpr int32_t HEX_STRING_WIDTH = 2;
2498     oss << std::hex << std::setfill('0');
2499     for (int i = 0; i < result; ++i) {
2500         oss << std::setw(HEX_STRING_WIDTH) << static_cast<unsigned>(hash[i]);
2501     }
2502     return oss.str();
2503 }
2504 
2505 }