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