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