1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 * Copyright (C) 2016 Mopria Alliance, Inc.
4 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "lib_wprint.h"
20 #include "cups.h"
21 #include "http-private.h"
22 #include "ipphelper.h"
23 #include "wprint_debug.h"
24
25 #include "ipp_print.h"
26 #include "../plugins/media.h"
27
28 #define TAG "ipphelper"
29
30 /*
31 * Get the IPP version of the given printer
32 */
33 static status_t determine_ipp_version(char *, http_t *);
34
35 /*
36 * Tests IPP versions and sets it to the latest working version
37 */
38 static status_t test_and_set_ipp_version(char *, http_t *, int, int);
39
40 /*
41 * Parses supported IPP versions from the IPP response and copies them into ippVersions
42 */
43 static void parse_IPPVersions(ipp_t *response, ipp_version_supported_t *ippVersions);
44
45 /*
46 * Parses printer URIs from the IPP response and copies them into capabilities
47 */
48 static void parse_printerUris(ipp_t *response, printer_capabilities_t *capabilities);
49
50 /*
51 * Known media sizes.
52 *
53 * A note on rounding: In some cases the Android-specified width (in mils) is rounded down.
54 * This causes artifacts in libjpeg-turbo when rendering to the correct width, so in these
55 * cases we override with a rounded-up value.
56 */
57 struct MediaSizeTableElement SupportedMediaSizes[SUPPORTED_MEDIA_SIZE_COUNT] = {
58 { US_LETTER, "LETTER", 8500, 11000, UNKNOWN_VALUE, UNKNOWN_VALUE, "na_letter_8.5x11in" },
59 { US_LEGAL, "LEGAL", 8500, 14000, UNKNOWN_VALUE, UNKNOWN_VALUE, "na_legal_8.5x14in" },
60 { LEDGER, "LEDGER", 11000, 17000, UNKNOWN_VALUE, UNKNOWN_VALUE, "na_ledger_11x17in" },
61 { INDEX_CARD_5X7, "5X7", 5000, 7000, UNKNOWN_VALUE, UNKNOWN_VALUE, "na_5x7_5x7in" },
62
63 // Android system uses width of 11690
64 { ISO_A3, "A3", 11694, 16540, 297, 420, "iso_a3_297x420mm" },
65
66 // Android system uses width of 8267
67 { ISO_A4, "A4", 8268, 11692, 210, 297, "iso_a4_210x297mm" },
68 { ISO_A5, "A5", 5830, 8270, 148, 210, "iso_a5_148x210mm" },
69
70 // Android system uses width of 10118
71 { JIS_B4, "JIS B4", 10119, 14331, 257, 364, "jis_b4_257x364mm" },
72
73 // Android system uses width of 7165
74 { JIS_B5, "JIS B5", 7167, 10118, 182, 257, "jis_b5_182x257mm" },
75 { US_GOVERNMENT_LETTER, "8x10", 8000, 10000, UNKNOWN_VALUE, UNKNOWN_VALUE,
76 "na_govt-letter_8x10in" },
77 { INDEX_CARD_4X6, "4x6", 4000, 6000, UNKNOWN_VALUE, UNKNOWN_VALUE, "na_index-4x6_4x6in" },
78 { JPN_HAGAKI_PC, "JPOST", 3940, 5830, 100, 148, "jpn_hagaki_100x148mm" },
79 { PHOTO_89X119, "89X119", 3504, 4685, 89, 119, "om_dsc-photo_89x119mm" },
80 { CARD_54X86, "54X86", 2126, 3386, 54, 86, "om_card_54x86mm" },
81 { OE_PHOTO_L, "L", 3500, 5000, UNKNOWN_VALUE, UNKNOWN_VALUE, "oe_photo-l_3.5x5in" }
82 };
83
84 typedef struct {
85 double Lower;
86 double Upper;
87 } media_dimension_mm_t;
88
89 static const char *__request_ipp_version[] = {"ipp-versions-supported"};
90
91 static int __ipp_version_major = 2;
92 static int __ipp_version_minor = 0;
93
set_ipp_version(ipp_t * op_to_set,char * printer_uri,http_t * http,ipp_version_state use_existing_version)94 status_t set_ipp_version(ipp_t *op_to_set, char *printer_uri, http_t *http,
95 ipp_version_state use_existing_version) {
96 LOGD("set_ipp_version(): Enter %d", use_existing_version);
97 if (op_to_set == NULL) {
98 return ERROR;
99 }
100 switch (use_existing_version) {
101 case NEW_REQUEST_SEQUENCE:
102 __ipp_version_major = 2;
103 __ipp_version_minor = 0;
104 break;
105 case IPP_VERSION_RESOLVED:
106 break;
107 case IPP_VERSION_UNSUPPORTED:
108 if (determine_ipp_version(printer_uri, http) != 0) {
109 return ERROR;
110 }
111 break;
112 }
113 ippSetVersion(op_to_set, __ipp_version_major, __ipp_version_minor);
114 LOGD("set_ipp_version(): Done");
115 return OK;
116 }
117
determine_ipp_version(char * printer_uri,http_t * http)118 static status_t determine_ipp_version(char *printer_uri, http_t *http) {
119 LOGD("determine_ipp_version(): Enter printer_uri = %s", printer_uri);
120
121 if (http == NULL) {
122 LOGE("determine_ipp_version(): http is NULL cannot continue");
123 return ERROR;
124 }
125 if ((test_and_set_ipp_version(printer_uri, http, 1, 1) == OK)
126 || (test_and_set_ipp_version(printer_uri, http, 1, 0) == OK)
127 || (test_and_set_ipp_version(printer_uri, http, 2, 0) == OK)) {
128 LOGD("successfully set ipp version.");
129 } else {
130 LOGD("could not get ipp version using any known ipp version.");
131 return ERROR;
132 }
133 return OK;
134 }
135
test_and_set_ipp_version(char * printer_uri,http_t * http,int major,int minor)136 static status_t test_and_set_ipp_version(char *printer_uri, http_t *http, int major, int minor) {
137 status_t return_value = ERROR;
138 int service_unavailable_retry_count = 0;
139 int bad_request_retry_count = 0;
140 ipp_t *request = NULL;
141 ipp_t *response;
142 ipp_version_supported_t ippVersions;
143 char http_resource[1024];
144 int op = IPP_GET_PRINTER_ATTRIBUTES;
145
146 LOGD("test_and_set_ipp_version(): Enter %d - %d", major, minor);
147 memset(&ippVersions, 0, sizeof(ipp_version_supported_t));
148 getResourceFromURI(printer_uri, http_resource, 1024);
149 do {
150 request = ippNewRequest(op);
151 ippSetVersion(request, major, minor);
152 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri);
153 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes",
154 sizeof(__request_ipp_version) / sizeof(__request_ipp_version[0]),
155 NULL, __request_ipp_version);
156 if ((response = cupsDoRequest(http, request, http_resource)) == NULL) {
157 ipp_status_t ipp_status = cupsLastError();
158 LOGD("test_and_set_ipp_version: response is null: ipp_status %d %s",
159 ipp_status, ippErrorString(ipp_status));
160 if (ipp_status == IPP_INTERNAL_ERROR) {
161 LOGE("test_and_set_ipp_version: 1280 received, bailing...");
162 break;
163 } else if ((ipp_status == IPP_SERVICE_UNAVAILABLE) &&
164 (service_unavailable_retry_count < IPP_SERVICE_ERROR_MAX_RETRIES)) {
165 LOGE("test_and_set_ipp_version: 1282 received, retrying %d of %d",
166 service_unavailable_retry_count, IPP_SERVICE_ERROR_MAX_RETRIES);
167 service_unavailable_retry_count++;
168 continue;
169 } else if (ipp_status == IPP_BAD_REQUEST) {
170 LOGE("test_and_set_ipp_version: IPP_Status of IPP_BAD_REQUEST "
171 "received. retry (%d) of (%d)", bad_request_retry_count,
172 IPP_BAD_REQUEST_MAX_RETRIES);
173 if (bad_request_retry_count > IPP_BAD_REQUEST_MAX_RETRIES) {
174 break;
175 }
176 bad_request_retry_count++;
177 continue;
178 } else if (ipp_status == IPP_NOT_FOUND) {
179 LOGE("test_and_set_ipp_version: IPP_Status of IPP_NOT_FOUND received");
180 break;
181 }
182 return_value = ERROR;
183 } else {
184 ipp_status_t ipp_status = cupsLastError();
185 LOGD("ipp CUPS last ERROR: %d, %s", ipp_status, ippErrorString(ipp_status));
186 if (ipp_status == IPP_BAD_REQUEST) {
187 LOGD("IPP_Status of IPP_BAD_REQUEST received. retry (%d) of (%d)",
188 bad_request_retry_count, IPP_BAD_REQUEST_MAX_RETRIES);
189 if (bad_request_retry_count > IPP_BAD_REQUEST_MAX_RETRIES) {
190 break;
191 }
192 bad_request_retry_count++;
193 ippDelete(response);
194 continue;
195 }
196
197 parse_IPPVersions(response, &ippVersions);
198 if (ippVersions.supportsIpp20) {
199 __ipp_version_major = 2;
200 __ipp_version_minor = 0;
201 return_value = OK;
202 LOGD("test_and_set_ipp_version(): ipp version set to %d,%d",
203 __ipp_version_major, __ipp_version_minor);
204 } else if (ippVersions.supportsIpp11) {
205 __ipp_version_major = 1;
206 __ipp_version_minor = 1;
207 return_value = OK;
208 LOGD("test_and_set_ipp_version(): ipp version set to %d,%d",
209 __ipp_version_major, __ipp_version_minor);
210 } else if (ippVersions.supportsIpp10) {
211 __ipp_version_major = 1;
212 __ipp_version_minor = 0;
213 return_value = OK;
214 LOGD("test_and_set_ipp_version(): ipp version set to %d,%d",
215 __ipp_version_major, __ipp_version_minor);
216 } else {
217 LOGD("test_and_set_ipp_version: ipp version not found");
218 return_value = ERROR;
219 }
220 }
221 if (response != NULL) ippDelete(response);
222 break;
223 } while (1);
224 return return_value;
225 }
226
get_PrinterState(http_t * http,char * printer_uri,printer_state_dyn_t * printer_state_dyn,ipp_pstate_t * printer_state)227 ipp_status_t get_PrinterState(http_t *http, char *printer_uri,
228 printer_state_dyn_t *printer_state_dyn, ipp_pstate_t *printer_state) {
229 LOGD("get_PrinterState(): Enter");
230
231 // Requested printer attributes
232 static const char *pattrs[] = {"printer-make-and-model", "printer-state",
233 "printer-state-message", "printer-state-reasons"};
234
235 ipp_t *request = NULL;
236 ipp_t *response = NULL;
237 ipp_status_t ipp_status = IPP_OK;
238 int op = IPP_GET_PRINTER_ATTRIBUTES;
239 char http_resource[1024];
240 getResourceFromURI(printer_uri, http_resource, 1024);
241
242 if (printer_state_dyn == NULL) {
243 LOGE("get_PrinterState(): printer_state_dyn is null");
244 return ipp_status;
245 }
246
247 if (printer_state) {
248 *printer_state = IPP_PRINTER_STOPPED;
249 } else {
250 LOGE("get_PrinterState(): printer_state is null");
251 }
252 request = ippNewRequest(op);
253
254 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri);
255
256 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes",
257 sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
258
259 if ((response = ipp_doCupsRequest(http, request, http_resource, printer_uri)) == NULL) {
260 ipp_status = cupsLastError();
261 LOGE("get_PrinterState(): response is null: ipp_status %d", ipp_status);
262 printer_state_dyn->printer_status = PRINT_STATUS_UNABLE_TO_CONNECT;
263 printer_state_dyn->printer_reasons[0] = PRINT_STATUS_UNABLE_TO_CONNECT;
264 } else {
265 ipp_status = cupsLastError();
266 LOGD("ipp CUPS last ERROR: %d, %s", ipp_status, ippErrorString(ipp_status));
267 get_PrinterStateReason(response, printer_state, printer_state_dyn);
268 LOGD("get_PrinterState(): printer_state_dyn->printer_status: %d",
269 printer_state_dyn->printer_status);
270 }
271 LOGD("get_PrinterState(): exit http->fd %d, ipp_status %d, printer_state %d", http->fd,
272 ipp_status, printer_state_dyn->printer_status);
273
274 ippDelete(request);
275 ippDelete(response);
276 return ipp_status;
277 }
278
get_PrinterStateReason(ipp_t * response,ipp_pstate_t * printer_state,printer_state_dyn_t * printer_state_dyn)279 void get_PrinterStateReason(ipp_t *response, ipp_pstate_t *printer_state,
280 printer_state_dyn_t *printer_state_dyn) {
281 LOGD("get_PrinterStateReason(): Enter");
282 ipp_attribute_t *attrptr;
283 int reason_idx = 0;
284 int idx = 0;
285 ipp_pstate_t printer_ippstate = IPP_PRINTER_IDLE;
286
287 if ((attrptr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) == NULL) {
288 LOGE("get_PrinterStateReason printer-state null");
289 printer_state_dyn->printer_status = PRINT_STATUS_UNABLE_TO_CONNECT;
290 printer_state_dyn->printer_reasons[0] = PRINT_STATUS_UNABLE_TO_CONNECT;
291 } else {
292 printer_ippstate = (ipp_pstate_t) ippGetInteger(attrptr, 0);
293 *printer_state = printer_ippstate;
294
295 LOGD("get_PrinterStateReason printer-state: %d", printer_ippstate);
296 // set the printer_status; they may be modified based on the status reasons below.
297 switch (printer_ippstate) {
298 case IPP_PRINTER_IDLE:
299 printer_state_dyn->printer_status = PRINT_STATUS_IDLE;
300 break;
301 case IPP_PRINTER_PROCESSING:
302 printer_state_dyn->printer_status = PRINT_STATUS_PRINTING;
303 break;
304 case IPP_PRINTER_STOPPED:
305 printer_state_dyn->printer_status = PRINT_STATUS_SVC_REQUEST;
306 break;
307 }
308 }
309
310 if ((attrptr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) == NULL) {
311 LOGE(" get_PrinterStateReason printer-state reason null");
312 printer_state_dyn->printer_status = PRINT_STATUS_UNABLE_TO_CONNECT;
313 printer_state_dyn->printer_reasons[0] = PRINT_STATUS_UNABLE_TO_CONNECT;
314 } else {
315 for (idx = 0; idx < ippGetCount(attrptr); idx++) {
316 // Per RFC2911 any of these can have -error, -warning, or -report appended to end
317 LOGD("get_PrinterStateReason printer-state-reason: %s",
318 ippGetString(attrptr, idx, NULL));
319 if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_NONE,
320 strlen(IPP_PRNT_STATE_NONE)) == 0) {
321 switch (printer_ippstate) {
322 case IPP_PRINTER_IDLE:
323 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_IDLE;
324 break;
325 case IPP_PRINTER_PROCESSING:
326 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_PRINTING;
327 break;
328 case IPP_PRINTER_STOPPED:
329 // should this be PRINT_STATUS_SVC_REQUEST
330 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_UNKNOWN;
331 break;
332 }
333 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_SPOOL_FULL,
334 strlen(IPP_PRNT_STATE_SPOOL_FULL)) == 0) {
335 switch (printer_ippstate) {
336 case IPP_PRINTER_IDLE:
337 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_UNKNOWN;
338 break;
339 case IPP_PRINTER_PROCESSING:
340 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_PRINTING;
341 break;
342 case IPP_PRINTER_STOPPED:
343 // should this be PRINT_STATUS_SVC_REQUEST
344 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_UNKNOWN;
345 break;
346 }
347 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_MARKER_SUPPLY_LOW,
348 strlen(IPP_PRNT_STATE_MARKER_SUPPLY_LOW)) == 0) {
349 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_LOW_ON_INK;
350 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_TONER_LOW,
351 strlen(IPP_PRNT_STATE_TONER_LOW)) == 0) {
352 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_LOW_ON_TONER;
353 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_OTHER_WARN,
354 strlen(IPP_PRNT_STATE_OTHER_WARN)) == 0) {
355 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_UNKNOWN;
356 } else {
357 // check blocking cases
358 if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_MEDIA_NEEDED,
359 strlen(IPP_PRNT_STATE_MEDIA_NEEDED)) == 0) {
360 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_OUT_OF_PAPER;
361 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_MEDIA_EMPTY,
362 strlen(IPP_PRNT_STATE_MEDIA_EMPTY)) == 0) {
363 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_OUT_OF_PAPER;
364 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_TONER_EMPTY,
365 strlen(IPP_PRNT_STATE_TONER_EMPTY)) == 0) {
366 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_OUT_OF_TONER;
367 } else if (strncmp(ippGetString(attrptr, idx, NULL),
368 IPP_PRNT_STATE_MARKER_SUPPLY_EMPTY,
369 strlen(IPP_PRNT_STATE_MARKER_SUPPLY_EMPTY)) == 0) {
370 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_OUT_OF_INK;
371 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_DOOR_OPEN,
372 strlen(IPP_PRNT_STATE_DOOR_OPEN)) == 0) {
373 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_DOOR_OPEN;
374 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_COVER_OPEN,
375 strlen(IPP_PRNT_STATE_COVER_OPEN)) == 0) {
376 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_DOOR_OPEN;
377 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_MEDIA_JAM,
378 strlen(IPP_PRNT_STATE_MEDIA_JAM)) == 0) {
379 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_JAMMED;
380 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_SHUTDOWN,
381 strlen(IPP_PRNT_SHUTDOWN)) == 0) {
382 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_SHUTTING_DOWN;
383 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_STATE_OTHER_ERR,
384 strlen(IPP_PRNT_STATE_OTHER_ERR)) == 0) {
385 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_SVC_REQUEST;
386 } else if (strncmp(ippGetString(attrptr, idx, NULL), IPP_PRNT_PAUSED,
387 strlen(IPP_PRNT_PAUSED)) == 0) {
388 printer_state_dyn->printer_reasons[reason_idx++] = PRINT_STATUS_UNKNOWN;
389 }
390 }
391 } // end of reasons loop
392 }
393 }
394
print_col(ipp_t * col)395 static void print_col(ipp_t *col) {
396 int i;
397 ipp_attribute_t *attr;
398
399 LOGD("{");
400 for (attr = ippFirstAttribute(col); attr; attr = ippNextAttribute(col)) {
401 switch (ippGetValueTag(attr)) {
402 case IPP_TAG_INTEGER:
403 case IPP_TAG_ENUM:
404 for (i = 0; i < ippGetCount(attr); i++) {
405 LOGD(" %s(%s%s)= %d ", ippGetName(attr),
406 ippGetCount(attr) > 1 ? "1setOf " : "",
407 ippTagString(ippGetValueTag(attr)), ippGetInteger(attr, i));
408 }
409 break;
410 case IPP_TAG_BOOLEAN:
411 for (i = 0; i < ippGetCount(attr); i++) {
412 if (ippGetBoolean(attr, i)) {
413 LOGD(" %s(%s%s)= true ", ippGetName(attr),
414 ippGetCount(attr) > 1 ? "1setOf " : "",
415 ippTagString(ippGetValueTag(attr)));
416 } else {
417 LOGD(" %s(%s%s)= false ", ippGetName(attr),
418 ippGetCount(attr) > 1 ? "1setOf " : "",
419 ippTagString(ippGetValueTag(attr)));
420 }
421 }
422 break;
423 case IPP_TAG_NOVALUE:
424 LOGD(" %s(%s%s)= novalue", ippGetName(attr),
425 ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)));
426 break;
427 case IPP_TAG_RANGE:
428 for (i = 0; i < ippGetCount(attr); i++) {
429 int lower, upper;
430 lower = ippGetRange(attr, i, &upper);
431 LOGD(" %s(%s%s)= %d-%d ", ippGetName(attr),
432 ippGetCount(attr) > 1 ? "1setOf " : "",
433 ippTagString(ippGetValueTag(attr)), lower, upper);
434 }
435 break;
436 case IPP_TAG_RESOLUTION:
437 for (i = 0; i < ippGetCount(attr); i++) {
438 ipp_res_t units;
439 int xres, yres;
440 xres = ippGetResolution(attr, i, &yres, &units);
441 LOGD(" %s(%s%s)= %dx%d%s ", ippGetName(attr),
442 ippGetCount(attr) > 1 ? "1setOf " : "",
443 ippTagString(ippGetValueTag(attr)), xres, yres,
444 units == IPP_RES_PER_INCH ? "dpi" : "dpc");
445 }
446 break;
447 case IPP_TAG_STRING:
448 case IPP_TAG_TEXT:
449 case IPP_TAG_NAME:
450 case IPP_TAG_KEYWORD:
451 case IPP_TAG_CHARSET:
452 case IPP_TAG_URI:
453 case IPP_TAG_MIMETYPE:
454 case IPP_TAG_LANGUAGE:
455 for (i = 0; i < ippGetCount(attr); i++) {
456 LOGD(" %s(%s%s)= \"%s\" ", ippGetName(attr),
457 ippGetCount(attr) > 1 ? "1setOf " : "",
458 ippTagString(ippGetValueTag(attr)), ippGetString(attr, i, NULL));
459 }
460 break;
461 case IPP_TAG_TEXTLANG:
462 case IPP_TAG_NAMELANG:
463 for (i = 0; i < ippGetCount(attr); i++) {
464 const char *charset;
465 const char *text;
466 text = ippGetString(attr, i, &charset);
467 LOGD(" %s(%s%s)= \"%s\",%s ", ippGetName(attr),
468 ippGetCount(attr) > 1 ? "1setOf " : "",
469 ippTagString(ippGetValueTag(attr)), text, charset);
470 }
471 break;
472 case IPP_TAG_BEGIN_COLLECTION:
473 for (i = 0; i < ippGetCount(attr); i++) {
474 print_col(ippGetCollection(attr, i));
475 }
476 break;
477 default:
478 break;
479 }
480 }
481 LOGD("}");
482 }
483
print_attr(ipp_attribute_t * attr)484 void print_attr(ipp_attribute_t *attr) {
485 int i;
486
487 if (ippGetName(attr) == NULL) {
488 return;
489 }
490
491 switch (ippGetValueTag(attr)) {
492 case IPP_TAG_INTEGER:
493 case IPP_TAG_ENUM:
494 for (i = 0; i < ippGetCount(attr); i++) {
495 LOGD("%s (%s%s) = %d ", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "",
496 ippTagString(ippGetValueTag(attr)), ippGetInteger(attr, i));
497 }
498 break;
499 case IPP_TAG_BOOLEAN:
500 for (i = 0; i < ippGetCount(attr); i++) {
501 if (ippGetBoolean(attr, i)) {
502 LOGD("%s (%s%s) = true ", ippGetName(attr),
503 ippGetCount(attr) > 1 ? "1setOf " : "",
504 ippTagString(ippGetValueTag(attr)));
505 } else {
506 LOGD("%s (%s%s) = false ", ippGetName(attr),
507 ippGetCount(attr) > 1 ? "1setOf " : "",
508 ippTagString(ippGetValueTag(attr)));
509 }
510 }
511 break;
512 case IPP_TAG_NOVALUE:
513 LOGD("%s (%s%s) = novalue", ippGetName(attr),
514 ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)));
515 break;
516 case IPP_TAG_RANGE:
517 for (i = 0; i < ippGetCount(attr); i++) {
518 int lower, upper;
519 lower = ippGetRange(attr, i, &upper);
520 LOGD("%s (%s%s) = %d-%d ", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "",
521 ippTagString(ippGetValueTag(attr)), lower, upper);
522 }
523 break;
524 case IPP_TAG_RESOLUTION:
525 for (i = 0; i < ippGetCount(attr); i++) {
526 ipp_res_t units;
527 int xres, yres;
528 xres = ippGetResolution(attr, i, &yres, &units);
529 LOGD("%s (%s%s) = %dx%d%s ", ippGetName(attr),
530 ippGetCount(attr) > 1 ? "1setOf " : "",
531 ippTagString(ippGetValueTag(attr)), xres, yres,
532 units == IPP_RES_PER_INCH ? "dpi" : "dpc");
533 }
534 break;
535 case IPP_TAG_STRING:
536 case IPP_TAG_TEXT:
537 case IPP_TAG_NAME:
538 case IPP_TAG_KEYWORD:
539 case IPP_TAG_CHARSET:
540 case IPP_TAG_URI:
541 case IPP_TAG_MIMETYPE:
542 case IPP_TAG_LANGUAGE:
543 for (i = 0; i < ippGetCount(attr); i++) {
544 LOGD("%s (%s%s) = \"%s\" ", ippGetName(attr),
545 ippGetCount(attr) > 1 ? "1setOf " : "",
546 ippTagString(ippGetValueTag(attr)), ippGetString(attr, i, NULL));
547 }
548 break;
549 case IPP_TAG_TEXTLANG:
550 case IPP_TAG_NAMELANG:
551 for (i = 0; i < ippGetCount(attr); i++) {
552 const char *charset;
553 const char *text;
554 text = ippGetString(attr, i, &charset);
555 LOGD("%s (%s%s) = \"%s\",%s ", ippGetName(attr),
556 ippGetCount(attr) > 1 ? "1setOf " : "",
557 ippTagString(ippGetValueTag(attr)), text, charset);
558 }
559 break;
560
561 case IPP_TAG_BEGIN_COLLECTION:
562 for (i = 0; i < ippGetCount(attr); i++) {
563 LOGD("%s (%s%s): IPP_TAG_BEGIN_COLLECTION", ippGetName(attr),
564 ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)));
565 print_col(ippGetCollection(attr, i));
566 }
567 LOGD("%s (%s%s): IPP_TAG_END_COLLECTION", ippGetName(attr),
568 ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)));
569 break;
570
571 default:
572 break;
573 }
574 }
575
parse_IPPVersions(ipp_t * response,ipp_version_supported_t * ippVersions)576 void parse_IPPVersions(ipp_t *response, ipp_version_supported_t *ippVersions) {
577 int i;
578 ipp_attribute_t *attrptr;
579 char ipp10[] = "1.0";
580 char ipp11[] = "1.1";
581 char ipp20[] = "2.0";
582 LOGD(" Entered IPPVersions");
583 if (ippVersions != NULL) {
584 memset(ippVersions, 0, sizeof(ipp_version_supported_t));
585 LOGD(" in get_supportedIPPVersions");
586 attrptr = ippFindAttribute(response, "ipp-versions-supported", IPP_TAG_KEYWORD);
587 if (attrptr != NULL) {
588 LOGD(" in get_supportedIPPVersions: %d", ippGetCount(attrptr));
589 for (i = 0; i < ippGetCount(attrptr); i++) {
590 if (strcmp(ipp10, ippGetString(attrptr, i, NULL)) == 0) {
591 ippVersions->supportsIpp10 = 1;
592 } else if (strcmp(ipp11, ippGetString(attrptr, i, NULL)) == 0) {
593 ippVersions->supportsIpp11 = 1;
594 } else if (strcmp(ipp20, ippGetString(attrptr, i, NULL)) == 0) {
595 ippVersions->supportsIpp20 = 1;
596 } else {
597 LOGD("found another ipp version. %s", ippGetString(attrptr, i, NULL));
598 }
599 }
600 }
601 }
602 }
603
mapDFMediaToIPPKeyword(media_size_t media_size)604 const char *mapDFMediaToIPPKeyword(media_size_t media_size) {
605 int i;
606 for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) {
607 if (SupportedMediaSizes[i].media_size == (media_size_t) media_size) {
608 return (SupportedMediaSizes[i].PWGName);
609 }
610 }
611 return (SupportedMediaSizes[0].PWGName);
612 }
613
ipp_find_media_size(const char * ipp_media_keyword,media_size_t * media_size)614 int ipp_find_media_size(const char *ipp_media_keyword, media_size_t *media_size) {
615 int i;
616 LOGD("ipp_find_media_size entry is %s", ipp_media_keyword);
617 for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) {
618 if (strcmp(SupportedMediaSizes[i].PWGName, ipp_media_keyword) == 0) {
619 LOGD(" mediaArraySize: match string %s PT_size: %d",
620 SupportedMediaSizes[i].PWGName, SupportedMediaSizes[i].media_size);
621 break;
622 }
623 }
624 if (i < SUPPORTED_MEDIA_SIZE_COUNT) {
625 *media_size = SupportedMediaSizes[i].media_size;
626 return i;
627 } else {
628 return -1;
629 }
630 return -1;
631 }
632
633 /*
634 * Return a freshly allocated string copied from another string
635 */
substring(const char * string,int position,int length)636 static char *substring(const char *string, int position, int length) {
637 char *pointer;
638 int c;
639 pointer = malloc(length + 1);
640 if (pointer == NULL) {
641 exit(EXIT_FAILURE);
642 }
643
644 for (c = 0; c < position - 1; c++) {
645 string++;
646 }
647
648 for (c = 0; c < length; c++) {
649 *(pointer + c) = *string;
650 string++;
651 }
652 *(pointer + c) = '\0';
653 return pointer;
654 }
655
656 /*
657 * Parse and IPP media size and return dimensions in millimeters.
658 * Format is region_name_#x#<unit> or format is custom_(min\max)_#x#<unit>
659 */
getMediaDimensions_mm(const char * mediaSize,media_dimension_mm_t * media_dimensions)660 static int getMediaDimensions_mm(const char *mediaSize, media_dimension_mm_t *media_dimensions) {
661 char *tempMediaSize = NULL;
662 char *um;
663 char *buf = NULL; // custom
664 char *dim = NULL; // min
665 char *upper = NULL; // 8.5
666 const char t[2] = "_";
667 const char x[2] = "x";
668 char in[3] = "in";
669 double inch_to_mm = 25.4;
670
671 tempMediaSize = malloc(strlen(mediaSize) + 1);
672 if (tempMediaSize == NULL) {
673 exit(EXIT_FAILURE);
674 }
675 strcpy(tempMediaSize, mediaSize);
676 LOGD("getMediaDimensions_mm Start media:%s", tempMediaSize);
677
678 um = substring(mediaSize, strlen(tempMediaSize) - 1, 2);
679 LOGD("getMediaDimensions um=%s", um);
680
681 // fill in buf with what we need to work with
682 buf = strtok(tempMediaSize, t); // custom
683 while (buf != NULL) {
684 if (dim != NULL) {
685 free(dim);
686 }
687 dim = malloc(strlen(buf) + 1);
688 if (dim == NULL) {
689 exit(EXIT_FAILURE);
690 }
691 strcpy(dim, buf);
692 buf = strtok(NULL, t);
693 }
694
695 if (dim != NULL) {
696 LOGD("getMediaDimensions part2=%s", dim);
697 media_dimensions->Lower = atof(strtok(dim, x));
698 LOGD("getMediaDimensions lower=%g", media_dimensions->Lower);
699 upper = strtok(NULL, x);
700 if (upper != NULL) {
701 // Finally the upper bound
702 char *tempStr = substring(upper, 1, strlen(upper) - 2);
703 media_dimensions->Upper = atof(tempStr);
704 free(tempStr);
705
706 tempStr = substring(upper, 1, strlen(upper) - 2);
707 LOGD("getMediaDimensions part4=%s", tempStr);
708 free(tempStr);
709
710 LOGD("getMediaDimensions upper=%g", media_dimensions->Upper);
711 // finally make sure we are in mm
712 if (strcmp(um, in) == 0) {
713 LOGD("getMediaDimensions part5");
714 media_dimensions->Lower = media_dimensions->Lower * inch_to_mm;
715 media_dimensions->Upper = media_dimensions->Upper * inch_to_mm;
716 }
717
718 if (media_dimensions->Lower > 0 && media_dimensions->Upper > 0) {
719 double dTemp = 0;
720 if (media_dimensions->Lower > media_dimensions->Upper) {
721 dTemp = media_dimensions->Lower;
722 media_dimensions->Lower = media_dimensions->Upper;
723 media_dimensions->Upper = dTemp;
724 }
725 LOGD("getMediaDimensions final lower=%g", media_dimensions->Lower);
726 LOGD("getMediaDimensions final upper=%g", media_dimensions->Upper);
727 free(tempMediaSize);
728 free(dim);
729 free(um);
730 return 1;
731 }
732 }
733 free(dim);
734 }
735 free(um);
736 free(tempMediaSize);
737 return 0;
738 }
739
parse_getMediaSupported(ipp_t * response,media_supported_t * media_supported,printer_capabilities_t * capabilities)740 void parse_getMediaSupported(ipp_t *response, media_supported_t *media_supported,
741 printer_capabilities_t *capabilities) {
742 int i;
743 ipp_attribute_t *attrptr;
744 int sizes_idx = 0;
745 char custom_min[] = "custom_min";
746 char custom_max[] = "custom_max";
747 bool apply_custom_min_max = true;
748 int iterate = 0;
749
750 char *optout_manufacture_list[7] = {"Brother", "Epson", "Fuji Xerox", "Konica Minolta",
751 "Kyocera", "Canon", "UTAX_TA"};
752 int manufacturerlist_size = (sizeof(optout_manufacture_list) /
753 sizeof(*optout_manufacture_list));
754
755 media_dimension_mm_t custom_min_dim;
756 media_dimension_mm_t custom_max_dim;
757 int rCustomMin = 0;
758 int rCustomMax = 0;
759 char *tempMediaSize = NULL;
760
761 char manufacturername_from_model[256];
762 LOGD(" Entered getMediaSupported");
763
764 media_size_t media_sizeTemp;
765 int idx = 0;
766
767 // First check printer-device-id for manufacturer exception
768 if ((attrptr = ippFindAttribute(response, "printer-device-id", IPP_TAG_TEXT)) != NULL) {
769 strlcpy(capabilities->make, ippGetString(attrptr, 0, NULL), sizeof(capabilities->make));
770 LOGD("manufacturer_from_deviceid: %s", capabilities->make);
771 for (iterate = 0; iterate < manufacturerlist_size; iterate++) {
772 if (strcasestr(capabilities->make, optout_manufacture_list[iterate]) != NULL) {
773 LOGD("printer device id cmp: %s", strcasestr(capabilities->make,
774 optout_manufacture_list[iterate]));
775 apply_custom_min_max = false;
776 }
777 }
778 }
779
780 // Second check printer-make-and-model for manufacturer exception
781 if (apply_custom_min_max) {
782 // Get manufacturer name using printer-make-and-model
783 attrptr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT);
784 if (attrptr != NULL) {
785 strlcpy(manufacturername_from_model, ippGetString(attrptr, 0, NULL),
786 sizeof(manufacturername_from_model));
787 LOGD("manufacturer_from_make_model: %s", manufacturername_from_model);
788 for (iterate = 0; iterate < manufacturerlist_size; iterate++) {
789 if (strcasestr(manufacturername_from_model, optout_manufacture_list[iterate]) !=
790 NULL) {
791 LOGD("printer make model cmp: %s", strcasestr(manufacturername_from_model,
792 optout_manufacture_list[iterate]));
793 apply_custom_min_max = false;
794 }
795 }
796 }
797 }
798
799 if ((attrptr = ippFindAttribute(response, "media-supported", IPP_TAG_KEYWORD)) != NULL) {
800 LOGD("media-supported found; number of values %d", ippGetCount(attrptr));
801 for (i = 0; i < ippGetCount(attrptr); i++) {
802 idx = ipp_find_media_size(ippGetString(attrptr, i, NULL), &media_sizeTemp);
803 LOGD(" Temp - i: %d idx %d keyword: %s PT_size %d", i, idx, ippGetString(
804 attrptr, i, NULL), media_sizeTemp);
805
806 // Modified since anytime the find media size returned 0 it could either mean
807 // NOT found or na_letter.
808 if (idx >= 0) {
809 media_supported->media_size[sizes_idx] = media_sizeTemp;
810 media_supported->idxKeywordTranTable[sizes_idx] = idx;
811 sizes_idx++;
812 }
813
814 if (idx == -1) { // it might be a custom range
815 if (tempMediaSize != NULL) {
816 free(tempMediaSize);
817 }
818 tempMediaSize = malloc(strlen(ippGetString(attrptr, i, NULL)) + 1);
819 if (tempMediaSize == NULL) {
820 exit(EXIT_FAILURE);
821 }
822 strcpy(tempMediaSize, ippGetString(attrptr, i, NULL));
823 if (strstr(tempMediaSize, custom_min) != NULL) {
824 rCustomMin = getMediaDimensions_mm(tempMediaSize, &custom_min_dim);
825 }
826 if (strstr(tempMediaSize, custom_max) != NULL) {
827 rCustomMax = getMediaDimensions_mm(tempMediaSize, &custom_max_dim);
828 }
829 }
830 }
831 // if value equal to particular manufacture condition goes here
832 if (apply_custom_min_max) {
833 LOGD("*****apply custom range for this manufacture");
834 // Now add in custom sizes if there is a custom min max range
835 media_dimension_mm_t media_dim;
836 int rMediaDim = 0;
837 LOGD("rCustomMin:%d rCustomMax:%d", rCustomMin, rCustomMax);
838 if (rCustomMin > 0 && rCustomMax > 0) { // we have custom support
839 LOGD("CustomRange minLower:%g minUpper:%g maxLower:%g maxUpper:%g",
840 custom_min_dim.Lower, custom_min_dim.Upper, custom_max_dim.Lower,
841 custom_max_dim.Upper);
842 media_dim.Lower = 0;
843 media_dim.Upper = 0;
844 for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) {
845 int found;
846 int j;
847 found = 0;
848 int sizes_idx_start = sizes_idx - 1;
849 for (j = 0; j < sizes_idx_start; j++) {
850 if (i == media_supported->idxKeywordTranTable[j]) {
851 found = 1;
852 break;
853 }
854 }
855 if (found == 0) {
856 // check custom
857 if (tempMediaSize != NULL) {
858 free(tempMediaSize);
859 }
860 tempMediaSize = malloc(strlen(SupportedMediaSizes[i].PWGName) + 1);
861 if (tempMediaSize == NULL) {
862 exit(EXIT_FAILURE);
863 }
864 strcpy(tempMediaSize, SupportedMediaSizes[i].PWGName);
865 LOGD("NOT FOUND CHECKING CUSTOM:%s", tempMediaSize);
866 rMediaDim = getMediaDimensions_mm(tempMediaSize, &media_dim);
867 if (rMediaDim > 0) {
868 LOGD("CustomRange minLower:%g minUpper:%g maxLower:%g maxUpper:%g"
869 "lower:%g upper:%g",
870 custom_min_dim.Lower, custom_min_dim.Upper,
871 custom_max_dim.Lower,
872 custom_max_dim.Upper, media_dim.Lower, media_dim.Upper);
873 if (media_dim.Lower >= custom_min_dim.Lower &&
874 media_dim.Lower <= custom_max_dim.Lower
875 && media_dim.Upper >= custom_min_dim.Upper &&
876 media_dim.Upper <= custom_max_dim.Upper) {
877 LOGD("Add Media Size %s!!", tempMediaSize);
878 media_supported->media_size[sizes_idx] =
879 SupportedMediaSizes[i].media_size;
880 media_supported->idxKeywordTranTable[sizes_idx] = i;
881 sizes_idx++;
882 }
883 }
884 }
885 }
886 if (tempMediaSize != NULL) {
887 free(tempMediaSize);
888 tempMediaSize = NULL;
889 }
890 }
891 } else {
892 LOGD("*****Dont apply custom range for this manufacture");
893 }
894 } else {
895 LOGD("media-supported not found");
896 }
897
898 if (tempMediaSize) {
899 free(tempMediaSize);
900 }
901 }
902
get_supportedPrinterResolutions(ipp_attribute_t * attrptr,printer_capabilities_t * capabilities)903 static void get_supportedPrinterResolutions(ipp_attribute_t *attrptr,
904 printer_capabilities_t *capabilities) {
905 int idx = 0;
906 int i;
907 for (i = 0; i < ippGetCount(attrptr); i++) {
908 ipp_res_t units;
909 int xres, yres;
910 xres = ippGetResolution(attrptr, i, &yres, &units);
911 if (units == IPP_RES_PER_INCH) {
912 if ((idx < MAX_RESOLUTIONS_SUPPORTED) && (xres == yres)) {
913 capabilities->supportedResolutions[idx] = xres;
914 idx++;
915 }
916 }
917 }
918 capabilities->numSupportedResolutions = idx;
919 }
920
getResourceFromURI(const char * uri,char * resource,int resourcelen)921 void getResourceFromURI(const char *uri, char *resource, int resourcelen) {
922 char scheme[1024];
923 char username[1024];
924 char host[1024];
925 int port;
926 httpSeparateURI(0, uri, scheme, 1024, username, 1024, host, 1024, &port, resource, resourcelen);
927 }
928
929 /*
930 * Add a new media type to a printer's collection of supported media types
931 */
addMediaType(printer_capabilities_t * capabilities,media_type_t mediaType)932 static void addMediaType(printer_capabilities_t *capabilities, media_type_t mediaType) {
933 int index;
934 for (index = 0; index < capabilities->numSupportedMediaTypes; index++) {
935 // Skip if already present
936 if (capabilities->supportedMediaTypes[index] == mediaType) return;
937 }
938
939 // Add if not found and not too many
940 if (capabilities->numSupportedMediaTypes < MAX_MEDIA_TYPES_SUPPORTED) {
941 capabilities->supportedMediaTypes[capabilities->numSupportedMediaTypes++] = mediaType;
942 } else {
943 LOGI("Hit MAX_MEDIA_TYPES_SUPPORTED while adding %d", mediaType);
944 }
945 }
946
parse_printerAttributes(ipp_t * response,printer_capabilities_t * capabilities)947 void parse_printerAttributes(ipp_t *response, printer_capabilities_t *capabilities) {
948 int i, j;
949 ipp_attribute_t *attrptr;
950
951 LOGD("Entered parse_printerAttributes");
952
953 media_supported_t media_supported;
954 for (i = 0; i <= PAGE_STATUS_MAX - 1; i++) {
955 media_supported.media_size[i] = 0;
956 }
957 parse_getMediaSupported(response, &media_supported, capabilities);
958
959 parse_printerUris(response, capabilities);
960
961 LOGD("Media Supported: ");
962 int idx = 0;
963 capabilities->numSupportedMediaTypes = 0;
964 for (i = 0; i <= PAGE_STATUS_MAX - 1; i++) {
965 if (media_supported.media_size[i] != 0) {
966 capabilities->supportedMediaSizes[capabilities->numSupportedMediaSizes++] =
967 media_supported.media_size[i];
968 idx = media_supported.idxKeywordTranTable[i];
969 LOGD(" i %d, \tPT_Size: %d \tidx %d \tKeyword: %s", i, media_supported.media_size[i],
970 idx, SupportedMediaSizes[idx].PWGName);
971 }
972 }
973
974 if ((attrptr = ippFindAttribute(response, "printer-dns-sd-name", IPP_TAG_NAME)) != NULL) {
975 strlcpy(capabilities->name, ippGetString(attrptr, 0, NULL), sizeof(capabilities->name));
976 }
977
978 if (!capabilities->name[0]) {
979 if ((attrptr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL) {
980 strlcpy(capabilities->name, ippGetString(attrptr, 0, NULL), sizeof(capabilities->name));
981 }
982 }
983
984 if (!capabilities->name[0]) {
985 if ((attrptr = ippFindAttribute(response, "printer-name", IPP_TAG_TEXT)) != NULL) {
986 strlcpy(capabilities->name, ippGetString(attrptr, 0, NULL), sizeof(capabilities->name));
987 }
988 }
989
990 if ((attrptr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL) {
991 strlcpy(capabilities->make, ippGetString(attrptr, 0, NULL), sizeof(capabilities->make));
992 }
993
994 if ((attrptr = ippFindAttribute(response, "printer-uuid", IPP_TAG_URI)) != NULL) {
995 strlcpy(capabilities->uuid, ippGetString(attrptr, 0, NULL), sizeof(capabilities->uuid));
996 }
997
998 if ((attrptr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL) {
999 strlcpy(capabilities->location, ippGetString(attrptr, 0, NULL),
1000 sizeof(capabilities->location));
1001 }
1002
1003 if ((attrptr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL) {
1004 strlcpy(capabilities->mediaDefault, ippGetString(attrptr, 0, NULL),
1005 sizeof(capabilities->mediaDefault));
1006 }
1007
1008 if ((attrptr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL) {
1009 if (ippGetBoolean(attrptr, 0)) {
1010 capabilities->color = 1;
1011 }
1012 }
1013 if ((attrptr = ippFindAttribute(response, "copies-supported", IPP_TAG_RANGE)) != NULL) {
1014 int upper = 0;
1015 for (i = 0; i < ippGetCount(attrptr); i++) {
1016 ippGetRange(attrptr, i, &upper);
1017 }
1018 if (upper > 1) {
1019 capabilities->canCopy = 1;
1020 }
1021 }
1022 if ((attrptr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD)) !=
1023 NULL) {
1024 for (i = 0; i < ippGetCount(attrptr); i++) {
1025 if (strcmp("color", ippGetString(attrptr, i, NULL)) == 0) {
1026 capabilities->color = 1;
1027 }
1028 }
1029 }
1030
1031 char imagePCLm[] = "application/PCLm";
1032 char imagePWG[] = "image/pwg-raster";
1033 char imagePDF[] = "image/pdf";
1034 char applicationPDF[] = "application/pdf";
1035
1036 if ((attrptr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE))
1037 != NULL) {
1038 for (i = 0; i < ippGetCount(attrptr); i++) {
1039 if (strcmp(imagePDF, ippGetString(attrptr, i, NULL)) == 0) {
1040 capabilities->canPrintPDF = 1;
1041 } else if (strcmp(applicationPDF, ippGetString(attrptr, i, NULL)) == 0) {
1042 capabilities->canPrintPDF = 1;
1043 } else if (strcmp(imagePCLm, ippGetString(attrptr, i, NULL)) == 0) {
1044 capabilities->canPrintPCLm = 1;
1045 } else if (strcmp(applicationPDF, ippGetString(attrptr, i, NULL)) == 0) {
1046 capabilities->canPrintPDF = 1;
1047 } else if (strcmp(imagePWG, ippGetString(attrptr, i, NULL)) == 0) {
1048 capabilities->canPrintPWG = 1;
1049 }
1050 }
1051 }
1052
1053 if ((attrptr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL) {
1054 for (i = 0; i < ippGetCount(attrptr); i++) {
1055 if (strcmp(IPP_SIDES_TWO_SIDED_SHORT_EDGE, ippGetString(attrptr, i, NULL)) == 0) {
1056 capabilities->duplex = 1;
1057 } else if (strcmp(IPP_SIDES_TWO_SIDED_LONG_EDGE, ippGetString(attrptr, i, NULL)) == 0) {
1058 capabilities->duplex = 1;
1059 }
1060 }
1061 }
1062
1063 // Look up supported media types
1064 capabilities->numSupportedMediaTypes = 0;
1065 if (((attrptr = ippFindAttribute(response, "media-type-supported", IPP_TAG_KEYWORD)) != NULL)
1066 || ((attrptr = ippFindAttribute(response, "media-type-supported", IPP_TAG_NAME))
1067 != NULL)) {
1068 for (i = 0; i < ippGetCount(attrptr); i++) {
1069 if (strcasestr(ippGetString(attrptr, i, NULL), "photographic-glossy")) {
1070 addMediaType(capabilities, MEDIA_PHOTO_GLOSSY);
1071 } else if (strcasestr(ippGetString(attrptr, i, NULL), "photo")) {
1072 addMediaType(capabilities, MEDIA_PHOTO);
1073 } else if (strcasestr(ippGetString(attrptr, i, NULL), "stationery")) {
1074 addMediaType(capabilities, MEDIA_PLAIN);
1075 }
1076 }
1077 }
1078
1079 if (capabilities->numSupportedMediaTypes == 0) {
1080 // If no recognized media types were found, fall back to all 3 just in case
1081 addMediaType(capabilities, MEDIA_PLAIN);
1082 addMediaType(capabilities, MEDIA_PHOTO);
1083 addMediaType(capabilities, MEDIA_PHOTO_GLOSSY);
1084 }
1085
1086 capabilities->numSupportedResolutions = 0;
1087 // only appears that SMM supports the pclm-source-resolution-supported attribute
1088 // if that is not present, use the printer-resolution-supported attribute to determine
1089 // if 300DPI is supported
1090 if ((attrptr = ippFindAttribute(response, "pclm-source-resolution-supported",
1091 IPP_TAG_RESOLUTION)) != NULL) {
1092 get_supportedPrinterResolutions(attrptr, capabilities);
1093 } else if ((attrptr = ippFindAttribute(response, "printer-resolution-supported",
1094 IPP_TAG_RESOLUTION)) != NULL) {
1095 get_supportedPrinterResolutions(attrptr, capabilities);
1096 }
1097
1098 char ipp10[] = "1.0";
1099 char ipp11[] = "1.1";
1100 char ipp20[] = "2.0";
1101
1102 if ((attrptr = ippFindAttribute(response, "ipp-versions-supported", IPP_TAG_KEYWORD)) != NULL) {
1103 unsigned char supportsIpp20 = 0;
1104 unsigned char supportsIpp11 = 0;
1105 unsigned char supportsIpp10 = 0;
1106
1107 for (i = 0; i < ippGetCount(attrptr); i++) {
1108 if (strcmp(ipp10, ippGetString(attrptr, i, NULL)) == 0) {
1109 supportsIpp10 = 1;
1110 } else if (strcmp(ipp11, ippGetString(attrptr, i, NULL)) == 0) {
1111 supportsIpp11 = 1;
1112 } else if (strcmp(ipp20, ippGetString(attrptr, i, NULL)) == 0) {
1113 supportsIpp20 = 1;
1114 } else {
1115 LOGD("found another ipp version. %s", ippGetString(attrptr, i, NULL));
1116 }
1117 if (supportsIpp20) {
1118 capabilities->ippVersionMajor = 2;
1119 capabilities->ippVersionMinor = 0;
1120 } else if (supportsIpp11) {
1121 capabilities->ippVersionMajor = 1;
1122 capabilities->ippVersionMinor = 1;
1123 } else if (supportsIpp10) {
1124 capabilities->ippVersionMajor = 1;
1125 capabilities->ippVersionMinor = 0;
1126 } else {
1127 // default to 1.0
1128 capabilities->ippVersionMajor = 1;
1129 capabilities->ippVersionMinor = 0;
1130 }
1131 }
1132 }
1133
1134 char epcl10[] = "1.0";
1135 if ((attrptr = ippFindAttribute(response, "epcl-version-supported", IPP_TAG_KEYWORD)) != NULL) {
1136 for (i = 0; i < ippGetCount(attrptr); i++) {
1137 LOGD("setting epcl_ipp_version (KEYWORD) %s", ippGetString(attrptr, i, NULL));
1138
1139 // substring match because different devices implemented spec differently
1140 if (strstr(ippGetString(attrptr, i, NULL), epcl10) != NULL) {
1141 LOGD("setting epcl_ipp_version = 1");
1142 capabilities->ePclIppVersion = 1;
1143 }
1144 }
1145 }
1146
1147 if ((attrptr = ippFindAttribute(response, "epcl-version-supported", IPP_TAG_TEXT)) != NULL) {
1148 for (i = 0; i < ippGetCount(attrptr); i++) {
1149 LOGD("setting epcl_ipp_verion (TEXT) %s", ippGetString(attrptr, i, NULL));
1150
1151 // substring match because different devices implemented spec differently
1152 if (strstr(ippGetString(attrptr, i, NULL), epcl10) != NULL) {
1153 LOGD("setting epcl_ipp_verion = 1");
1154 capabilities->ePclIppVersion = 1;
1155 }
1156 }
1157 }
1158
1159 if ((attrptr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION)) !=
1160 NULL) {
1161 for (i = 0; i < ippGetCount(attrptr); i++) {
1162 LOGD("Gathering margins supported");
1163
1164 ipp_t *collection = ippGetCollection(attrptr, i);
1165
1166 for (j = 0, attrptr = ippFirstAttribute(collection);
1167 (j < 4) && (attrptr != NULL); attrptr = ippNextAttribute(collection)) {
1168 if (strcmp("media-top-margin", ippGetName(attrptr)) == 0) {
1169 capabilities->printerTopMargin = ippGetInteger(attrptr, 0);
1170 } else if (strcmp("media-bottom-margin", ippGetName(attrptr)) == 0) {
1171 capabilities->printerBottomMargin = ippGetInteger(attrptr, 0);
1172 } else if (strcmp("media-left-margin", ippGetName(attrptr)) == 0) {
1173 capabilities->printerLeftMargin = ippGetInteger(attrptr, 0);
1174 } else if (strcmp("media-right-margin", ippGetName(attrptr)) == 0) {
1175 capabilities->printerRightMargin = ippGetInteger(attrptr, 0);
1176 }
1177 }
1178 }
1179 }
1180
1181 if ((attrptr = ippFindAttribute(response, "media-size-name", IPP_TAG_KEYWORD)) != NULL) {
1182 capabilities->isMediaSizeNameSupported = true;
1183 } else {
1184 capabilities->isMediaSizeNameSupported = false;
1185 }
1186
1187 // is strip length supported? if so, stored in capabilities
1188 if ((attrptr = ippFindAttribute(response, "pclm-strip-height-preferred",
1189 IPP_TAG_INTEGER)) != NULL) {
1190 LOGD("pclm-strip-height-preferred=%d", ippGetInteger(attrptr, 0));
1191
1192 // if the strip height is 0, the device wants us to send the entire page in one band
1193 // (according to ePCL spec). Since our code doesn't currently support generating an entire
1194 // page in one band, set the strip height to the default value every device *should* support
1195 // also, for some reason our code crashes when it attempts to generate strips at 512 or
1196 // above. Therefore, limiting the upper bound strip height to 256
1197 if (ippGetInteger(attrptr, 0) == 0 || ippGetInteger(attrptr, 0) > 256) {
1198 capabilities->stripHeight = STRIPE_HEIGHT;
1199 } else {
1200 capabilities->stripHeight = ippGetInteger(attrptr, 0);
1201 }
1202 } else {
1203 capabilities->stripHeight = STRIPE_HEIGHT;
1204 }
1205
1206 // what is the preferred compression method - jpeg, flate, rle
1207 if ((attrptr = ippFindAttribute(response, "pclm-compression-method-preferred",
1208 IPP_TAG_KEYWORD)) != NULL) {
1209 LOGD("pclm-compression-method-preferred=%s", ippGetString(attrptr, 0, NULL));
1210 }
1211
1212 // is device able to rotate back page for duplex jobs?
1213 if ((attrptr = ippFindAttribute(response, "pclm-raster-back-side", IPP_TAG_KEYWORD)) != NULL) {
1214 LOGD("pclm-raster-back-side=%s", ippGetString(attrptr, 0, NULL));
1215 if (strcmp(ippGetString(attrptr, 0, NULL), "rotated") == 0) {
1216 capabilities->canRotateDuplexBackPage = 0;
1217 LOGD("Device cannot rotate back page for duplex jobs.");
1218 } else {
1219 capabilities->canRotateDuplexBackPage = 1;
1220 }
1221 }
1222
1223 // look for full-bleed supported by looking for 0 on all margins
1224 bool topsupported = false, bottomsupported = false, rightsupported = false,
1225 leftsupported = false;
1226 if ((attrptr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) !=
1227 NULL) {
1228 for (i = 0; i < ippGetCount(attrptr); i++) {
1229 if (ippGetInteger(attrptr, i) == 0) {
1230 LOGD("Top Margin Supported");
1231 topsupported = true;
1232 break;
1233 }
1234 }
1235 }
1236 if ((attrptr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) !=
1237 NULL) {
1238 for (i = 0; i < ippGetCount(attrptr); i++) {
1239 if (ippGetInteger(attrptr, i) == 0) {
1240 LOGD("Bottom Margin Supported");
1241 bottomsupported = true;
1242 break;
1243 }
1244 }
1245 }
1246 if ((attrptr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) !=
1247 NULL) {
1248 for (i = 0; i < ippGetCount(attrptr); i++) {
1249 if (ippGetInteger(attrptr, i) == 0) {
1250 LOGD("Right Margin Supported");
1251 rightsupported = true;
1252 break;
1253 }
1254 }
1255 }
1256 if ((attrptr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) !=
1257 NULL) {
1258 for (i = 0; i < ippGetCount(attrptr); i++) {
1259 if (ippGetInteger(attrptr, i) == 0) {
1260 LOGD("Left Margin Supported");
1261 leftsupported = true;
1262 break;
1263 }
1264 }
1265 }
1266
1267 if (topsupported && bottomsupported && rightsupported && leftsupported) {
1268 LOGD("full-bleed is supported");
1269 capabilities->borderless = 1;
1270 } else {
1271 LOGD("full-bleed is NOT supported");
1272 }
1273
1274 if ((attrptr = ippFindAttribute(response, "printer-device-id", IPP_TAG_TEXT)) != NULL) {
1275 if (strstr(ippGetString(attrptr, 0, NULL), "PCL3GUI") != NULL) {
1276 capabilities->inkjet = 1;
1277 }
1278 } else if (capabilities->borderless == 1) {
1279 capabilities->inkjet = 1;
1280 }
1281
1282 // determine if device prints pages face-down
1283 capabilities->faceDownTray = 1;
1284 if ((attrptr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_KEYWORD)) != NULL) {
1285 if (strstr(ippGetString(attrptr, 0, NULL), "face-up") != NULL) {
1286 capabilities->faceDownTray = 0;
1287 }
1288 }
1289
1290 // Determine supported document format details
1291 if ((attrptr = ippFindAttribute(response, "document-format-details-supported",
1292 IPP_TAG_KEYWORD)) != NULL) {
1293 for (i = 0; i < ippGetCount(attrptr); i++) {
1294 if (strcmp("document-source-application-name", ippGetString(attrptr, i, NULL)) == 0) {
1295 capabilities->docSourceAppName = 1;
1296 } else if (
1297 strcmp("document-source-application-version", ippGetString(attrptr, i, NULL)) ==
1298 0) {
1299 capabilities->docSourceAppVersion = 1;
1300 } else if (strcmp("document-source-os-name", ippGetString(attrptr, i, NULL)) == 0) {
1301 capabilities->docSourceOsName = 1;
1302 } else if (strcmp("document-source-os-version", ippGetString(attrptr, i, NULL)) == 0) {
1303 capabilities->docSourceOsVersion = 1;
1304 }
1305 }
1306 }
1307 debuglist_printerCapabilities(capabilities);
1308 }
1309
1310 // Used in parse_printerUris
1311 #define MAX_URIS 10
1312 typedef struct {
1313 const char *uri;
1314 int valid;
1315 } parsed_uri_t;
1316
parse_printerUris(ipp_t * response,printer_capabilities_t * capabilities)1317 static void parse_printerUris(ipp_t *response, printer_capabilities_t *capabilities) {
1318 ipp_attribute_t *attrptr;
1319 int i;
1320 parsed_uri_t uris[MAX_URIS] = {0};
1321
1322 if ((attrptr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) {
1323 for (i = 0; i < MIN(ippGetCount(attrptr), MAX_URIS); i++) {
1324 uris[i].uri = ippGetString(attrptr, i, NULL);
1325 uris[i].valid = true;
1326 }
1327 }
1328
1329 // If security or authentication is required (non-"none") at any URI, mark it invalid
1330
1331 if ((attrptr = ippFindAttribute(response, "uri-security-supported", IPP_TAG_KEYWORD)) != NULL) {
1332 for (i = 0; i < MIN(ippGetCount(attrptr), MAX_URIS); i++) {
1333 if (strcmp("none", ippGetString(attrptr, i, NULL)) != 0) {
1334 LOGD("parse_printerUris %s invalid because sec=%s", uris[i].uri,
1335 ippGetString(attrptr, i, NULL));
1336 uris[i].valid = false;
1337 }
1338 }
1339 }
1340
1341 if ((attrptr = ippFindAttribute(response, "uri-authentication-supported", IPP_TAG_KEYWORD))
1342 != NULL) {
1343 for (i = 0; i < MIN(ippGetCount(attrptr), MAX_URIS); i++) {
1344 // Allow "none" and "requesting-user-name" only
1345 if (strcmp("none", ippGetString(attrptr, i, NULL)) != 0 &&
1346 strcmp("requesting-user-name", ippGetString(attrptr, i, NULL)) != 0) {
1347 LOGD("parse_printerUris %s invalid because auth=%s", uris[i].uri,
1348 ippGetString(attrptr, i, NULL));
1349 uris[i].valid = false;
1350 }
1351 }
1352 }
1353
1354 // Find a valid URI and copy it into place.
1355 for (i = 0; i < MAX_URIS; i++) {
1356 if (uris[i].valid) {
1357 LOGD("parse_printerUris found %s", uris[i].uri);
1358 strlcpy(capabilities->printerUri, uris[i].uri, sizeof(capabilities->printerUri));
1359 break;
1360 }
1361 }
1362 }
1363
debuglist_printerCapabilities(printer_capabilities_t * capabilities)1364 void debuglist_printerCapabilities(printer_capabilities_t *capabilities) {
1365 LOGD("printer make: %s", capabilities->make);
1366 LOGD("printer default media: %s", capabilities->mediaDefault);
1367 LOGD("canPrintPDF: %d", capabilities->canPrintPDF);
1368 LOGD("duplex: %d", capabilities->duplex);
1369 LOGD("canRotateDuplexBackPage: %d", capabilities->canRotateDuplexBackPage);
1370 LOGD("color: %d", capabilities->color);
1371 LOGD("canCopy: %d", capabilities->canCopy);
1372 LOGD("ippVersionMajor: %d", capabilities->ippVersionMajor);
1373 LOGD("ippVersionMinor: %d", capabilities->ippVersionMinor);
1374 LOGD("strip height: %d", capabilities->stripHeight);
1375 LOGD("faceDownTray: %d", capabilities->faceDownTray);
1376 }
1377
debuglist_printerStatus(printer_state_dyn_t * printer_state_dyn)1378 void debuglist_printerStatus(printer_state_dyn_t *printer_state_dyn) {
1379 const char *decoded = "unknown";
1380 if (printer_state_dyn->printer_status == PRINT_STATUS_INITIALIZING) {
1381 decoded = "Initializing";
1382 } else if (printer_state_dyn->printer_status == PRINT_STATUS_SHUTTING_DOWN) {
1383 decoded = "Shutting Down";
1384 } else if (printer_state_dyn->printer_status == PRINT_STATUS_UNABLE_TO_CONNECT) {
1385 decoded = "Unable To Connect";
1386 } else if (printer_state_dyn->printer_status == PRINT_STATUS_UNKNOWN) {
1387 decoded = "Unknown";
1388 } else if (printer_state_dyn->printer_status == PRINT_STATUS_OFFLINE) {
1389 decoded = "Offline";
1390 } else if (printer_state_dyn->printer_status == PRINT_STATUS_IDLE) {
1391 decoded = "Idle";
1392 } else if (printer_state_dyn->printer_status == PRINT_STATUS_PRINTING) {
1393 decoded = "Printing";
1394 } else if (printer_state_dyn->printer_status == PRINT_STATUS_OUT_OF_PAPER) {
1395 decoded = "Out Of Paper";
1396 } else if (printer_state_dyn->printer_status == PRINT_STATUS_OUT_OF_INK) {
1397 decoded = "Out Of Ink";
1398 } else if (printer_state_dyn->printer_status == PRINT_STATUS_JAMMED) {
1399 decoded = "Jammed";
1400 } else if (printer_state_dyn->printer_status == PRINT_STATUS_DOOR_OPEN) {
1401 decoded = "Door Open";
1402 } else if (printer_state_dyn->printer_status == PRINT_STATUS_SVC_REQUEST) {
1403 decoded = "Service Request";
1404 }
1405 LOGD("printer status: %d (%s)", printer_state_dyn->printer_status, decoded);
1406
1407 int idx = 0;
1408 for (idx = 0; idx < (PRINT_STATUS_MAX_STATE + 1); idx++) {
1409 if (PRINT_STATUS_MAX_STATE != printer_state_dyn->printer_reasons[idx]) {
1410 LOGD("printer_reasons (%d): %d", idx, printer_state_dyn->printer_reasons[idx]);
1411 }
1412 }
1413 }
1414
ipp_cups_connect(const wprint_connect_info_t * connect_info,char * printer_uri,unsigned int uriLength)1415 http_t *ipp_cups_connect(const wprint_connect_info_t *connect_info, char *printer_uri,
1416 unsigned int uriLength) {
1417 const char *uri_path;
1418 http_t *curl_http = NULL;
1419
1420 if ((connect_info->uri_path == NULL) || (strlen(connect_info->uri_path) == 0)) {
1421 uri_path = DEFAULT_IPP_URI_RESOURCE;
1422 } else {
1423 uri_path = connect_info->uri_path;
1424 }
1425
1426 int ippPortNumber = ((connect_info->port_num == IPP_PORT) ? ippPort() : connect_info->port_num);
1427
1428 if (strstr(connect_info->uri_scheme,IPPS_PREFIX) != NULL) {
1429 curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPTION_ALWAYS);
1430
1431 // If ALWAYS doesn't work, fall back to REQUIRED
1432 if (curl_http == NULL) {
1433 curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPT_REQUIRED);
1434 }
1435 } else {
1436 curl_http = httpConnectEncrypt(connect_info->printer_addr, ippPortNumber, HTTP_ENCRYPTION_IF_REQUESTED);
1437 }
1438
1439 httpSetTimeout(curl_http, (double)connect_info->timeout / 1000, NULL, 0);
1440 httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, uriLength, connect_info->uri_scheme, NULL,
1441 connect_info->printer_addr, ippPortNumber, uri_path);
1442
1443 if (curl_http == NULL) {
1444 LOGD("ipp_cups_connect failed addr=%s port=%d", connect_info->printer_addr, ippPortNumber);
1445 }
1446 return curl_http;
1447 }
1448
1449 /*
1450 * Send a request using cupsSendRequest(). Loop if we get NULL or CONTINUE. Does not delete
1451 * the request.
1452 */
ippSendRequest(http_t * http,ipp_t * request,char * resource)1453 static ipp_t *ippSendRequest(http_t *http, ipp_t *request, char *resource) {
1454 ipp_t *response = NULL;
1455 http_status_t result;
1456 bool retry;
1457
1458 do {
1459 retry = false;
1460 result = cupsSendRequest(http, request, resource, ippLength(request));
1461 if (result != HTTP_ERROR) {
1462 response = cupsGetResponse(http, resource);
1463 result = httpGetStatus(http);
1464 }
1465
1466 if (result == HTTP_CONTINUE && response == NULL) {
1467 // We need to retry when this happens.
1468 LOGD("ippSendRequest: (Continue with NULL response) Retry");
1469 retry = true;
1470 } else if (result == HTTP_ERROR || result >= HTTP_BAD_REQUEST) {
1471 _cupsSetHTTPError(result);
1472 break;
1473 }
1474
1475 if (http->state != HTTP_WAITING) {
1476 httpFlush(http);
1477 }
1478 } while (retry);
1479
1480 return response;
1481 }
1482
1483 /*
1484 * Call ippDoCupsIORequest, repeating if a failure occurs based on failure conditions, and
1485 * returning the response (or NULL if it failed).
1486 *
1487 * Does not free the request, and the caller must call ippDelete to free any valid response.
1488 */
ipp_doCupsRequest(http_t * http,ipp_t * request,char * http_resource,char * printer_uri)1489 ipp_t *ipp_doCupsRequest(http_t *http, ipp_t *request, char *http_resource, char *printer_uri) {
1490 ipp_status_t ipp_status;
1491 ipp_t *response = NULL;
1492 int service_unavailable_retry_count = 0;
1493 int bad_request_retry_count = 0;
1494 int internal_error_retry_count = 0;
1495 ipp_version_state ipp_version_supported = IPP_VERSION_RESOLVED;
1496
1497 // Fail if any of these parameters are NULL
1498 if (http == NULL || request == NULL || http_resource == NULL || printer_uri == NULL) {
1499 return NULL;
1500 }
1501
1502 do {
1503 // Give up immediately if wprint is done.
1504 if (!wprintIsRunning()) return NULL;
1505
1506 // This is a no-op until we hit the error IPP_VERSION_NOT_SUPPORTED and retry.
1507 if (set_ipp_version(request, printer_uri, http, ipp_version_supported) != 0) {
1508 // We tried to find the correct IPP version by doing a series of get attribute
1509 // requests but they all failed... we give up.
1510 LOGE("ipp_doCupsRequest: set_ipp_version!=0, version not set");
1511 break;
1512 }
1513
1514 response = ippSendRequest(http, request, http_resource);
1515 if (response == NULL) {
1516 ipp_status = cupsLastError();
1517 if (ipp_status == IPP_INTERNAL_ERROR || ipp_status == HTTP_ERROR) {
1518 internal_error_retry_count++;
1519 if (internal_error_retry_count > IPP_INTERNAL_ERROR_MAX_RETRIES) {
1520 break;
1521 }
1522
1523 LOGE("ipp_doCupsRequest: %s %d received, retry %d of %d",
1524 printer_uri, ipp_status, internal_error_retry_count,
1525 IPP_INTERNAL_ERROR_MAX_RETRIES);
1526 continue;
1527 } else if (ipp_status == IPP_SERVICE_UNAVAILABLE) {
1528 service_unavailable_retry_count++;
1529 if (service_unavailable_retry_count > IPP_SERVICE_ERROR_MAX_RETRIES) {
1530 break;
1531 }
1532
1533 LOGE("ipp_doCupsRequest: %s IPP_SERVICE_UNAVAILABLE received, retrying %d of %d",
1534 printer_uri, service_unavailable_retry_count,
1535 IPP_SERVICE_ERROR_MAX_RETRIES);
1536 continue;
1537 } else if (ipp_status == IPP_BAD_REQUEST) {
1538 bad_request_retry_count++;
1539 if (bad_request_retry_count > IPP_BAD_REQUEST_MAX_RETRIES) {
1540 break;
1541 }
1542
1543 LOGD("ipp_doCupsRequest: %s IPP_BAD_REQUEST received. retry (%d) of (%d)",
1544 printer_uri, bad_request_retry_count, IPP_BAD_REQUEST_MAX_RETRIES);
1545 continue;
1546 } else if (ipp_status == IPP_NOT_FOUND) {
1547 LOGE("ipp_doCupsRequest: %s IPP_NOT_FOUND received.", printer_uri);
1548 break;
1549 }
1550 } else {
1551 ipp_status = cupsLastError();
1552 if (ipp_status == IPP_BAD_REQUEST) {
1553 bad_request_retry_count++;
1554 LOGE("ipp_doCupsRequest: %s IPP_BAD_REQUEST received. retry (%d) of (%d)",
1555 printer_uri, bad_request_retry_count, IPP_BAD_REQUEST_MAX_RETRIES);
1556 if (bad_request_retry_count > IPP_BAD_REQUEST_MAX_RETRIES) {
1557 break;
1558 }
1559
1560 ippDelete(response);
1561 response = NULL;
1562 continue;
1563 } else if (ipp_status == IPP_VERSION_NOT_SUPPORTED) {
1564 ipp_version_supported = IPP_VERSION_UNSUPPORTED;
1565 ippDelete(response);
1566 response = NULL;
1567 continue;
1568 }
1569 }
1570 break;
1571 } while (1);
1572
1573 return response;
1574 }