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