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