]>
Commit | Line | Data |
---|---|---|
3b960317 | 1 | /* |
294c916e | 2 | * "$Id: util.c,v 1.81.2.28 2003/10/22 03:17:35 mike Exp $" |
3b960317 | 3 | * |
4 | * Printing utilities for the Common UNIX Printing System (CUPS). | |
5 | * | |
1d9595ab | 6 | * Copyright 1997-2003 by Easy Software Products. |
3b960317 | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
3b960317 | 18 | * Hollywood, Maryland 20636-3111 USA |
19 | * | |
20 | * Voice: (301) 373-9603 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
dab1a4d8 | 24 | * This file is subject to the Apple OS-Developed Software exception. |
25 | * | |
3b960317 | 26 | * Contents: |
27 | * | |
3270670b | 28 | * cupsCancelJob() - Cancel a print job. |
018b8ca8 | 29 | * cupsDoFileRequest() - Do an IPP request... |
b5cb0608 | 30 | * cupsFreeJobs() - Free memory used by job data. |
3270670b | 31 | * cupsGetClasses() - Get a list of printer classes. |
32 | * cupsGetDefault() - Get the default printer or class. | |
b5cb0608 | 33 | * cupsGetJobs() - Get the jobs from the server. |
3270670b | 34 | * cupsGetPPD() - Get the PPD file for a printer. |
35 | * cupsGetPrinters() - Get a list of printers. | |
486cdc15 | 36 | * cupsLastError() - Return the last IPP error that occurred. |
3270670b | 37 | * cupsPrintFile() - Print a file to a printer or class. |
c7c24dd7 | 38 | * cupsPrintFiles() - Print one or more files to a printer or class. |
3270670b | 39 | * cups_connect() - Connect to the specified host... |
3b960317 | 40 | */ |
41 | ||
42 | /* | |
43 | * Include necessary headers... | |
44 | */ | |
45 | ||
46 | #include "cups.h" | |
4a73831b | 47 | #include "language.h" |
48 | #include "string.h" | |
49 | #include "debug.h" | |
aeabf506 | 50 | #include <stdlib.h> |
51 | #include <ctype.h> | |
4a73831b | 52 | #include <errno.h> |
04115410 | 53 | #include <fcntl.h> |
4a73831b | 54 | #include <sys/stat.h> |
d23a857a | 55 | #if defined(WIN32) || defined(__EMX__) |
56 | # include <io.h> | |
57 | #else | |
58 | # include <unistd.h> | |
59 | #endif /* WIN32 || __EMX__ */ | |
3b960317 | 60 | |
61 | ||
113aba7a | 62 | /* |
63 | * Local globals... | |
64 | */ | |
65 | ||
3095105a | 66 | static http_t *cups_server = NULL; /* Current server connection */ |
67 | static ipp_status_t last_error = IPP_OK; /* Last IPP error */ | |
d23a857a | 68 | |
69 | ||
70 | /* | |
71 | * Local functions... | |
72 | */ | |
73 | ||
063e1ac7 | 74 | static char *cups_connect(const char *name, char *printer, char *hostname); |
113aba7a | 75 | |
76 | ||
8431231f | 77 | /* |
78 | * 'cupsCancelJob()' - Cancel a print job. | |
79 | */ | |
80 | ||
3ec5b662 | 81 | int /* O - 1 on success, 0 on failure */ |
82 | cupsCancelJob(const char *name, /* I - Name of printer or class */ | |
83 | int job) /* I - Job ID */ | |
3b960317 | 84 | { |
d23a857a | 85 | char printer[HTTP_MAX_URI], /* Printer name */ |
86 | hostname[HTTP_MAX_URI], /* Hostname */ | |
87 | uri[HTTP_MAX_URI]; /* Printer URI */ | |
88 | ipp_t *request, /* IPP request */ | |
89 | *response; /* IPP response */ | |
90 | cups_lang_t *language; /* Language info */ | |
91 | ||
92 | ||
93 | /* | |
94 | * See if we can connect to the server... | |
95 | */ | |
96 | ||
97 | if (!cups_connect(name, printer, hostname)) | |
9aebebc3 | 98 | { |
dd63ebe2 | 99 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 100 | last_error = IPP_SERVICE_UNAVAILABLE; |
2bffb563 | 101 | return (0); |
9aebebc3 | 102 | } |
d23a857a | 103 | |
104 | /* | |
105 | * Build an IPP_CANCEL_JOB request, which requires the following | |
106 | * attributes: | |
107 | * | |
108 | * attributes-charset | |
109 | * attributes-natural-language | |
110 | * printer-uri | |
111 | * job-id | |
8b06ca19 | 112 | * [requesting-user-name] |
d23a857a | 113 | */ |
114 | ||
115 | request = ippNew(); | |
116 | ||
0a3ac972 | 117 | request->request.op.operation_id = IPP_CANCEL_JOB; |
118 | request->request.op.request_id = 1; | |
d23a857a | 119 | |
120 | language = cupsLangDefault(); | |
121 | ||
122 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
123 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
124 | ||
125 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
126 | "attributes-natural-language", NULL, | |
127 | language != NULL ? language->language : "C"); | |
128 | ||
04de52f8 | 129 | snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); |
d23a857a | 130 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
131 | NULL, uri); | |
132 | ||
6d0582d2 | 133 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); |
d23a857a | 134 | |
8b06ca19 | 135 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", |
136 | NULL, cupsUser()); | |
137 | ||
d23a857a | 138 | /* |
139 | * Do the request... | |
140 | */ | |
141 | ||
294c916e | 142 | if ((response = cupsDoRequest(cups_server, request, "/jobs/")) != NULL) |
8b06ca19 | 143 | ippDelete(response); |
d23a857a | 144 | |
294c916e | 145 | return (last_error < IPP_REDIRECTION_OTHER_SITE); |
3b960317 | 146 | } |
147 | ||
148 | ||
113aba7a | 149 | /* |
3270670b | 150 | * 'cupsDoFileRequest()' - Do an IPP request... |
113aba7a | 151 | */ |
152 | ||
3270670b | 153 | ipp_t * /* O - Response data */ |
063e1ac7 | 154 | cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ |
155 | ipp_t *request, /* I - IPP request */ | |
156 | const char *resource, /* I - HTTP resource for POST */ | |
157 | const char *filename) /* I - File to send or NULL */ | |
113aba7a | 158 | { |
83e740a5 | 159 | ipp_t *response; /* IPP response data */ |
160 | char length[255]; /* Content-Length field */ | |
161 | http_status_t status; /* Status of HTTP request */ | |
162 | FILE *file; /* File to send */ | |
163 | struct stat fileinfo; /* File information */ | |
164 | int bytes; /* Number of bytes read/written */ | |
753453e4 | 165 | char buffer[32768]; /* Output buffer */ |
113aba7a | 166 | |
167 | ||
dd63ebe2 | 168 | DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n", |
169 | http, request, resource ? resource : "(null)", | |
170 | filename ? filename : "(null)")); | |
171 | ||
0f6a2276 | 172 | if (http == NULL || request == NULL || resource == NULL) |
173 | { | |
174 | if (request != NULL) | |
175 | ippDelete(request); | |
176 | ||
177 | last_error = IPP_INTERNAL_ERROR; | |
178 | return (NULL); | |
179 | } | |
180 | ||
113aba7a | 181 | /* |
3270670b | 182 | * See if we have a file to send... |
113aba7a | 183 | */ |
184 | ||
3270670b | 185 | if (filename != NULL) |
186 | { | |
187 | if (stat(filename, &fileinfo)) | |
188 | { | |
189 | /* | |
190 | * Can't get file information! | |
191 | */ | |
113aba7a | 192 | |
3270670b | 193 | ippDelete(request); |
9aebebc3 | 194 | last_error = IPP_NOT_FOUND; |
3270670b | 195 | return (NULL); |
196 | } | |
113aba7a | 197 | |
3ec5b662 | 198 | #ifdef WIN32 |
199 | if (fileinfo.st_mode & _S_IFDIR) | |
200 | #else | |
fba7409c | 201 | if (S_ISDIR(fileinfo.st_mode)) |
3ec5b662 | 202 | #endif /* WIN32 */ |
fba7409c | 203 | { |
204 | /* | |
205 | * Can't send a directory... | |
206 | */ | |
207 | ||
208 | ippDelete(request); | |
209 | last_error = IPP_NOT_POSSIBLE; | |
210 | return (NULL); | |
211 | } | |
212 | ||
3270670b | 213 | if ((file = fopen(filename, "rb")) == NULL) |
877378d9 | 214 | { |
3270670b | 215 | /* |
216 | * Can't open file! | |
217 | */ | |
218 | ||
877378d9 | 219 | ippDelete(request); |
9aebebc3 | 220 | last_error = IPP_NOT_FOUND; |
877378d9 | 221 | return (NULL); |
222 | } | |
3270670b | 223 | } |
d21a7597 | 224 | else |
225 | file = NULL; | |
113aba7a | 226 | |
227 | /* | |
3270670b | 228 | * Loop until we can send the request without authorization problems. |
113aba7a | 229 | */ |
230 | ||
3270670b | 231 | response = NULL; |
d21a7597 | 232 | status = HTTP_ERROR; |
d23a857a | 233 | |
3270670b | 234 | while (response == NULL) |
d23a857a | 235 | { |
3270670b | 236 | DEBUG_puts("cupsDoFileRequest: setup..."); |
237 | ||
d23a857a | 238 | /* |
3270670b | 239 | * Setup the HTTP variables needed... |
d23a857a | 240 | */ |
241 | ||
3270670b | 242 | if (filename != NULL) |
753453e4 | 243 | sprintf(length, "%lu", (unsigned long)(ippLength(request) + |
244 | (size_t)fileinfo.st_size)); | |
3270670b | 245 | else |
753453e4 | 246 | sprintf(length, "%lu", (unsigned long)ippLength(request)); |
d23a857a | 247 | |
3270670b | 248 | httpClearFields(http); |
249 | httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); | |
250 | httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); | |
3ec5b662 | 251 | httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); |
3270670b | 252 | |
3ec5b662 | 253 | DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring)); |
c3c5af5e | 254 | |
3270670b | 255 | /* |
256 | * Try the request... | |
257 | */ | |
258 | ||
259 | DEBUG_puts("cupsDoFileRequest: post..."); | |
260 | ||
261 | if (httpPost(http, resource)) | |
dbb05cda | 262 | { |
263 | if (httpReconnect(http)) | |
264 | { | |
9d13ae31 | 265 | status = HTTP_ERROR; |
dbb05cda | 266 | break; |
267 | } | |
268 | else | |
269 | continue; | |
270 | } | |
3270670b | 271 | |
272 | /* | |
273 | * Send the IPP data and wait for the response... | |
274 | */ | |
275 | ||
276 | DEBUG_puts("cupsDoFileRequest: ipp write..."); | |
277 | ||
278 | request->state = IPP_IDLE; | |
018b8ca8 | 279 | if (ippWrite(http, request) != IPP_ERROR) |
280 | if (filename != NULL) | |
281 | { | |
282 | DEBUG_puts("cupsDoFileRequest: file write..."); | |
d23a857a | 283 | |
018b8ca8 | 284 | /* |
285 | * Send the file... | |
286 | */ | |
d23a857a | 287 | |
018b8ca8 | 288 | rewind(file); |
d23a857a | 289 | |
018b8ca8 | 290 | while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) |
0669cbc7 | 291 | { |
292 | if (httpCheck(http)) | |
293 | break; | |
294 | ||
018b8ca8 | 295 | if (httpWrite(http, buffer, bytes) < bytes) |
296 | break; | |
0669cbc7 | 297 | } |
018b8ca8 | 298 | } |
d23a857a | 299 | |
d23a857a | 300 | /* |
3270670b | 301 | * Get the server's return status... |
d23a857a | 302 | */ |
303 | ||
3270670b | 304 | DEBUG_puts("cupsDoFileRequest: update..."); |
d23a857a | 305 | |
018b8ca8 | 306 | while ((status = httpUpdate(http)) == HTTP_CONTINUE); |
307 | ||
c3c5af5e | 308 | DEBUG_printf(("cupsDoFileRequest: status = %d\n", status)); |
309 | ||
018b8ca8 | 310 | if (status == HTTP_UNAUTHORIZED) |
3270670b | 311 | { |
312 | DEBUG_puts("cupsDoFileRequest: unauthorized..."); | |
113aba7a | 313 | |
3270670b | 314 | /* |
315 | * Flush any error message... | |
316 | */ | |
317 | ||
318 | httpFlush(http); | |
d2122fde | 319 | |
320 | /* | |
3ec5b662 | 321 | * See if we can do authentication... |
d2122fde | 322 | */ |
323 | ||
3ec5b662 | 324 | if (cupsDoAuthentication(http, "POST", resource)) |
325 | break; | |
83e740a5 | 326 | |
3ec5b662 | 327 | httpReconnect(http); |
83e740a5 | 328 | |
3ec5b662 | 329 | continue; |
3270670b | 330 | } |
77be8777 | 331 | else if (status == HTTP_ERROR) |
332 | { | |
c3026ddc | 333 | #ifdef WIN32 |
977acbd3 | 334 | if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH) |
335 | #else | |
77be8777 | 336 | if (http->error != ENETDOWN && http->error != ENETUNREACH) |
c3026ddc | 337 | #endif /* WIN32 */ |
77be8777 | 338 | continue; |
339 | else | |
340 | break; | |
341 | } | |
bcf61448 | 342 | #ifdef HAVE_SSL |
b5cb0608 | 343 | else if (status == HTTP_UPGRADE_REQUIRED) |
344 | { | |
345 | /* | |
346 | * Flush any error message... | |
347 | */ | |
348 | ||
349 | httpFlush(http); | |
350 | ||
3ec5b662 | 351 | /* |
352 | * Upgrade with encryption... | |
353 | */ | |
354 | ||
355 | httpEncryption(http, HTTP_ENCRYPT_REQUIRED); | |
356 | ||
b5cb0608 | 357 | /* |
358 | * Try again, this time with encryption enabled... | |
359 | */ | |
360 | ||
361 | continue; | |
362 | } | |
bcf61448 | 363 | #endif /* HAVE_SSL */ |
77be8777 | 364 | else if (status != HTTP_OK) |
113aba7a | 365 | { |
3270670b | 366 | DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); |
d23a857a | 367 | |
368 | /* | |
3270670b | 369 | * Flush any error message... |
d23a857a | 370 | */ |
371 | ||
69ee1496 | 372 | httpFlush(http); |
3270670b | 373 | break; |
374 | } | |
375 | else | |
376 | { | |
377 | /* | |
378 | * Read the response... | |
379 | */ | |
380 | ||
381 | DEBUG_puts("cupsDoFileRequest: response..."); | |
382 | ||
383 | response = ippNew(); | |
384 | ||
385 | if (ippRead(http, response) == IPP_ERROR) | |
386 | { | |
387 | /* | |
388 | * Delete the response... | |
389 | */ | |
390 | ||
dd63ebe2 | 391 | DEBUG_puts("IPP read error!"); |
3270670b | 392 | ippDelete(response); |
393 | response = NULL; | |
394 | ||
9aebebc3 | 395 | last_error = IPP_SERVICE_UNAVAILABLE; |
3270670b | 396 | break; |
397 | } | |
113aba7a | 398 | } |
399 | } | |
400 | ||
3270670b | 401 | /* |
402 | * Close the file if needed... | |
403 | */ | |
404 | ||
405 | if (filename != NULL) | |
406 | fclose(file); | |
407 | ||
f37fe731 | 408 | /* |
409 | * Flush any remaining data... | |
410 | */ | |
411 | ||
412 | httpFlush(http); | |
413 | ||
113aba7a | 414 | /* |
415 | * Delete the original request and return the response... | |
416 | */ | |
417 | ||
418 | ippDelete(request); | |
419 | ||
9aebebc3 | 420 | if (response) |
0a3ac972 | 421 | last_error = response->request.status.status_code; |
9aebebc3 | 422 | else if (status != HTTP_OK) |
dd63ebe2 | 423 | { |
aa7b8dba | 424 | switch (status) |
425 | { | |
426 | case HTTP_NOT_FOUND : | |
427 | last_error = IPP_NOT_FOUND; | |
428 | break; | |
429 | ||
430 | case HTTP_UNAUTHORIZED : | |
431 | last_error = IPP_NOT_AUTHORIZED; | |
432 | break; | |
433 | ||
434 | case HTTP_FORBIDDEN : | |
435 | last_error = IPP_FORBIDDEN; | |
436 | break; | |
437 | ||
438 | case HTTP_BAD_REQUEST : | |
439 | last_error = IPP_BAD_REQUEST; | |
440 | break; | |
441 | ||
442 | case HTTP_REQUEST_TOO_LARGE : | |
443 | last_error = IPP_REQUEST_VALUE; | |
444 | break; | |
445 | ||
446 | case HTTP_NOT_IMPLEMENTED : | |
447 | last_error = IPP_OPERATION_NOT_SUPPORTED; | |
448 | break; | |
449 | ||
450 | case HTTP_NOT_SUPPORTED : | |
451 | last_error = IPP_VERSION_NOT_SUPPORTED; | |
452 | break; | |
453 | ||
454 | default : | |
455 | DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n", | |
456 | status)); | |
457 | last_error = IPP_SERVICE_UNAVAILABLE; | |
458 | break; | |
459 | } | |
dd63ebe2 | 460 | } |
9aebebc3 | 461 | |
113aba7a | 462 | return (response); |
463 | } | |
464 | ||
465 | ||
b5cb0608 | 466 | /* |
467 | * 'cupsFreeJobs()' - Free memory used by job data. | |
468 | */ | |
469 | ||
470 | void | |
3ec5b662 | 471 | cupsFreeJobs(int num_jobs, /* I - Number of jobs */ |
472 | cups_job_t *jobs) /* I - Jobs */ | |
b5cb0608 | 473 | { |
3ec5b662 | 474 | int i; /* Looping var */ |
b5cb0608 | 475 | |
476 | ||
477 | if (num_jobs <= 0 || jobs == NULL) | |
478 | return; | |
479 | ||
480 | for (i = 0; i < num_jobs; i ++) | |
481 | { | |
482 | free(jobs[i].dest); | |
483 | free(jobs[i].user); | |
484 | free(jobs[i].format); | |
485 | free(jobs[i].title); | |
486 | } | |
487 | ||
488 | free(jobs); | |
489 | } | |
490 | ||
491 | ||
8431231f | 492 | /* |
493 | * 'cupsGetClasses()' - Get a list of printer classes. | |
494 | */ | |
495 | ||
3ec5b662 | 496 | int /* O - Number of classes */ |
497 | cupsGetClasses(char ***classes) /* O - Classes */ | |
3b960317 | 498 | { |
3ec5b662 | 499 | int n; /* Number of classes */ |
500 | ipp_t *request, /* IPP Request */ | |
501 | *response; /* IPP Response */ | |
502 | ipp_attribute_t *attr; /* Current attribute */ | |
503 | cups_lang_t *language; /* Default language */ | |
504 | char **temp; /* Temporary pointer */ | |
d23a857a | 505 | |
506 | ||
0f6a2276 | 507 | if (classes == NULL) |
508 | { | |
509 | last_error = IPP_INTERNAL_ERROR; | |
510 | return (0); | |
511 | } | |
512 | ||
d23a857a | 513 | /* |
514 | * Try to connect to the server... | |
515 | */ | |
516 | ||
517 | if (!cups_connect("default", NULL, NULL)) | |
9aebebc3 | 518 | { |
dd63ebe2 | 519 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 520 | last_error = IPP_SERVICE_UNAVAILABLE; |
2bffb563 | 521 | return (0); |
9aebebc3 | 522 | } |
d23a857a | 523 | |
524 | /* | |
525 | * Build a CUPS_GET_CLASSES request, which requires the following | |
526 | * attributes: | |
527 | * | |
528 | * attributes-charset | |
529 | * attributes-natural-language | |
27d555e8 | 530 | * requested-attributes |
d23a857a | 531 | */ |
532 | ||
533 | request = ippNew(); | |
534 | ||
0a3ac972 | 535 | request->request.op.operation_id = CUPS_GET_CLASSES; |
536 | request->request.op.request_id = 1; | |
d23a857a | 537 | |
538 | language = cupsLangDefault(); | |
539 | ||
540 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
a9b97a87 | 541 | "attributes-charset", NULL, cupsLangEncoding(language)); |
d23a857a | 542 | |
543 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
a9b97a87 | 544 | "attributes-natural-language", NULL, language->language); |
d23a857a | 545 | |
27d555e8 | 546 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
547 | "requested-attributes", NULL, "printer-name"); | |
548 | ||
d23a857a | 549 | /* |
550 | * Do the request and get back a response... | |
551 | */ | |
552 | ||
553 | n = 0; | |
554 | *classes = NULL; | |
555 | ||
a9b97a87 | 556 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
d23a857a | 557 | { |
0a3ac972 | 558 | last_error = response->request.status.status_code; |
8b06ca19 | 559 | |
d23a857a | 560 | for (attr = response->attrs; attr != NULL; attr = attr->next) |
fbc6b634 | 561 | if (attr->name != NULL && |
562 | strcasecmp(attr->name, "printer-name") == 0 && | |
d23a857a | 563 | attr->value_tag == IPP_TAG_NAME) |
564 | { | |
565 | if (n == 0) | |
a9b97a87 | 566 | temp = malloc(sizeof(char *)); |
d23a857a | 567 | else |
a9b97a87 | 568 | temp = realloc(*classes, sizeof(char *) * (n + 1)); |
d23a857a | 569 | |
a9b97a87 | 570 | if (temp == NULL) |
d23a857a | 571 | { |
a9b97a87 | 572 | /* |
573 | * Ran out of memory! | |
574 | */ | |
575 | ||
576 | while (n > 0) | |
577 | { | |
578 | n --; | |
579 | free((*classes)[n]); | |
580 | } | |
581 | ||
582 | free(*classes); | |
d23a857a | 583 | ippDelete(response); |
584 | return (0); | |
585 | } | |
586 | ||
a9b97a87 | 587 | *classes = temp; |
588 | temp[n] = strdup(attr->values[0].string.text); | |
d23a857a | 589 | n ++; |
590 | } | |
591 | ||
592 | ippDelete(response); | |
593 | } | |
8b06ca19 | 594 | else |
595 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 596 | |
597 | return (n); | |
3b960317 | 598 | } |
599 | ||
600 | ||
8431231f | 601 | /* |
602 | * 'cupsGetDefault()' - Get the default printer or class. | |
603 | */ | |
604 | ||
3ec5b662 | 605 | const char * /* O - Default printer or NULL */ |
4a73831b | 606 | cupsGetDefault(void) |
607 | { | |
3ec5b662 | 608 | ipp_t *request, /* IPP Request */ |
609 | *response; /* IPP Response */ | |
610 | ipp_attribute_t *attr; /* Current attribute */ | |
611 | cups_lang_t *language; /* Default language */ | |
612 | const char *var; /* Environment variable */ | |
613 | static char def_printer[256]; /* Default printer */ | |
113aba7a | 614 | |
615 | ||
616 | /* | |
617 | * First see if the LPDEST or PRINTER environment variables are | |
9aebebc3 | 618 | * set... However, if PRINTER is set to "lp", ignore it to work |
619 | * around a "feature" in most Linux distributions - the default | |
620 | * user login scripts set PRINTER to "lp"... | |
113aba7a | 621 | */ |
622 | ||
9aebebc3 | 623 | if ((var = getenv("LPDEST")) != NULL) |
624 | return (var); | |
625 | else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) | |
626 | return (var); | |
113aba7a | 627 | |
628 | /* | |
629 | * Try to connect to the server... | |
630 | */ | |
631 | ||
d23a857a | 632 | if (!cups_connect("default", NULL, NULL)) |
9aebebc3 | 633 | { |
dd63ebe2 | 634 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 635 | last_error = IPP_SERVICE_UNAVAILABLE; |
d23a857a | 636 | return (NULL); |
9aebebc3 | 637 | } |
113aba7a | 638 | |
639 | /* | |
640 | * Build a CUPS_GET_DEFAULT request, which requires the following | |
641 | * attributes: | |
642 | * | |
643 | * attributes-charset | |
644 | * attributes-natural-language | |
645 | */ | |
646 | ||
647 | request = ippNew(); | |
648 | ||
0a3ac972 | 649 | request->request.op.operation_id = CUPS_GET_DEFAULT; |
650 | request->request.op.request_id = 1; | |
113aba7a | 651 | |
652 | language = cupsLangDefault(); | |
653 | ||
d23a857a | 654 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
655 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
113aba7a | 656 | |
d23a857a | 657 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
658 | "attributes-natural-language", NULL, language->language); | |
113aba7a | 659 | |
660 | /* | |
661 | * Do the request and get back a response... | |
662 | */ | |
663 | ||
8b06ca19 | 664 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
113aba7a | 665 | { |
0a3ac972 | 666 | last_error = response->request.status.status_code; |
8b06ca19 | 667 | |
113aba7a | 668 | if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) |
669 | { | |
def978d5 | 670 | strlcpy(def_printer, attr->values[0].string.text, sizeof(def_printer)); |
113aba7a | 671 | ippDelete(response); |
672 | return (def_printer); | |
673 | } | |
674 | ||
675 | ippDelete(response); | |
676 | } | |
8b06ca19 | 677 | else |
678 | last_error = IPP_BAD_REQUEST; | |
113aba7a | 679 | |
680 | return (NULL); | |
4a73831b | 681 | } |
682 | ||
683 | ||
b5cb0608 | 684 | /* |
685 | * 'cupsGetJobs()' - Get the jobs from the server. | |
686 | */ | |
687 | ||
688 | int /* O - Number of jobs */ | |
689 | cupsGetJobs(cups_job_t **jobs, /* O - Job data */ | |
690 | const char *mydest, /* I - Only show jobs for dest? */ | |
691 | int myjobs, /* I - Only show my jobs? */ | |
692 | int completed) /* I - Only show completed jobs? */ | |
693 | { | |
694 | int n; /* Number of jobs */ | |
695 | ipp_t *request, /* IPP Request */ | |
696 | *response; /* IPP Response */ | |
697 | ipp_attribute_t *attr; /* Current attribute */ | |
698 | cups_lang_t *language; /* Default language */ | |
699 | cups_job_t *temp; /* Temporary pointer */ | |
700 | int id, /* job-id */ | |
701 | priority, /* job-priority */ | |
702 | size; /* job-k-octets */ | |
703 | ipp_jstate_t state; /* job-state */ | |
704 | time_t completed_time, /* time-at-completed */ | |
705 | creation_time, /* time-at-creation */ | |
706 | processing_time; /* time-at-processing */ | |
707 | const char *dest, /* job-printer-uri */ | |
708 | *format, /* document-format */ | |
709 | *title, /* job-name */ | |
710 | *user; /* job-originating-user-name */ | |
711 | char uri[HTTP_MAX_URI]; /* URI for jobs */ | |
6db7190f | 712 | static const char * const attrs[] = /* Requested attributes */ |
b5cb0608 | 713 | { |
714 | "job-id", | |
715 | "job-priority", | |
716 | "job-k-octets", | |
717 | "job-state", | |
718 | "time-at-completed", | |
719 | "time-at-creation", | |
720 | "time-at-processing", | |
721 | "job-printer-uri", | |
722 | "document-format", | |
723 | "job-name", | |
724 | "job-originating-user-name" | |
725 | }; | |
726 | ||
727 | ||
728 | if (jobs == NULL) | |
729 | { | |
730 | last_error = IPP_INTERNAL_ERROR; | |
731 | return (0); | |
732 | } | |
733 | ||
734 | /* | |
735 | * Try to connect to the server... | |
736 | */ | |
737 | ||
738 | if (!cups_connect("default", NULL, NULL)) | |
739 | { | |
dd63ebe2 | 740 | DEBUG_puts("Unable to connect to server!"); |
b5cb0608 | 741 | last_error = IPP_SERVICE_UNAVAILABLE; |
742 | return (0); | |
743 | } | |
744 | ||
745 | /* | |
746 | * Build an IPP_GET_JOBS request, which requires the following | |
747 | * attributes: | |
748 | * | |
749 | * attributes-charset | |
750 | * attributes-natural-language | |
751 | * printer-uri | |
752 | * requesting-user-name | |
753 | * which-jobs | |
754 | * my-jobs | |
755 | * requested-attributes | |
756 | */ | |
757 | ||
758 | request = ippNew(); | |
759 | ||
0a3ac972 | 760 | request->request.op.operation_id = IPP_GET_JOBS; |
761 | request->request.op.request_id = 1; | |
b5cb0608 | 762 | |
763 | language = cupsLangDefault(); | |
764 | ||
765 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
766 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
767 | ||
768 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
769 | "attributes-natural-language", NULL, language->language); | |
770 | ||
771 | if (mydest) | |
772 | snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", mydest); | |
773 | else | |
774 | strcpy(uri, "ipp://localhost/jobs"); | |
775 | ||
776 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, | |
777 | "printer-uri", NULL, uri); | |
778 | ||
779 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, | |
780 | "requesting-user-name", NULL, cupsUser()); | |
781 | ||
782 | if (myjobs) | |
783 | ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); | |
784 | ||
785 | if (completed) | |
786 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
787 | "which-jobs", NULL, "completed"); | |
788 | ||
789 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
790 | "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), | |
791 | NULL, attrs); | |
792 | ||
793 | /* | |
794 | * Do the request and get back a response... | |
795 | */ | |
796 | ||
797 | n = 0; | |
798 | *jobs = NULL; | |
799 | ||
800 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) | |
801 | { | |
0a3ac972 | 802 | last_error = response->request.status.status_code; |
b5cb0608 | 803 | |
804 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
805 | { | |
806 | /* | |
807 | * Skip leading attributes until we hit a job... | |
808 | */ | |
809 | ||
810 | while (attr != NULL && attr->group_tag != IPP_TAG_JOB) | |
811 | attr = attr->next; | |
812 | ||
813 | if (attr == NULL) | |
814 | break; | |
815 | ||
816 | /* | |
817 | * Pull the needed attributes from this job... | |
818 | */ | |
819 | ||
820 | id = 0; | |
821 | size = 0; | |
822 | priority = 50; | |
823 | state = IPP_JOB_PENDING; | |
02543a3f | 824 | user = "unknown"; |
b5cb0608 | 825 | dest = NULL; |
02543a3f | 826 | format = "application/octet-stream"; |
827 | title = "untitled"; | |
b5cb0608 | 828 | creation_time = 0; |
829 | completed_time = 0; | |
830 | processing_time = 0; | |
831 | ||
832 | while (attr != NULL && attr->group_tag == IPP_TAG_JOB) | |
833 | { | |
834 | if (strcmp(attr->name, "job-id") == 0 && | |
835 | attr->value_tag == IPP_TAG_INTEGER) | |
836 | id = attr->values[0].integer; | |
837 | else if (strcmp(attr->name, "job-state") == 0 && | |
838 | attr->value_tag == IPP_TAG_ENUM) | |
839 | state = (ipp_jstate_t)attr->values[0].integer; | |
840 | else if (strcmp(attr->name, "job-priority") == 0 && | |
841 | attr->value_tag == IPP_TAG_INTEGER) | |
842 | priority = attr->values[0].integer; | |
843 | else if (strcmp(attr->name, "job-k-octets") == 0 && | |
844 | attr->value_tag == IPP_TAG_INTEGER) | |
845 | size = attr->values[0].integer; | |
846 | else if (strcmp(attr->name, "time-at-completed") == 0 && | |
847 | attr->value_tag == IPP_TAG_INTEGER) | |
848 | completed_time = attr->values[0].integer; | |
849 | else if (strcmp(attr->name, "time-at-creation") == 0 && | |
850 | attr->value_tag == IPP_TAG_INTEGER) | |
851 | creation_time = attr->values[0].integer; | |
852 | else if (strcmp(attr->name, "time-at-processing") == 0 && | |
853 | attr->value_tag == IPP_TAG_INTEGER) | |
854 | processing_time = attr->values[0].integer; | |
855 | else if (strcmp(attr->name, "job-printer-uri") == 0 && | |
856 | attr->value_tag == IPP_TAG_URI) | |
857 | { | |
858 | if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) | |
859 | dest ++; | |
860 | } | |
861 | else if (strcmp(attr->name, "job-originating-user-name") == 0 && | |
862 | attr->value_tag == IPP_TAG_NAME) | |
863 | user = attr->values[0].string.text; | |
864 | else if (strcmp(attr->name, "document-format") == 0 && | |
865 | attr->value_tag == IPP_TAG_MIMETYPE) | |
866 | format = attr->values[0].string.text; | |
867 | else if (strcmp(attr->name, "job-name") == 0 && | |
59168282 | 868 | (attr->value_tag == IPP_TAG_TEXT || |
869 | attr->value_tag == IPP_TAG_NAME)) | |
b5cb0608 | 870 | title = attr->values[0].string.text; |
871 | ||
872 | attr = attr->next; | |
873 | } | |
874 | ||
875 | /* | |
876 | * See if we have everything needed... | |
877 | */ | |
878 | ||
02543a3f | 879 | if (dest == NULL || id == 0) |
b5cb0608 | 880 | { |
881 | if (attr == NULL) | |
882 | break; | |
883 | else | |
884 | continue; | |
885 | } | |
886 | ||
887 | /* | |
888 | * Allocate memory for the job... | |
889 | */ | |
890 | ||
891 | if (n == 0) | |
892 | temp = malloc(sizeof(cups_job_t)); | |
893 | else | |
894 | temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1)); | |
895 | ||
896 | if (temp == NULL) | |
897 | { | |
898 | /* | |
899 | * Ran out of memory! | |
900 | */ | |
901 | ||
902 | cupsFreeJobs(n, *jobs); | |
903 | *jobs = NULL; | |
904 | ||
905 | ippDelete(response); | |
906 | return (0); | |
907 | } | |
908 | ||
909 | *jobs = temp; | |
910 | temp += n; | |
911 | n ++; | |
912 | ||
913 | /* | |
914 | * Copy the data over... | |
915 | */ | |
916 | ||
917 | temp->dest = strdup(dest); | |
918 | temp->user = strdup(user); | |
919 | temp->format = strdup(format); | |
920 | temp->title = strdup(title); | |
921 | temp->id = id; | |
922 | temp->priority = priority; | |
923 | temp->state = state; | |
924 | temp->size = size; | |
925 | temp->completed_time = completed_time; | |
926 | temp->creation_time = creation_time; | |
927 | temp->processing_time = processing_time; | |
59168282 | 928 | |
929 | if (attr == NULL) | |
930 | break; | |
b5cb0608 | 931 | } |
932 | ||
933 | ippDelete(response); | |
934 | } | |
935 | else | |
936 | last_error = IPP_BAD_REQUEST; | |
937 | ||
938 | return (n); | |
939 | } | |
940 | ||
941 | ||
8431231f | 942 | /* |
943 | * 'cupsGetPPD()' - Get the PPD file for a printer. | |
944 | */ | |
945 | ||
83e740a5 | 946 | const char * /* O - Filename for PPD file */ |
947 | cupsGetPPD(const char *name) /* I - Printer name */ | |
3b960317 | 948 | { |
ce314a94 | 949 | int i; /* Looping var */ |
bc16fd64 | 950 | ipp_t *request, /* IPP request */ |
951 | *response; /* IPP response */ | |
952 | ipp_attribute_t *attr; /* Current attribute */ | |
953 | cups_lang_t *language; /* Local language */ | |
1b5bf964 | 954 | int fd; /* PPD file */ |
aa7b8dba | 955 | char uri[HTTP_MAX_URI], /* Printer URI */ |
956 | printer[HTTP_MAX_URI], /* Printer name */ | |
bc16fd64 | 957 | method[HTTP_MAX_URI], /* Method/scheme name */ |
958 | username[HTTP_MAX_URI], /* Username:password */ | |
d23a857a | 959 | hostname[HTTP_MAX_URI], /* Hostname */ |
960 | resource[HTTP_MAX_URI]; /* Resource name */ | |
bc16fd64 | 961 | int port; /* Port number */ |
3095105a | 962 | http_status_t status; /* HTTP status from server */ |
963 | static char filename[HTTP_MAX_URI]; /* Local filename */ | |
6db7190f | 964 | static const char * const requested_attrs[] = |
965 | { /* Requested attributes */ | |
ce314a94 | 966 | "printer-uri-supported", |
967 | "printer-type", | |
968 | "member-uris" | |
969 | }; | |
d23a857a | 970 | |
971 | ||
3ec5b662 | 972 | /* |
973 | * Range check input... | |
974 | */ | |
975 | ||
0f6a2276 | 976 | if (name == NULL) |
977 | { | |
978 | last_error = IPP_INTERNAL_ERROR; | |
979 | return (NULL); | |
980 | } | |
981 | ||
d23a857a | 982 | /* |
983 | * See if we can connect to the server... | |
984 | */ | |
985 | ||
986 | if (!cups_connect(name, printer, hostname)) | |
9aebebc3 | 987 | { |
dd63ebe2 | 988 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 989 | last_error = IPP_SERVICE_UNAVAILABLE; |
d23a857a | 990 | return (NULL); |
9aebebc3 | 991 | } |
d23a857a | 992 | |
ce314a94 | 993 | /* |
994 | * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following | |
995 | * attributes: | |
996 | * | |
997 | * attributes-charset | |
998 | * attributes-natural-language | |
999 | * printer-uri | |
1000 | * requested-attributes | |
1001 | */ | |
1002 | ||
1003 | request = ippNew(); | |
1004 | ||
0a3ac972 | 1005 | request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; |
1006 | request->request.op.request_id = 1; | |
bc16fd64 | 1007 | |
ce314a94 | 1008 | language = cupsLangDefault(); |
bc16fd64 | 1009 | |
ce314a94 | 1010 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
1011 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
bc16fd64 | 1012 | |
ce314a94 | 1013 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
1014 | "attributes-natural-language", NULL, language->language); | |
bc16fd64 | 1015 | |
aa7b8dba | 1016 | snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); |
ce314a94 | 1017 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, |
aa7b8dba | 1018 | "printer-uri", NULL, uri); |
bc16fd64 | 1019 | |
ce314a94 | 1020 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, |
1021 | "requested-attributes", | |
1022 | sizeof(requested_attrs) / sizeof(requested_attrs[0]), | |
1023 | NULL, requested_attrs); | |
bc16fd64 | 1024 | |
ce314a94 | 1025 | /* |
1026 | * Do the request and get back a response... | |
1027 | */ | |
bc16fd64 | 1028 | |
ce314a94 | 1029 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
1030 | { | |
0a3ac972 | 1031 | last_error = response->request.status.status_code; |
ce314a94 | 1032 | printer[0] = '\0'; |
1033 | hostname[0] = '\0'; | |
bc16fd64 | 1034 | |
ce314a94 | 1035 | if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) |
bc16fd64 | 1036 | { |
ce314a94 | 1037 | /* |
1038 | * Get the first actual server and printer name in the class... | |
1039 | */ | |
bc16fd64 | 1040 | |
ce314a94 | 1041 | for (i = 0; i < attr->num_values; i ++) |
bc16fd64 | 1042 | { |
ce314a94 | 1043 | httpSeparate(attr->values[0].string.text, method, username, hostname, |
bc16fd64 | 1044 | &port, resource); |
ce314a94 | 1045 | if (strncmp(resource, "/printers/", 10) == 0) |
1046 | { | |
1047 | /* | |
1048 | * Found a printer! | |
1049 | */ | |
bc16fd64 | 1050 | |
def978d5 | 1051 | strlcpy(printer, resource + 10, sizeof(printer)); |
ce314a94 | 1052 | break; |
1053 | } | |
bc16fd64 | 1054 | } |
ce314a94 | 1055 | } |
1056 | else if ((attr = ippFindAttribute(response, "printer-uri-supported", | |
1057 | IPP_TAG_URI)) != NULL) | |
1058 | { | |
1059 | /* | |
1060 | * Get the actual server and printer names... | |
1061 | */ | |
bc16fd64 | 1062 | |
ce314a94 | 1063 | httpSeparate(attr->values[0].string.text, method, username, hostname, |
1064 | &port, resource); | |
def978d5 | 1065 | strlcpy(printer, strrchr(resource, '/') + 1, sizeof(printer)); |
bc16fd64 | 1066 | } |
1067 | ||
ce314a94 | 1068 | ippDelete(response); |
bc16fd64 | 1069 | |
1070 | /* | |
ce314a94 | 1071 | * Remap local hostname to localhost... |
bc16fd64 | 1072 | */ |
1073 | ||
aa7b8dba | 1074 | gethostname(uri, sizeof(uri)); |
bc16fd64 | 1075 | |
aa7b8dba | 1076 | if (strcasecmp(uri, hostname) == 0) |
ce314a94 | 1077 | strcpy(hostname, "localhost"); |
1078 | } | |
1079 | ||
1080 | cupsLangFree(language); | |
1081 | ||
1082 | if (!printer[0]) | |
0e66dba3 | 1083 | { |
1084 | last_error = IPP_NOT_FOUND; | |
ce314a94 | 1085 | return (NULL); |
0e66dba3 | 1086 | } |
ce314a94 | 1087 | |
1088 | /* | |
1089 | * Reconnect to the correct server as needed... | |
1090 | */ | |
1091 | ||
1092 | if (strcasecmp(cups_server->hostname, hostname) != 0) | |
1093 | { | |
1094 | httpClose(cups_server); | |
1095 | ||
b5cb0608 | 1096 | if ((cups_server = httpConnectEncrypt(hostname, ippPort(), |
1097 | cupsEncryption())) == NULL) | |
ce314a94 | 1098 | { |
dd63ebe2 | 1099 | DEBUG_puts("Unable to connect to server!"); |
ce314a94 | 1100 | last_error = IPP_SERVICE_UNAVAILABLE; |
1101 | return (NULL); | |
bc16fd64 | 1102 | } |
1103 | } | |
1104 | ||
d23a857a | 1105 | /* |
082b40d2 | 1106 | * Get a temp file... |
d23a857a | 1107 | */ |
1108 | ||
1b5bf964 | 1109 | if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) |
1110 | { | |
1111 | /* | |
1112 | * Can't open file; close the server connection and return NULL... | |
1113 | */ | |
1114 | ||
0e66dba3 | 1115 | last_error = IPP_INTERNAL_ERROR; |
1b5bf964 | 1116 | httpFlush(cups_server); |
1117 | httpClose(cups_server); | |
1118 | cups_server = NULL; | |
1119 | return (NULL); | |
1120 | } | |
d23a857a | 1121 | |
1122 | /* | |
e269c4f8 | 1123 | * And send a request to the HTTP server... |
d23a857a | 1124 | */ |
1125 | ||
04de52f8 | 1126 | snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer); |
d23a857a | 1127 | |
3ec5b662 | 1128 | status = cupsGetFd(cups_server, resource, fd); |
83e740a5 | 1129 | |
3ec5b662 | 1130 | close(fd); |
d23a857a | 1131 | |
1132 | /* | |
1b5bf964 | 1133 | * See if we actually got the file or an error... |
d23a857a | 1134 | */ |
1135 | ||
1b5bf964 | 1136 | if (status != HTTP_OK) |
d23a857a | 1137 | { |
0e66dba3 | 1138 | switch (status) |
1139 | { | |
2e708040 | 1140 | case HTTP_NOT_FOUND : |
1141 | last_error = IPP_NOT_FOUND; | |
1142 | break; | |
0e66dba3 | 1143 | case HTTP_ERROR : |
dd63ebe2 | 1144 | DEBUG_puts("Mapping HTTP error to IPP_SERVICE_UNAVAILABLE"); |
0e66dba3 | 1145 | last_error = IPP_SERVICE_UNAVAILABLE; |
1146 | break; | |
1147 | case HTTP_UNAUTHORIZED : | |
1148 | last_error = IPP_NOT_AUTHORIZED; | |
1149 | break; | |
1150 | default : | |
1151 | last_error = IPP_INTERNAL_ERROR; | |
1152 | break; | |
1153 | } | |
1154 | ||
1b5bf964 | 1155 | unlink(filename); |
bc16fd64 | 1156 | httpFlush(cups_server); |
d23a857a | 1157 | httpClose(cups_server); |
1158 | cups_server = NULL; | |
1159 | return (NULL); | |
1160 | } | |
1161 | ||
1b5bf964 | 1162 | /* |
3ec5b662 | 1163 | * Return the PPD file... |
1b5bf964 | 1164 | */ |
1165 | ||
d23a857a | 1166 | return (filename); |
3b960317 | 1167 | } |
1168 | ||
1169 | ||
8431231f | 1170 | /* |
1171 | * 'cupsGetPrinters()' - Get a list of printers. | |
1172 | */ | |
1173 | ||
d23a857a | 1174 | int /* O - Number of printers */ |
1175 | cupsGetPrinters(char ***printers) /* O - Printers */ | |
3b960317 | 1176 | { |
3ec5b662 | 1177 | int n; /* Number of printers */ |
1178 | ipp_t *request, /* IPP Request */ | |
1179 | *response; /* IPP Response */ | |
1180 | ipp_attribute_t *attr; /* Current attribute */ | |
1181 | cups_lang_t *language; /* Default language */ | |
1182 | char **temp; /* Temporary pointer */ | |
d23a857a | 1183 | |
1184 | ||
0f6a2276 | 1185 | if (printers == NULL) |
1186 | { | |
1187 | last_error = IPP_INTERNAL_ERROR; | |
1188 | return (0); | |
1189 | } | |
1190 | ||
d23a857a | 1191 | /* |
1192 | * Try to connect to the server... | |
1193 | */ | |
1194 | ||
1195 | if (!cups_connect("default", NULL, NULL)) | |
9aebebc3 | 1196 | { |
dd63ebe2 | 1197 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 1198 | last_error = IPP_SERVICE_UNAVAILABLE; |
2bffb563 | 1199 | return (0); |
9aebebc3 | 1200 | } |
d23a857a | 1201 | |
1202 | /* | |
1203 | * Build a CUPS_GET_PRINTERS request, which requires the following | |
1204 | * attributes: | |
1205 | * | |
1206 | * attributes-charset | |
1207 | * attributes-natural-language | |
27d555e8 | 1208 | * requested-attributes |
d23a857a | 1209 | */ |
1210 | ||
1211 | request = ippNew(); | |
1212 | ||
0a3ac972 | 1213 | request->request.op.operation_id = CUPS_GET_PRINTERS; |
1214 | request->request.op.request_id = 1; | |
d23a857a | 1215 | |
1216 | language = cupsLangDefault(); | |
1217 | ||
1218 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
a9b97a87 | 1219 | "attributes-charset", NULL, cupsLangEncoding(language)); |
d23a857a | 1220 | |
1221 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
a9b97a87 | 1222 | "attributes-natural-language", NULL, language->language); |
d23a857a | 1223 | |
27d555e8 | 1224 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
1225 | "requested-attributes", NULL, "printer-name"); | |
1226 | ||
d23a857a | 1227 | /* |
1228 | * Do the request and get back a response... | |
1229 | */ | |
1230 | ||
1231 | n = 0; | |
1232 | *printers = NULL; | |
1233 | ||
a9b97a87 | 1234 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
d23a857a | 1235 | { |
0a3ac972 | 1236 | last_error = response->request.status.status_code; |
8b06ca19 | 1237 | |
d23a857a | 1238 | for (attr = response->attrs; attr != NULL; attr = attr->next) |
fbc6b634 | 1239 | if (attr->name != NULL && |
1240 | strcasecmp(attr->name, "printer-name") == 0 && | |
d23a857a | 1241 | attr->value_tag == IPP_TAG_NAME) |
1242 | { | |
1243 | if (n == 0) | |
a9b97a87 | 1244 | temp = malloc(sizeof(char *)); |
d23a857a | 1245 | else |
a9b97a87 | 1246 | temp = realloc(*printers, sizeof(char *) * (n + 1)); |
d23a857a | 1247 | |
a9b97a87 | 1248 | if (temp == NULL) |
d23a857a | 1249 | { |
a9b97a87 | 1250 | /* |
1251 | * Ran out of memory! | |
1252 | */ | |
1253 | ||
1254 | while (n > 0) | |
1255 | { | |
1256 | n --; | |
1257 | free((*printers)[n]); | |
1258 | } | |
1259 | ||
1260 | free(*printers); | |
d23a857a | 1261 | ippDelete(response); |
1262 | return (0); | |
1263 | } | |
1264 | ||
a9b97a87 | 1265 | *printers = temp; |
1266 | temp[n] = strdup(attr->values[0].string.text); | |
d23a857a | 1267 | n ++; |
1268 | } | |
1269 | ||
1270 | ippDelete(response); | |
1271 | } | |
8b06ca19 | 1272 | else |
1273 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 1274 | |
1275 | return (n); | |
3b960317 | 1276 | } |
1277 | ||
1278 | ||
8b06ca19 | 1279 | /* |
1280 | * 'cupsLastError()' - Return the last IPP error that occurred. | |
1281 | */ | |
1282 | ||
3ec5b662 | 1283 | ipp_status_t /* O - IPP error code */ |
8b06ca19 | 1284 | cupsLastError(void) |
1285 | { | |
1286 | return (last_error); | |
1287 | } | |
1288 | ||
1289 | ||
4a73831b | 1290 | /* |
1291 | * 'cupsPrintFile()' - Print a file to a printer or class. | |
1292 | */ | |
1293 | ||
1294 | int /* O - Job ID */ | |
063e1ac7 | 1295 | cupsPrintFile(const char *name, /* I - Printer or class name */ |
1296 | const char *filename, /* I - File to print */ | |
1297 | const char *title, /* I - Title of job */ | |
4a73831b | 1298 | int num_options,/* I - Number of options */ |
1299 | cups_option_t *options) /* I - Options */ | |
501b59e2 | 1300 | { |
183914a3 | 1301 | DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %p)\n", |
880dc0ce | 1302 | name, filename, num_options, options)); |
501b59e2 | 1303 | |
1304 | return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); | |
1305 | } | |
1306 | ||
1307 | ||
1308 | /* | |
1309 | * 'cupsPrintFiles()' - Print one or more files to a printer or class. | |
1310 | */ | |
1311 | ||
1312 | int /* O - Job ID */ | |
1313 | cupsPrintFiles(const char *name, /* I - Printer or class name */ | |
1314 | int num_files, /* I - Number of files */ | |
1315 | const char **files, /* I - File(s) to print */ | |
1316 | const char *title, /* I - Title of job */ | |
3ec5b662 | 1317 | int num_options, |
1318 | /* I - Number of options */ | |
501b59e2 | 1319 | cups_option_t *options) /* I - Options */ |
3b960317 | 1320 | { |
d23a857a | 1321 | int i; /* Looping var */ |
501b59e2 | 1322 | const char *val; /* Pointer to option value */ |
d23a857a | 1323 | ipp_t *request; /* IPP request */ |
1324 | ipp_t *response; /* IPP response */ | |
1325 | ipp_attribute_t *attr; /* IPP job-id attribute */ | |
1326 | char hostname[HTTP_MAX_URI], /* Hostname */ | |
1327 | printer[HTTP_MAX_URI], /* Printer or class name */ | |
1328 | uri[HTTP_MAX_URI]; /* Printer URI */ | |
1329 | cups_lang_t *language; /* Language to use */ | |
d23a857a | 1330 | int jobid; /* New job ID */ |
1331 | ||
4a73831b | 1332 | |
183914a3 | 1333 | DEBUG_printf(("cupsPrintFiles(\'%s\', %d, %p, %d, %p)\n", |
880dc0ce | 1334 | name, num_files, files, num_options, options)); |
4a73831b | 1335 | |
501b59e2 | 1336 | if (name == NULL || num_files < 1 || files == NULL) |
4a73831b | 1337 | return (0); |
1338 | ||
4a73831b | 1339 | /* |
1340 | * Setup a connection and request data... | |
1341 | */ | |
1342 | ||
d23a857a | 1343 | if (!cups_connect(name, printer, hostname)) |
1344 | { | |
1345 | DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n", | |
1346 | strerror(errno))); | |
dd63ebe2 | 1347 | DEBUG_puts("Unable to connect to server!"); |
9aebebc3 | 1348 | last_error = IPP_SERVICE_UNAVAILABLE; |
d23a857a | 1349 | return (0); |
1350 | } | |
4a73831b | 1351 | |
501b59e2 | 1352 | language = cupsLangDefault(); |
1353 | ||
4a73831b | 1354 | /* |
1355 | * Build a standard CUPS URI for the printer and fill the standard IPP | |
1356 | * attributes... | |
1357 | */ | |
1358 | ||
c7c24dd7 | 1359 | if ((request = ippNew()) == NULL) |
1360 | return (0); | |
1361 | ||
0a3ac972 | 1362 | request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB : |
501b59e2 | 1363 | IPP_CREATE_JOB; |
0a3ac972 | 1364 | request->request.op.request_id = 1; |
4a73831b | 1365 | |
04de52f8 | 1366 | snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); |
4a73831b | 1367 | |
d23a857a | 1368 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
1369 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
4a73831b | 1370 | |
d23a857a | 1371 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
1372 | "attributes-natural-language", NULL, | |
1373 | language != NULL ? language->language : "C"); | |
4a73831b | 1374 | |
d23a857a | 1375 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
1376 | NULL, uri); | |
4a73831b | 1377 | |
6d0582d2 | 1378 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", |
ac4c1450 | 1379 | NULL, cupsUser()); |
4a73831b | 1380 | |
d23a857a | 1381 | if (title) |
6d0582d2 | 1382 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); |
d23a857a | 1383 | |
4a73831b | 1384 | /* |
183914a3 | 1385 | * Then add all options... |
4a73831b | 1386 | */ |
1387 | ||
183914a3 | 1388 | cupsEncodeOptions(request, num_options, options); |
4a73831b | 1389 | |
1390 | /* | |
501b59e2 | 1391 | * Do the request... |
4a73831b | 1392 | */ |
1393 | ||
04de52f8 | 1394 | snprintf(uri, sizeof(uri), "/printers/%s", printer); |
4a73831b | 1395 | |
501b59e2 | 1396 | if (num_files == 1) |
1397 | response = cupsDoFileRequest(cups_server, request, uri, *files); | |
1398 | else | |
1399 | response = cupsDoRequest(cups_server, request, uri); | |
1400 | ||
1401 | if (response == NULL) | |
3270670b | 1402 | jobid = 0; |
0a3ac972 | 1403 | else if (response->request.status.status_code > IPP_OK_CONFLICT) |
4a73831b | 1404 | { |
3270670b | 1405 | DEBUG_printf(("IPP response code was 0x%x!\n", |
0a3ac972 | 1406 | response->request.status.status_code)); |
4a73831b | 1407 | jobid = 0; |
1408 | } | |
3270670b | 1409 | else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) |
4a73831b | 1410 | { |
3270670b | 1411 | DEBUG_puts("No job ID!"); |
4a73831b | 1412 | jobid = 0; |
1413 | } | |
1414 | else | |
3270670b | 1415 | jobid = attr->values[0].integer; |
4a73831b | 1416 | |
3270670b | 1417 | if (response != NULL) |
1418 | ippDelete(response); | |
4a73831b | 1419 | |
501b59e2 | 1420 | /* |
1421 | * Handle multiple file jobs if the create-job operation worked... | |
1422 | */ | |
1423 | ||
1424 | if (jobid > 0 && num_files > 1) | |
1425 | for (i = 0; i < num_files; i ++) | |
1426 | { | |
1427 | /* | |
1428 | * Build a standard CUPS URI for the job and fill the standard IPP | |
1429 | * attributes... | |
1430 | */ | |
1431 | ||
c7c24dd7 | 1432 | if ((request = ippNew()) == NULL) |
1433 | return (0); | |
1434 | ||
0a3ac972 | 1435 | request->request.op.operation_id = IPP_SEND_DOCUMENT; |
1436 | request->request.op.request_id = 1; | |
501b59e2 | 1437 | |
04de52f8 | 1438 | snprintf(uri, sizeof(uri), "ipp://%s:%d/jobs/%d", hostname, ippPort(), |
501b59e2 | 1439 | jobid); |
1440 | ||
1441 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
1442 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
1443 | ||
1444 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
1445 | "attributes-natural-language", NULL, | |
1446 | language != NULL ? language->language : "C"); | |
1447 | ||
1448 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", | |
1449 | NULL, uri); | |
1450 | ||
1451 | /* | |
1452 | * Handle raw print files... | |
1453 | */ | |
1454 | ||
1455 | if (cupsGetOption("raw", num_options, options)) | |
1456 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1457 | NULL, "application/vnd.cups-raw"); | |
1458 | else if ((val = cupsGetOption("document-format", num_options, options)) != NULL) | |
1459 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1460 | NULL, val); | |
1461 | else | |
1462 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1463 | NULL, "application/octet-stream"); | |
1464 | ||
1465 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
1466 | NULL, cupsUser()); | |
1467 | ||
1468 | /* | |
1469 | * Is this the last document? | |
1470 | */ | |
1471 | ||
1472 | if (i == (num_files - 1)) | |
1473 | ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); | |
1474 | ||
1475 | /* | |
1476 | * Send the file... | |
1477 | */ | |
1478 | ||
04de52f8 | 1479 | snprintf(uri, sizeof(uri), "/printers/%s", printer); |
501b59e2 | 1480 | |
1481 | if ((response = cupsDoFileRequest(cups_server, request, uri, | |
1482 | files[i])) != NULL) | |
1483 | ippDelete(response); | |
1484 | } | |
1485 | ||
4a73831b | 1486 | return (jobid); |
3b960317 | 1487 | } |
1488 | ||
1489 | ||
1490 | /* | |
d23a857a | 1491 | * 'cups_connect()' - Connect to the specified host... |
1492 | */ | |
1493 | ||
063e1ac7 | 1494 | static char * /* I - Printer name or NULL */ |
1495 | cups_connect(const char *name, /* I - Destination (printer[@host]) */ | |
970017a4 | 1496 | char *printer, /* O - Printer name [HTTP_MAX_URI] */ |
1497 | char *hostname) /* O - Hostname [HTTP_MAX_URI] */ | |
d23a857a | 1498 | { |
e354b6e3 | 1499 | char hostbuf[HTTP_MAX_URI]; /* Name of host */ |
d23a857a | 1500 | |
1501 | ||
b5cb0608 | 1502 | DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); |
1503 | ||
d23a857a | 1504 | if (name == NULL) |
8b06ca19 | 1505 | { |
1506 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 1507 | return (NULL); |
8b06ca19 | 1508 | } |
d23a857a | 1509 | |
e354b6e3 | 1510 | /* |
1511 | * All jobs are now queued to cupsServer() to avoid hostname | |
1512 | * resolution problems and to ensure that the user sees all | |
1513 | * locally queued jobs locally. | |
1514 | */ | |
1515 | ||
1516 | strlcpy(hostbuf, cupsServer(), sizeof(hostbuf)); | |
d23a857a | 1517 | |
1518 | if (hostname != NULL) | |
def978d5 | 1519 | strlcpy(hostname, hostbuf, HTTP_MAX_URI); |
d23a857a | 1520 | else |
1521 | hostname = hostbuf; | |
1522 | ||
1523 | if (printer != NULL) | |
e354b6e3 | 1524 | strlcpy(printer, name, HTTP_MAX_URI); |
d23a857a | 1525 | else |
e354b6e3 | 1526 | printer = (char *)name; |
d23a857a | 1527 | |
1528 | if (cups_server != NULL) | |
1529 | { | |
1530 | if (strcasecmp(cups_server->hostname, hostname) == 0) | |
1531 | return (printer); | |
1532 | ||
1533 | httpClose(cups_server); | |
1534 | } | |
1535 | ||
b5cb0608 | 1536 | DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); |
1537 | ||
1538 | if ((cups_server = httpConnectEncrypt(hostname, ippPort(), | |
1539 | cupsEncryption())) == NULL) | |
8b06ca19 | 1540 | { |
dd63ebe2 | 1541 | DEBUG_puts("Unable to connect to server!"); |
8b06ca19 | 1542 | last_error = IPP_SERVICE_UNAVAILABLE; |
d23a857a | 1543 | return (NULL); |
8b06ca19 | 1544 | } |
d23a857a | 1545 | else |
1546 | return (printer); | |
1547 | } | |
1548 | ||
1549 | ||
1550 | /* | |
294c916e | 1551 | * End of "$Id: util.c,v 1.81.2.28 2003/10/22 03:17:35 mike Exp $". |
3b960317 | 1552 | */ |