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