]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
b94498cf | 2 | * "$Id: util.c 6506 2007-05-03 18:12:35Z mike $" |
ef416fc2 | 3 | * |
4 | * Printing utilities for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2006 by Easy Software Products. | |
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 | |
17 | * 44141 Airport View Drive, Suite 204 | |
18 | * Hollywood, Maryland 20636 USA | |
19 | * | |
20 | * Voice: (301) 373-9600 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * This file is subject to the Apple OS-Developed Software exception. | |
25 | * | |
26 | * Contents: | |
27 | * | |
fa73b229 | 28 | * cupsCancelJob() - Cancel a print job on the default server. |
fa73b229 | 29 | * cupsFreeJobs() - Free memory used by job data. |
30 | * cupsGetClasses() - Get a list of printer classes from the default | |
31 | * server. | |
32 | * cupsGetDefault() - Get the default printer or class from the default | |
33 | * server. | |
34 | * cupsGetDefault2() - Get the default printer or class from the | |
35 | * specified server. | |
36 | * cupsGetJobs() - Get the jobs from the default server. | |
37 | * cupsGetJobs2() - Get the jobs from the specified server. | |
38 | * cupsGetPPD() - Get the PPD file for a printer on the default | |
39 | * server. | |
40 | * cupsGetPPD2() - Get the PPD file for a printer on the specified | |
41 | * server. | |
42 | * cupsGetPrinters() - Get a list of printers from the default server. | |
b94498cf | 43 | * cupsGetServerPPD() - Get an available PPD file from the server. |
fa73b229 | 44 | * cupsLastError() - Return the last IPP status code. |
45 | * cupsLastErrorString() - Return the last IPP status-message. | |
46 | * cupsPrintFile() - Print a file to a printer or class on the default | |
47 | * server. | |
48 | * cupsPrintFile2() - Print a file to a printer or class on the | |
49 | * specified server. | |
50 | * cupsPrintFiles() - Print one or more files to a printer or class on | |
51 | * the default server. | |
52 | * cupsPrintFiles2() - Print one or more files to a printer or class on | |
53 | * the specified server. | |
54 | * cups_connect() - Connect to the specified host... | |
55 | * cups_get_printer_uri() - Get the printer-uri-supported attribute for the | |
56 | * first printer in a class. | |
ef416fc2 | 57 | */ |
58 | ||
59 | /* | |
60 | * Include necessary headers... | |
61 | */ | |
62 | ||
63 | #include "globals.h" | |
64 | #include "debug.h" | |
65 | #include <stdlib.h> | |
66 | #include <errno.h> | |
67 | #include <fcntl.h> | |
68 | #include <sys/stat.h> | |
69 | #if defined(WIN32) || defined(__EMX__) | |
70 | # include <io.h> | |
71 | #else | |
72 | # include <unistd.h> | |
73 | #endif /* WIN32 || __EMX__ */ | |
74 | ||
75 | ||
76 | /* | |
77 | * Local functions... | |
78 | */ | |
79 | ||
80 | static char *cups_connect(const char *name, char *printer, char *hostname); | |
fa73b229 | 81 | static int cups_get_printer_uri(http_t *http, const char *name, |
82 | char *host, int hostsize, int *port, | |
83 | char *resource, int resourcesize, | |
84 | int depth); | |
ef416fc2 | 85 | |
86 | ||
87 | /* | |
88 | * 'cupsCancelJob()' - Cancel a print job on the default server. | |
89 | * | |
90 | * Use the cupsLastError() and cupsLastErrorString() functions to get | |
91 | * the cause of any failure. | |
92 | */ | |
93 | ||
94 | int /* O - 1 on success, 0 on failure */ | |
95 | cupsCancelJob(const char *name, /* I - Name of printer or class */ | |
96 | int job) /* I - Job ID */ | |
97 | { | |
98 | char printer[HTTP_MAX_URI], /* Printer name */ | |
99 | hostname[HTTP_MAX_URI], /* Hostname */ | |
100 | uri[HTTP_MAX_URI]; /* Printer URI */ | |
101 | ipp_t *request, /* IPP request */ | |
102 | *response; /* IPP response */ | |
103 | cups_lang_t *language; /* Language info */ | |
104 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
105 | ||
106 | ||
107 | /* | |
108 | * See if we can connect to the server... | |
109 | */ | |
110 | ||
111 | if (!cups_connect(name, printer, hostname)) | |
112 | { | |
113 | DEBUG_puts("Unable to connect to server!"); | |
114 | ||
115 | return (0); | |
116 | } | |
117 | ||
118 | /* | |
119 | * Create a printer URI... | |
120 | */ | |
121 | ||
a4d04587 | 122 | if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
123 | "localhost", 0, "/printers/%s", printer) != HTTP_URI_OK) | |
ef416fc2 | 124 | { |
ecdc0628 | 125 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 126 | |
127 | return (0); | |
128 | } | |
129 | ||
130 | /* | |
131 | * Build an IPP_CANCEL_JOB request, which requires the following | |
132 | * attributes: | |
133 | * | |
134 | * attributes-charset | |
135 | * attributes-natural-language | |
136 | * printer-uri | |
137 | * job-id | |
138 | * [requesting-user-name] | |
139 | */ | |
140 | ||
141 | request = ippNew(); | |
142 | ||
143 | request->request.op.operation_id = IPP_CANCEL_JOB; | |
144 | request->request.op.request_id = 1; | |
145 | ||
146 | language = cupsLangDefault(); | |
147 | ||
148 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
149 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
150 | ||
151 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
152 | "attributes-natural-language", NULL, | |
153 | language != NULL ? language->language : "C"); | |
154 | ||
155 | cupsLangFree(language); | |
156 | ||
157 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
158 | NULL, uri); | |
159 | ||
160 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); | |
161 | ||
162 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
163 | NULL, cupsUser()); | |
164 | ||
165 | /* | |
166 | * Do the request... | |
167 | */ | |
168 | ||
169 | if ((response = cupsDoRequest(cg->http, request, "/jobs/")) != NULL) | |
170 | ippDelete(response); | |
171 | ||
172 | return (cg->last_error < IPP_REDIRECTION_OTHER_SITE); | |
173 | } | |
174 | ||
175 | ||
ef416fc2 | 176 | /* |
177 | * 'cupsFreeJobs()' - Free memory used by job data. | |
178 | */ | |
179 | ||
180 | void | |
181 | cupsFreeJobs(int num_jobs, /* I - Number of jobs */ | |
182 | cups_job_t *jobs) /* I - Jobs */ | |
183 | { | |
184 | int i; /* Looping var */ | |
185 | ||
186 | ||
187 | if (num_jobs <= 0 || jobs == NULL) | |
188 | return; | |
189 | ||
190 | for (i = 0; i < num_jobs; i ++) | |
191 | { | |
192 | free(jobs[i].dest); | |
193 | free(jobs[i].user); | |
194 | free(jobs[i].format); | |
195 | free(jobs[i].title); | |
196 | } | |
197 | ||
198 | free(jobs); | |
199 | } | |
200 | ||
201 | ||
202 | /* | |
203 | * 'cupsGetClasses()' - Get a list of printer classes from the default server. | |
204 | * | |
205 | * This function is deprecated - use cupsGetDests() instead. | |
206 | * | |
207 | * @deprecated@ | |
208 | */ | |
209 | ||
210 | int /* O - Number of classes */ | |
211 | cupsGetClasses(char ***classes) /* O - Classes */ | |
212 | { | |
213 | int n; /* Number of classes */ | |
214 | ipp_t *request, /* IPP Request */ | |
215 | *response; /* IPP Response */ | |
216 | ipp_attribute_t *attr; /* Current attribute */ | |
217 | cups_lang_t *language; /* Default language */ | |
218 | char **temp; /* Temporary pointer */ | |
219 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
220 | ||
221 | ||
222 | if (classes == NULL) | |
223 | { | |
ecdc0628 | 224 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 225 | |
226 | return (0); | |
227 | } | |
228 | ||
229 | /* | |
230 | * Try to connect to the server... | |
231 | */ | |
232 | ||
233 | if (!cups_connect("default", NULL, NULL)) | |
234 | { | |
235 | DEBUG_puts("Unable to connect to server!"); | |
236 | ||
237 | return (0); | |
238 | } | |
239 | ||
240 | /* | |
241 | * Build a CUPS_GET_CLASSES request, which requires the following | |
242 | * attributes: | |
243 | * | |
244 | * attributes-charset | |
245 | * attributes-natural-language | |
246 | * requested-attributes | |
247 | */ | |
248 | ||
249 | request = ippNew(); | |
250 | ||
251 | request->request.op.operation_id = CUPS_GET_CLASSES; | |
252 | request->request.op.request_id = 1; | |
253 | ||
254 | language = cupsLangDefault(); | |
255 | ||
256 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
257 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
258 | ||
259 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
260 | "attributes-natural-language", NULL, language->language); | |
261 | ||
262 | cupsLangFree(language); | |
263 | ||
264 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
265 | "requested-attributes", NULL, "printer-name"); | |
266 | ||
267 | /* | |
268 | * Do the request and get back a response... | |
269 | */ | |
270 | ||
271 | n = 0; | |
272 | *classes = NULL; | |
273 | ||
274 | if ((response = cupsDoRequest(cg->http, request, "/")) != NULL) | |
275 | { | |
276 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
277 | if (attr->name != NULL && | |
278 | strcasecmp(attr->name, "printer-name") == 0 && | |
279 | attr->value_tag == IPP_TAG_NAME) | |
280 | { | |
281 | if (n == 0) | |
282 | temp = malloc(sizeof(char *)); | |
283 | else | |
284 | temp = realloc(*classes, sizeof(char *) * (n + 1)); | |
285 | ||
286 | if (temp == NULL) | |
287 | { | |
288 | /* | |
289 | * Ran out of memory! | |
290 | */ | |
291 | ||
292 | while (n > 0) | |
293 | { | |
294 | n --; | |
295 | free((*classes)[n]); | |
296 | } | |
297 | ||
298 | free(*classes); | |
299 | ippDelete(response); | |
300 | return (0); | |
301 | } | |
302 | ||
303 | *classes = temp; | |
304 | temp[n] = strdup(attr->values[0].string.text); | |
305 | n ++; | |
306 | } | |
307 | ||
308 | ippDelete(response); | |
309 | } | |
310 | ||
311 | return (n); | |
312 | } | |
313 | ||
314 | ||
315 | /* | |
316 | * 'cupsGetDefault()' - Get the default printer or class for the default server. | |
317 | * | |
318 | * This function returns the default printer or class as defined by | |
319 | * the LPDEST or PRINTER environment variables. If these environment | |
320 | * variables are not set, the server default destination is returned. | |
321 | * Applications should use the cupsGetDests() and cupsGetDest() functions | |
322 | * to get the user-defined default printer, as this function does not | |
323 | * support the lpoptions-defined default printer. | |
324 | */ | |
325 | ||
326 | const char * /* O - Default printer or NULL */ | |
327 | cupsGetDefault(void) | |
328 | { | |
329 | const char *var; /* Environment variable */ | |
330 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
331 | ||
332 | ||
333 | /* | |
334 | * First see if the LPDEST or PRINTER environment variables are | |
335 | * set... However, if PRINTER is set to "lp", ignore it to work | |
336 | * around a "feature" in most Linux distributions - the default | |
337 | * user login scripts set PRINTER to "lp"... | |
338 | */ | |
339 | ||
340 | if ((var = getenv("LPDEST")) != NULL) | |
341 | return (var); | |
342 | else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) | |
343 | return (var); | |
344 | ||
345 | /* | |
346 | * Try to connect to the server... | |
347 | */ | |
348 | ||
349 | if (!cups_connect("default", NULL, NULL)) | |
350 | { | |
351 | DEBUG_puts("Unable to connect to server!"); | |
352 | ||
353 | return (NULL); | |
354 | } | |
355 | ||
356 | /* | |
357 | * Return the default printer... | |
358 | */ | |
359 | ||
360 | return (cupsGetDefault2(cg->http)); | |
361 | } | |
362 | ||
363 | ||
364 | /* | |
365 | * 'cupsGetDefault2()' - Get the default printer or class for the specified server. | |
366 | * | |
367 | * This function returns the default printer or class as defined by | |
368 | * the LPDEST or PRINTER environment variables. If these environment | |
369 | * variables are not set, the server default destination is returned. | |
370 | * Applications should use the cupsGetDests() and cupsGetDest() functions | |
371 | * to get the user-defined default printer, as this function does not | |
372 | * support the lpoptions-defined default printer. | |
373 | * | |
374 | * @since CUPS 1.1.21@ | |
375 | */ | |
376 | ||
377 | const char * /* O - Default printer or NULL */ | |
378 | cupsGetDefault2(http_t *http) /* I - HTTP connection */ | |
379 | { | |
380 | ipp_t *request, /* IPP Request */ | |
381 | *response; /* IPP Response */ | |
382 | ipp_attribute_t *attr; /* Current attribute */ | |
383 | cups_lang_t *language; /* Default language */ | |
384 | const char *var; /* Environment variable */ | |
385 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
386 | ||
387 | ||
388 | /* | |
389 | * First see if the LPDEST or PRINTER environment variables are | |
390 | * set... However, if PRINTER is set to "lp", ignore it to work | |
391 | * around a "feature" in most Linux distributions - the default | |
392 | * user login scripts set PRINTER to "lp"... | |
393 | */ | |
394 | ||
395 | if ((var = getenv("LPDEST")) != NULL) | |
396 | return (var); | |
397 | else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) | |
398 | return (var); | |
399 | ||
400 | /* | |
401 | * Range check input... | |
402 | */ | |
403 | ||
404 | if (!http) | |
405 | return (NULL); | |
406 | ||
407 | /* | |
408 | * Build a CUPS_GET_DEFAULT request, which requires the following | |
409 | * attributes: | |
410 | * | |
411 | * attributes-charset | |
412 | * attributes-natural-language | |
413 | */ | |
414 | ||
415 | request = ippNew(); | |
416 | ||
417 | request->request.op.operation_id = CUPS_GET_DEFAULT; | |
418 | request->request.op.request_id = 1; | |
419 | ||
420 | language = cupsLangDefault(); | |
421 | ||
422 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
423 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
424 | ||
425 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
426 | "attributes-natural-language", NULL, language->language); | |
427 | ||
428 | cupsLangFree(language); | |
429 | ||
430 | /* | |
431 | * Do the request and get back a response... | |
432 | */ | |
433 | ||
434 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
435 | { | |
436 | if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) | |
437 | { | |
438 | strlcpy(cg->def_printer, attr->values[0].string.text, sizeof(cg->def_printer)); | |
439 | ippDelete(response); | |
440 | return (cg->def_printer); | |
441 | } | |
442 | ||
443 | ippDelete(response); | |
444 | } | |
445 | ||
446 | return (NULL); | |
447 | } | |
448 | ||
449 | ||
450 | /* | |
451 | * 'cupsGetJobs()' - Get the jobs from the default server. | |
452 | */ | |
453 | ||
454 | int /* O - Number of jobs */ | |
455 | cupsGetJobs(cups_job_t **jobs, /* O - Job data */ | |
ecdc0628 | 456 | const char *mydest, /* I - NULL = all destinations, * |
457 | * otherwise show jobs for mydest */ | |
458 | int myjobs, /* I - 0 = all users, 1 = mine */ | |
459 | int completed) /* I - -1 = show all, 0 = active, * | |
460 | * 1 = completed jobs */ | |
ef416fc2 | 461 | { |
462 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
463 | ||
464 | /* | |
465 | * Try to connect to the server... | |
466 | */ | |
467 | ||
468 | if (!cups_connect("default", NULL, NULL)) | |
469 | { | |
470 | DEBUG_puts("Unable to connect to server!"); | |
471 | ||
472 | return (-1); | |
473 | } | |
474 | ||
475 | /* | |
476 | * Return the jobs... | |
477 | */ | |
478 | ||
479 | return (cupsGetJobs2(cg->http, jobs, mydest, myjobs, completed)); | |
480 | } | |
481 | ||
482 | ||
483 | ||
484 | /* | |
485 | * 'cupsGetJobs2()' - Get the jobs from the specified server. | |
486 | * | |
487 | * @since CUPS 1.1.21@ | |
488 | */ | |
489 | ||
490 | int /* O - Number of jobs */ | |
491 | cupsGetJobs2(http_t *http, /* I - HTTP connection */ | |
492 | cups_job_t **jobs, /* O - Job data */ | |
ecdc0628 | 493 | const char *mydest, /* I - NULL = all destinations, * |
494 | * otherwise show jobs for mydest */ | |
495 | int myjobs, /* I - 0 = all users, 1 = mine */ | |
496 | int completed) /* I - -1 = show all, 0 = active, * | |
497 | * 1 = completed jobs */ | |
ef416fc2 | 498 | { |
499 | int n; /* Number of jobs */ | |
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 | cups_job_t *temp; /* Temporary pointer */ | |
505 | int id, /* job-id */ | |
506 | priority, /* job-priority */ | |
507 | size; /* job-k-octets */ | |
508 | ipp_jstate_t state; /* job-state */ | |
509 | time_t completed_time, /* time-at-completed */ | |
510 | creation_time, /* time-at-creation */ | |
511 | processing_time; /* time-at-processing */ | |
512 | const char *dest, /* job-printer-uri */ | |
513 | *format, /* document-format */ | |
514 | *title, /* job-name */ | |
515 | *user; /* job-originating-user-name */ | |
516 | char uri[HTTP_MAX_URI]; /* URI for jobs */ | |
517 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
518 | static const char * const attrs[] = /* Requested attributes */ | |
519 | { | |
520 | "job-id", | |
521 | "job-priority", | |
522 | "job-k-octets", | |
523 | "job-state", | |
524 | "time-at-completed", | |
525 | "time-at-creation", | |
526 | "time-at-processing", | |
527 | "job-printer-uri", | |
528 | "document-format", | |
529 | "job-name", | |
530 | "job-originating-user-name" | |
531 | }; | |
532 | ||
533 | ||
534 | /* | |
535 | * Range check input... | |
536 | */ | |
537 | ||
538 | if (!http || !jobs) | |
539 | { | |
ecdc0628 | 540 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 541 | |
542 | return (-1); | |
543 | } | |
544 | ||
545 | /* | |
546 | * Get the right URI... | |
547 | */ | |
548 | ||
549 | if (mydest) | |
550 | { | |
a4d04587 | 551 | if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
552 | "localhost", 0, "/printers/%s", mydest) != HTTP_URI_OK) | |
ef416fc2 | 553 | { |
ecdc0628 | 554 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 555 | |
556 | return (-1); | |
557 | } | |
558 | } | |
559 | else | |
560 | strcpy(uri, "ipp://localhost/jobs"); | |
561 | ||
562 | ||
563 | /* | |
564 | * Build an IPP_GET_JOBS request, which requires the following | |
565 | * attributes: | |
566 | * | |
567 | * attributes-charset | |
568 | * attributes-natural-language | |
569 | * printer-uri | |
570 | * requesting-user-name | |
571 | * which-jobs | |
572 | * my-jobs | |
573 | * requested-attributes | |
574 | */ | |
575 | ||
576 | request = ippNew(); | |
577 | ||
578 | request->request.op.operation_id = IPP_GET_JOBS; | |
579 | request->request.op.request_id = 1; | |
580 | ||
581 | language = cupsLangDefault(); | |
582 | ||
583 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
584 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
585 | ||
586 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
587 | "attributes-natural-language", NULL, language->language); | |
588 | ||
589 | cupsLangFree(language); | |
590 | ||
591 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, | |
592 | "printer-uri", NULL, uri); | |
593 | ||
594 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, | |
595 | "requesting-user-name", NULL, cupsUser()); | |
596 | ||
597 | if (myjobs) | |
598 | ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); | |
599 | ||
ecdc0628 | 600 | if (completed > 0) |
ef416fc2 | 601 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
602 | "which-jobs", NULL, "completed"); | |
ecdc0628 | 603 | else if (completed < 0) |
604 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
605 | "which-jobs", NULL, "all"); | |
ef416fc2 | 606 | |
607 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
608 | "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), | |
609 | NULL, attrs); | |
610 | ||
611 | /* | |
612 | * Do the request and get back a response... | |
613 | */ | |
614 | ||
615 | n = 0; | |
616 | *jobs = NULL; | |
617 | ||
618 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
619 | { | |
620 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
621 | { | |
622 | /* | |
623 | * Skip leading attributes until we hit a job... | |
624 | */ | |
625 | ||
626 | while (attr != NULL && attr->group_tag != IPP_TAG_JOB) | |
627 | attr = attr->next; | |
628 | ||
629 | if (attr == NULL) | |
630 | break; | |
631 | ||
632 | /* | |
633 | * Pull the needed attributes from this job... | |
634 | */ | |
635 | ||
636 | id = 0; | |
637 | size = 0; | |
638 | priority = 50; | |
639 | state = IPP_JOB_PENDING; | |
640 | user = "unknown"; | |
641 | dest = NULL; | |
642 | format = "application/octet-stream"; | |
643 | title = "untitled"; | |
644 | creation_time = 0; | |
645 | completed_time = 0; | |
646 | processing_time = 0; | |
647 | ||
648 | while (attr != NULL && attr->group_tag == IPP_TAG_JOB) | |
649 | { | |
650 | if (strcmp(attr->name, "job-id") == 0 && | |
651 | attr->value_tag == IPP_TAG_INTEGER) | |
652 | id = attr->values[0].integer; | |
653 | else if (strcmp(attr->name, "job-state") == 0 && | |
654 | attr->value_tag == IPP_TAG_ENUM) | |
655 | state = (ipp_jstate_t)attr->values[0].integer; | |
656 | else if (strcmp(attr->name, "job-priority") == 0 && | |
657 | attr->value_tag == IPP_TAG_INTEGER) | |
658 | priority = attr->values[0].integer; | |
659 | else if (strcmp(attr->name, "job-k-octets") == 0 && | |
660 | attr->value_tag == IPP_TAG_INTEGER) | |
661 | size = attr->values[0].integer; | |
662 | else if (strcmp(attr->name, "time-at-completed") == 0 && | |
663 | attr->value_tag == IPP_TAG_INTEGER) | |
664 | completed_time = attr->values[0].integer; | |
665 | else if (strcmp(attr->name, "time-at-creation") == 0 && | |
666 | attr->value_tag == IPP_TAG_INTEGER) | |
667 | creation_time = attr->values[0].integer; | |
668 | else if (strcmp(attr->name, "time-at-processing") == 0 && | |
669 | attr->value_tag == IPP_TAG_INTEGER) | |
670 | processing_time = attr->values[0].integer; | |
671 | else if (strcmp(attr->name, "job-printer-uri") == 0 && | |
672 | attr->value_tag == IPP_TAG_URI) | |
673 | { | |
674 | if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) | |
675 | dest ++; | |
676 | } | |
677 | else if (strcmp(attr->name, "job-originating-user-name") == 0 && | |
678 | attr->value_tag == IPP_TAG_NAME) | |
679 | user = attr->values[0].string.text; | |
680 | else if (strcmp(attr->name, "document-format") == 0 && | |
681 | attr->value_tag == IPP_TAG_MIMETYPE) | |
682 | format = attr->values[0].string.text; | |
683 | else if (strcmp(attr->name, "job-name") == 0 && | |
684 | (attr->value_tag == IPP_TAG_TEXT || | |
685 | attr->value_tag == IPP_TAG_NAME)) | |
686 | title = attr->values[0].string.text; | |
687 | ||
688 | attr = attr->next; | |
689 | } | |
690 | ||
691 | /* | |
692 | * See if we have everything needed... | |
693 | */ | |
694 | ||
695 | if (dest == NULL || id == 0) | |
696 | { | |
697 | if (attr == NULL) | |
698 | break; | |
699 | else | |
700 | continue; | |
701 | } | |
702 | ||
703 | /* | |
704 | * Allocate memory for the job... | |
705 | */ | |
706 | ||
707 | if (n == 0) | |
708 | temp = malloc(sizeof(cups_job_t)); | |
709 | else | |
710 | temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1)); | |
711 | ||
712 | if (temp == NULL) | |
713 | { | |
714 | /* | |
715 | * Ran out of memory! | |
716 | */ | |
717 | ||
718 | cupsFreeJobs(n, *jobs); | |
719 | *jobs = NULL; | |
720 | ||
721 | ippDelete(response); | |
722 | return (0); | |
723 | } | |
724 | ||
725 | *jobs = temp; | |
726 | temp += n; | |
727 | n ++; | |
728 | ||
729 | /* | |
730 | * Copy the data over... | |
731 | */ | |
732 | ||
733 | temp->dest = strdup(dest); | |
734 | temp->user = strdup(user); | |
735 | temp->format = strdup(format); | |
736 | temp->title = strdup(title); | |
737 | temp->id = id; | |
738 | temp->priority = priority; | |
739 | temp->state = state; | |
740 | temp->size = size; | |
741 | temp->completed_time = completed_time; | |
742 | temp->creation_time = creation_time; | |
743 | temp->processing_time = processing_time; | |
744 | ||
745 | if (attr == NULL) | |
746 | break; | |
747 | } | |
748 | ||
749 | ippDelete(response); | |
750 | } | |
751 | ||
752 | if (n == 0 && cg->last_error >= IPP_BAD_REQUEST) | |
753 | return (-1); | |
754 | else | |
755 | return (n); | |
756 | } | |
757 | ||
758 | ||
759 | /* | |
760 | * 'cupsGetPPD()' - Get the PPD file for a printer on the default server. | |
761 | * | |
762 | * For classes, cupsGetPPD() returns the PPD file for the first printer | |
763 | * in the class. | |
764 | */ | |
765 | ||
766 | const char * /* O - Filename for PPD file */ | |
767 | cupsGetPPD(const char *name) /* I - Printer name */ | |
768 | { | |
769 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
770 | ||
771 | /* | |
772 | * See if we can connect to the server... | |
773 | */ | |
774 | ||
775 | if (!cups_connect(name, NULL, NULL)) | |
776 | { | |
777 | DEBUG_puts("Unable to connect to server!"); | |
778 | ||
779 | return (NULL); | |
780 | } | |
781 | ||
782 | /* | |
783 | * Return the PPD file... | |
784 | */ | |
785 | ||
786 | return (cupsGetPPD2(cg->http, name)); | |
787 | } | |
788 | ||
789 | ||
790 | /* | |
791 | * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server. | |
792 | * | |
793 | * For classes, cupsGetPPD2() returns the PPD file for the first printer | |
794 | * in the class. | |
795 | * | |
796 | * @since CUPS 1.1.21@ | |
797 | */ | |
798 | ||
799 | const char * /* O - Filename for PPD file */ | |
800 | cupsGetPPD2(http_t *http, /* I - HTTP connection */ | |
801 | const char *name) /* I - Printer name */ | |
802 | { | |
ef416fc2 | 803 | int http_port; /* Port number */ |
ed486911 | 804 | char http_hostname[HTTP_MAX_HOST]; |
805 | /* Hostname associated with connection */ | |
ef416fc2 | 806 | http_t *http2; /* Alternate HTTP connection */ |
ef416fc2 | 807 | int fd; /* PPD file */ |
fa73b229 | 808 | char localhost[HTTP_MAX_URI],/* Local hostname */ |
ef416fc2 | 809 | hostname[HTTP_MAX_URI], /* Hostname */ |
810 | resource[HTTP_MAX_URI]; /* Resource name */ | |
811 | int port; /* Port number */ | |
812 | http_status_t status; /* HTTP status from server */ | |
813 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
ef416fc2 | 814 | |
815 | ||
816 | /* | |
817 | * Range check input... | |
818 | */ | |
819 | ||
820 | DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http, | |
821 | name ? name : "(null)")); | |
822 | ||
823 | if (!http || !name) | |
824 | { | |
b423cd4c | 825 | if (!http) |
826 | _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!"); | |
827 | else | |
828 | _cupsSetError(IPP_INTERNAL_ERROR, "No printer name!"); | |
ef416fc2 | 829 | |
830 | return (NULL); | |
831 | } | |
832 | ||
833 | /* | |
fa73b229 | 834 | * Try finding a printer URI for this printer... |
ef416fc2 | 835 | */ |
836 | ||
fa73b229 | 837 | if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port, |
838 | resource, sizeof(resource), 0)) | |
ef416fc2 | 839 | return (NULL); |
ef416fc2 | 840 | |
8ca02f3c | 841 | DEBUG_printf(("Printer hostname=\"%s\", port=%d\n", hostname, port)); |
842 | ||
ef416fc2 | 843 | /* |
fa73b229 | 844 | * Remap local hostname to localhost... |
845 | */ | |
846 | ||
757d2cad | 847 | httpGetHostname(NULL, localhost, sizeof(localhost)); |
fa73b229 | 848 | |
8ca02f3c | 849 | DEBUG_printf(("Local hostname=\"%s\"\n", localhost)); |
850 | ||
fa73b229 | 851 | if (!strcasecmp(localhost, hostname)) |
852 | strcpy(hostname, "localhost"); | |
853 | ||
854 | /* | |
ed486911 | 855 | * Get the hostname and port number we are connected to... |
ef416fc2 | 856 | */ |
857 | ||
ed486911 | 858 | httpGetHostname(http, http_hostname, sizeof(http_hostname)); |
859 | ||
ef416fc2 | 860 | #ifdef AF_INET6 |
861 | if (http->hostaddr->addr.sa_family == AF_INET6) | |
862 | http_port = ntohs(http->hostaddr->ipv6.sin6_port); | |
863 | else | |
864 | #endif /* AF_INET6 */ | |
865 | if (http->hostaddr->addr.sa_family == AF_INET) | |
866 | http_port = ntohs(http->hostaddr->ipv4.sin_port); | |
867 | else | |
868 | http_port = ippPort(); | |
869 | ||
8ca02f3c | 870 | DEBUG_printf(("Connection hostname=\"%s\", port=%d\n", http_hostname, |
871 | http_port)); | |
872 | ||
ef416fc2 | 873 | /* |
874 | * Reconnect to the correct server as needed... | |
875 | */ | |
876 | ||
ed486911 | 877 | if (!strcasecmp(http_hostname, hostname) && port == http_port) |
ef416fc2 | 878 | http2 = http; |
879 | else if ((http2 = httpConnectEncrypt(hostname, port, | |
880 | cupsEncryption())) == NULL) | |
881 | { | |
882 | DEBUG_puts("Unable to connect to server!"); | |
883 | ||
884 | return (NULL); | |
885 | } | |
886 | ||
887 | /* | |
888 | * Get a temp file... | |
889 | */ | |
890 | ||
891 | if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0) | |
892 | { | |
893 | /* | |
894 | * Can't open file; close the server connection and return NULL... | |
895 | */ | |
896 | ||
ecdc0628 | 897 | _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); |
ef416fc2 | 898 | |
899 | if (http2 != http) | |
900 | httpClose(http2); | |
901 | ||
902 | return (NULL); | |
903 | } | |
904 | ||
905 | /* | |
906 | * And send a request to the HTTP server... | |
907 | */ | |
908 | ||
fa73b229 | 909 | strlcat(resource, ".ppd", sizeof(resource)); |
ef416fc2 | 910 | |
911 | status = cupsGetFd(http2, resource, fd); | |
912 | ||
913 | close(fd); | |
914 | ||
915 | if (http2 != http) | |
916 | httpClose(http2); | |
917 | ||
918 | /* | |
919 | * See if we actually got the file or an error... | |
920 | */ | |
921 | ||
922 | if (status != HTTP_OK) | |
923 | { | |
924 | switch (status) | |
925 | { | |
926 | case HTTP_NOT_FOUND : | |
ecdc0628 | 927 | _cupsSetError(IPP_NOT_FOUND, httpStatus(status)); |
ef416fc2 | 928 | break; |
929 | ||
930 | case HTTP_UNAUTHORIZED : | |
ecdc0628 | 931 | _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status)); |
ef416fc2 | 932 | break; |
933 | ||
934 | default : | |
935 | DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n", | |
936 | status)); | |
ecdc0628 | 937 | _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status)); |
ef416fc2 | 938 | break; |
939 | } | |
940 | ||
941 | unlink(cg->ppd_filename); | |
942 | ||
943 | return (NULL); | |
944 | } | |
945 | ||
946 | /* | |
947 | * Return the PPD file... | |
948 | */ | |
949 | ||
950 | return (cg->ppd_filename); | |
951 | } | |
952 | ||
953 | ||
954 | /* | |
955 | * 'cupsGetPrinters()' - Get a list of printers from the default server. | |
956 | * | |
957 | * This function is deprecated - use cupsGetDests() instead. | |
958 | * | |
959 | * @deprecated@ | |
960 | */ | |
961 | ||
962 | int /* O - Number of printers */ | |
963 | cupsGetPrinters(char ***printers) /* O - Printers */ | |
964 | { | |
965 | int n; /* Number of printers */ | |
966 | ipp_t *request, /* IPP Request */ | |
967 | *response; /* IPP Response */ | |
968 | ipp_attribute_t *attr; /* Current attribute */ | |
969 | cups_lang_t *language; /* Default language */ | |
970 | char **temp; /* Temporary pointer */ | |
971 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
972 | ||
973 | ||
974 | if (printers == NULL) | |
975 | { | |
ecdc0628 | 976 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 977 | |
978 | return (0); | |
979 | } | |
980 | ||
981 | /* | |
982 | * Try to connect to the server... | |
983 | */ | |
984 | ||
985 | if (!cups_connect("default", NULL, NULL)) | |
986 | { | |
987 | DEBUG_puts("Unable to connect to server!"); | |
988 | ||
989 | return (0); | |
990 | } | |
991 | ||
992 | /* | |
993 | * Build a CUPS_GET_PRINTERS request, which requires the following | |
994 | * attributes: | |
995 | * | |
996 | * attributes-charset | |
997 | * attributes-natural-language | |
998 | * requested-attributes | |
999 | */ | |
1000 | ||
1001 | request = ippNew(); | |
1002 | ||
1003 | request->request.op.operation_id = CUPS_GET_PRINTERS; | |
1004 | request->request.op.request_id = 1; | |
1005 | ||
1006 | language = cupsLangDefault(); | |
1007 | ||
1008 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
1009 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
1010 | ||
1011 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
1012 | "attributes-natural-language", NULL, language->language); | |
1013 | ||
1014 | cupsLangFree(language); | |
1015 | ||
1016 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
1017 | "requested-attributes", NULL, "printer-name"); | |
1018 | ||
1019 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, | |
1020 | "printer-type", 0); | |
1021 | ||
1022 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, | |
1023 | "printer-type-mask", CUPS_PRINTER_CLASS); | |
1024 | ||
1025 | /* | |
1026 | * Do the request and get back a response... | |
1027 | */ | |
1028 | ||
1029 | n = 0; | |
1030 | *printers = NULL; | |
1031 | ||
1032 | if ((response = cupsDoRequest(cg->http, request, "/")) != NULL) | |
1033 | { | |
1034 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
1035 | if (attr->name != NULL && | |
1036 | strcasecmp(attr->name, "printer-name") == 0 && | |
1037 | attr->value_tag == IPP_TAG_NAME) | |
1038 | { | |
1039 | if (n == 0) | |
1040 | temp = malloc(sizeof(char *)); | |
1041 | else | |
1042 | temp = realloc(*printers, sizeof(char *) * (n + 1)); | |
1043 | ||
1044 | if (temp == NULL) | |
1045 | { | |
1046 | /* | |
1047 | * Ran out of memory! | |
1048 | */ | |
1049 | ||
1050 | while (n > 0) | |
1051 | { | |
1052 | n --; | |
1053 | free((*printers)[n]); | |
1054 | } | |
1055 | ||
1056 | free(*printers); | |
1057 | ippDelete(response); | |
1058 | return (0); | |
1059 | } | |
1060 | ||
1061 | *printers = temp; | |
1062 | temp[n] = strdup(attr->values[0].string.text); | |
1063 | n ++; | |
1064 | } | |
1065 | ||
1066 | ippDelete(response); | |
1067 | } | |
1068 | ||
1069 | return (n); | |
1070 | } | |
1071 | ||
1072 | ||
b94498cf | 1073 | /* |
1074 | * 'cupsGetServerPPD()' - Get an available PPD file from the server. | |
1075 | * | |
1076 | * This function returns the named PPD file from the server. The | |
1077 | * list of available PPDs is provided by the IPP CUPS_GET_PPDS | |
1078 | * operation. | |
1079 | * | |
1080 | * You must remove (unlink) the PPD file when you are finished with | |
1081 | * it. The PPD filename is stored in a static location that will be | |
1082 | * overwritten on the next call to cupsGetPPD(), cupsGetPPD2(), or | |
1083 | * cupsGetServerPPD(). | |
1084 | * | |
1085 | * @since CUPS 1.3@ | |
1086 | */ | |
1087 | ||
1088 | char * /* O - Name of PPD file or NULL on error */ | |
1089 | cupsGetServerPPD(http_t *http, /* I - HTTP connection */ | |
1090 | const char *name) /* I - Name of PPD file ("ppd-name") */ | |
1091 | { | |
1092 | int fd; /* PPD file descriptor */ | |
1093 | ipp_t *request; /* IPP request */ | |
1094 | _cups_globals_t *cg = _cupsGlobals(); | |
1095 | /* Pointer to library globals */ | |
1096 | ||
1097 | ||
1098 | /* | |
1099 | * Range check input... | |
1100 | */ | |
1101 | ||
1102 | if (!http || !name) | |
1103 | { | |
1104 | if (!http) | |
1105 | _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!"); | |
1106 | else | |
1107 | _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!"); | |
1108 | ||
1109 | return (NULL); | |
1110 | } | |
1111 | ||
1112 | /* | |
1113 | * Get a temp file... | |
1114 | */ | |
1115 | ||
1116 | if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0) | |
1117 | { | |
1118 | /* | |
1119 | * Can't open file; close the server connection and return NULL... | |
1120 | */ | |
1121 | ||
1122 | _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); | |
1123 | ||
1124 | return (NULL); | |
1125 | } | |
1126 | ||
1127 | /* | |
1128 | * Get the PPD file... | |
1129 | */ | |
1130 | ||
1131 | request = ippNewRequest(CUPS_GET_PPD); | |
1132 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL, | |
1133 | name); | |
1134 | ||
1135 | ippDelete(cupsDoIORequest(http, request, "/", -1, fd)); | |
1136 | ||
1137 | close(fd); | |
1138 | ||
1139 | if (cupsLastError() != IPP_OK) | |
1140 | { | |
1141 | unlink(cg->ppd_filename); | |
1142 | return (NULL); | |
1143 | } | |
1144 | else | |
1145 | return (cg->ppd_filename); | |
1146 | } | |
1147 | ||
1148 | ||
ef416fc2 | 1149 | /* |
1150 | * 'cupsLastError()' - Return the last IPP status code. | |
1151 | */ | |
1152 | ||
1153 | ipp_status_t /* O - IPP status code from last request */ | |
1154 | cupsLastError(void) | |
1155 | { | |
1156 | return (_cupsGlobals()->last_error); | |
1157 | } | |
1158 | ||
1159 | ||
1160 | /* | |
1161 | * 'cupsLastErrorString()' - Return the last IPP status-message. | |
1162 | * | |
1163 | * @since CUPS 1.2@ | |
1164 | */ | |
1165 | ||
1166 | const char * /* O - status-message text from last request */ | |
1167 | cupsLastErrorString(void) | |
1168 | { | |
1169 | return (_cupsGlobals()->last_status_message); | |
1170 | } | |
1171 | ||
1172 | ||
1173 | /* | |
1174 | * 'cupsPrintFile()' - Print a file to a printer or class on the default server. | |
1175 | */ | |
1176 | ||
1177 | int /* O - Job ID */ | |
1178 | cupsPrintFile(const char *name, /* I - Printer or class name */ | |
1179 | const char *filename, /* I - File to print */ | |
1180 | const char *title, /* I - Title of job */ | |
1181 | int num_options,/* I - Number of options */ | |
1182 | cups_option_t *options) /* I - Options */ | |
1183 | { | |
1184 | DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", " | |
1185 | "title=\"%s\", num_options=%d, options=%p)\n", | |
1186 | name, filename, title, num_options, options)); | |
1187 | ||
1188 | return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); | |
1189 | } | |
1190 | ||
1191 | ||
1192 | /* | |
1193 | * 'cupsPrintFile2()' - Print a file to a printer or class on the specified server. | |
1194 | * | |
1195 | * @since CUPS 1.1.21@ | |
1196 | */ | |
1197 | ||
1198 | int /* O - Job ID */ | |
1199 | cupsPrintFile2(http_t *http, /* I - HTTP connection */ | |
1200 | const char *name, /* I - Printer or class name */ | |
1201 | const char *filename, /* I - File to print */ | |
1202 | const char *title, /* I - Title of job */ | |
1203 | int num_options, | |
1204 | /* I - Number of options */ | |
1205 | cups_option_t *options) /* I - Options */ | |
1206 | { | |
1207 | DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", " | |
1208 | "title=\"%s\", num_options=%d, options=%p)\n", | |
1209 | http, name, filename, title, num_options, options)); | |
1210 | ||
1211 | return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options)); | |
1212 | } | |
1213 | ||
1214 | ||
1215 | /* | |
fa73b229 | 1216 | * 'cupsPrintFiles()' - Print one or more files to a printer or class on the |
1217 | * default server. | |
ef416fc2 | 1218 | */ |
1219 | ||
1220 | int /* O - Job ID */ | |
1221 | cupsPrintFiles(const char *name, /* I - Printer or class name */ | |
1222 | int num_files, /* I - Number of files */ | |
1223 | const char **files, /* I - File(s) to print */ | |
1224 | const char *title, /* I - Title of job */ | |
1225 | int num_options, | |
1226 | /* I - Number of options */ | |
1227 | cups_option_t *options) /* I - Options */ | |
1228 | { | |
1229 | _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ | |
1230 | ||
1231 | DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, " | |
1232 | "files=%p, title=\"%s\", num_options=%d, options=%p)\n", | |
1233 | name, num_files, files, title, num_options, options)); | |
1234 | ||
1235 | ||
1236 | /* | |
1237 | * Setup a connection and request data... | |
1238 | */ | |
1239 | ||
1240 | if (!cups_connect(name, NULL, NULL)) | |
1241 | { | |
1242 | DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n", | |
1243 | strerror(errno))); | |
1244 | DEBUG_puts("Unable to connect to server!"); | |
1245 | ||
1246 | return (0); | |
1247 | } | |
1248 | ||
1249 | /* | |
1250 | * Print the file(s)... | |
1251 | */ | |
1252 | ||
1253 | return (cupsPrintFiles2(cg->http, name, num_files, files, title, | |
1254 | num_options, options)); | |
1255 | } | |
1256 | ||
1257 | ||
1258 | ||
1259 | /* | |
fa73b229 | 1260 | * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the |
1261 | * specified server. | |
ef416fc2 | 1262 | * |
1263 | * @since CUPS 1.1.21@ | |
1264 | */ | |
1265 | ||
1266 | int /* O - Job ID */ | |
1267 | cupsPrintFiles2(http_t *http, /* I - HTTP connection */ | |
1268 | const char *name, /* I - Printer or class name */ | |
1269 | int num_files,/* I - Number of files */ | |
1270 | const char **files, /* I - File(s) to print */ | |
1271 | const char *title, /* I - Title of job */ | |
1272 | int num_options, | |
1273 | /* I - Number of options */ | |
1274 | cups_option_t *options) /* I - Options */ | |
1275 | { | |
1276 | int i; /* Looping var */ | |
1277 | const char *val; /* Pointer to option value */ | |
1278 | ipp_t *request; /* IPP request */ | |
1279 | ipp_t *response; /* IPP response */ | |
1280 | ipp_attribute_t *attr; /* IPP job-id attribute */ | |
1281 | char uri[HTTP_MAX_URI]; /* Printer URI */ | |
1282 | cups_lang_t *language; /* Language to use */ | |
1283 | int jobid; /* New job ID */ | |
bd7854cb | 1284 | const char *base; /* Basename of current filename */ |
ef416fc2 | 1285 | |
1286 | ||
1287 | DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, " | |
1288 | "files=%p, title=\"%s\", num_options=%d, options=%p)\n", | |
1289 | http, name, num_files, files, title, num_options, options)); | |
1290 | ||
1291 | /* | |
1292 | * Range check input... | |
1293 | */ | |
1294 | ||
1295 | if (!http || !name || num_files < 1 || files == NULL) | |
1296 | { | |
ecdc0628 | 1297 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 1298 | |
1299 | return (0); | |
1300 | } | |
1301 | ||
1302 | /* | |
1303 | * Setup the printer URI... | |
1304 | */ | |
1305 | ||
a4d04587 | 1306 | if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
1307 | "localhost", 0, "/printers/%s", name) != HTTP_URI_OK) | |
ef416fc2 | 1308 | { |
ecdc0628 | 1309 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 1310 | |
1311 | return (0); | |
1312 | } | |
1313 | ||
1314 | /* | |
1315 | * Setup the request data... | |
1316 | */ | |
1317 | ||
1318 | language = cupsLangDefault(); | |
1319 | ||
1320 | /* | |
1321 | * Build a standard CUPS URI for the printer and fill the standard IPP | |
1322 | * attributes... | |
1323 | */ | |
1324 | ||
1325 | if ((request = ippNew()) == NULL) | |
1326 | { | |
ecdc0628 | 1327 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 1328 | |
1329 | return (0); | |
1330 | } | |
1331 | ||
1332 | request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB : | |
1333 | IPP_CREATE_JOB; | |
1334 | request->request.op.request_id = 1; | |
1335 | ||
1336 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
1337 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
1338 | ||
1339 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
1340 | "attributes-natural-language", NULL, | |
1341 | language != NULL ? language->language : "C"); | |
1342 | ||
1343 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1344 | NULL, uri); | |
1345 | ||
1346 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
1347 | NULL, cupsUser()); | |
1348 | ||
1349 | if (title) | |
1350 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, | |
1351 | title); | |
1352 | ||
1353 | /* | |
1354 | * Then add all options... | |
1355 | */ | |
1356 | ||
1357 | cupsEncodeOptions(request, num_options, options); | |
1358 | ||
1359 | /* | |
1360 | * Do the request... | |
1361 | */ | |
1362 | ||
1363 | snprintf(uri, sizeof(uri), "/printers/%s", name); | |
1364 | ||
1365 | if (num_files == 1) | |
1366 | response = cupsDoFileRequest(http, request, uri, *files); | |
1367 | else | |
1368 | response = cupsDoRequest(http, request, uri); | |
1369 | ||
1370 | if (response == NULL) | |
1371 | jobid = 0; | |
1372 | else if (response->request.status.status_code > IPP_OK_CONFLICT) | |
1373 | { | |
1374 | DEBUG_printf(("IPP response code was 0x%x!\n", | |
1375 | response->request.status.status_code)); | |
1376 | jobid = 0; | |
1377 | } | |
1378 | else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) | |
1379 | { | |
1380 | DEBUG_puts("No job ID!"); | |
1381 | ||
ecdc0628 | 1382 | _cupsSetError(IPP_INTERNAL_ERROR, NULL); |
ef416fc2 | 1383 | |
1384 | jobid = 0; | |
1385 | } | |
1386 | else | |
1387 | jobid = attr->values[0].integer; | |
1388 | ||
1389 | if (response != NULL) | |
1390 | ippDelete(response); | |
1391 | ||
1392 | /* | |
1393 | * Handle multiple file jobs if the create-job operation worked... | |
1394 | */ | |
1395 | ||
1396 | if (jobid > 0 && num_files > 1) | |
1397 | for (i = 0; i < num_files; i ++) | |
1398 | { | |
1399 | /* | |
1400 | * Build a standard CUPS URI for the job and fill the standard IPP | |
1401 | * attributes... | |
1402 | */ | |
1403 | ||
1404 | if ((request = ippNew()) == NULL) | |
1405 | return (0); | |
1406 | ||
1407 | request->request.op.operation_id = IPP_SEND_DOCUMENT; | |
1408 | request->request.op.request_id = 1; | |
1409 | ||
1410 | snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", jobid); | |
1411 | ||
1412 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
1413 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
1414 | ||
1415 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
1416 | "attributes-natural-language", NULL, | |
1417 | language != NULL ? language->language : "C"); | |
1418 | ||
1419 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", | |
1420 | NULL, uri); | |
1421 | ||
1422 | /* | |
1423 | * Handle raw print files... | |
1424 | */ | |
1425 | ||
1426 | if (cupsGetOption("raw", num_options, options)) | |
fa73b229 | 1427 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, |
1428 | "document-format", NULL, "application/vnd.cups-raw"); | |
1429 | else if ((val = cupsGetOption("document-format", num_options, | |
1430 | options)) != NULL) | |
1431 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, | |
1432 | "document-format", NULL, val); | |
ef416fc2 | 1433 | else |
fa73b229 | 1434 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, |
1435 | "document-format", NULL, "application/octet-stream"); | |
ef416fc2 | 1436 | |
fa73b229 | 1437 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, |
1438 | "requesting-user-name", NULL, cupsUser()); | |
ef416fc2 | 1439 | |
bd7854cb | 1440 | /* |
1441 | * Add the original document filename... | |
1442 | */ | |
1443 | ||
1444 | if ((base = strrchr(files[i], '/')) != NULL) | |
1445 | base ++; | |
1446 | else | |
1447 | base = files[i]; | |
1448 | ||
1449 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", | |
1450 | NULL, base); | |
1451 | ||
ef416fc2 | 1452 | /* |
1453 | * Is this the last document? | |
1454 | */ | |
1455 | ||
1456 | if (i == (num_files - 1)) | |
1457 | ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); | |
1458 | ||
1459 | /* | |
1460 | * Send the file... | |
1461 | */ | |
1462 | ||
1463 | snprintf(uri, sizeof(uri), "/printers/%s", name); | |
1464 | ||
1465 | if ((response = cupsDoFileRequest(http, request, uri, | |
1466 | files[i])) != NULL) | |
1467 | ippDelete(response); | |
1468 | } | |
1469 | ||
1470 | cupsLangFree(language); | |
1471 | ||
1472 | return (jobid); | |
1473 | } | |
1474 | ||
1475 | ||
1476 | /* | |
1477 | * 'cups_connect()' - Connect to the specified host... | |
1478 | */ | |
1479 | ||
1480 | static char * /* I - Printer name or NULL */ | |
1481 | cups_connect(const char *name, /* I - Destination (printer[@host]) */ | |
1482 | char *printer, /* O - Printer name [HTTP_MAX_URI] */ | |
1483 | char *hostname) /* O - Hostname [HTTP_MAX_URI] */ | |
1484 | { | |
ed486911 | 1485 | char hostbuf[HTTP_MAX_URI], /* Name of host */ |
1486 | http_hostname[HTTP_MAX_HOST]; /* Hostname associated with connection */ | |
fa73b229 | 1487 | _cups_globals_t *cg = _cupsGlobals();/* Pointer to library globals */ |
ef416fc2 | 1488 | |
1489 | ||
1490 | DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); | |
1491 | ||
1492 | if (name == NULL) | |
1493 | { | |
ecdc0628 | 1494 | _cupsSetError(IPP_BAD_REQUEST, NULL); |
ef416fc2 | 1495 | |
1496 | return (NULL); | |
1497 | } | |
1498 | ||
1499 | /* | |
1500 | * All jobs are now queued to cupsServer() to avoid hostname | |
1501 | * resolution problems and to ensure that the user sees all | |
1502 | * locally queued jobs locally. | |
1503 | */ | |
1504 | ||
1505 | strlcpy(hostbuf, cupsServer(), sizeof(hostbuf)); | |
1506 | ||
ed486911 | 1507 | httpGetHostname(cg->http, http_hostname, sizeof(http_hostname)); |
1508 | ||
ef416fc2 | 1509 | if (hostname != NULL) |
1510 | strlcpy(hostname, hostbuf, HTTP_MAX_URI); | |
1511 | else | |
1512 | hostname = hostbuf; | |
1513 | ||
1514 | if (printer != NULL) | |
1515 | strlcpy(printer, name, HTTP_MAX_URI); | |
1516 | else | |
1517 | printer = (char *)name; | |
1518 | ||
1519 | if (cg->http != NULL) | |
1520 | { | |
ed486911 | 1521 | if (!strcasecmp(http_hostname, hostname)) |
ef416fc2 | 1522 | return (printer); |
1523 | ||
1524 | httpClose(cg->http); | |
1525 | } | |
1526 | ||
1527 | DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); | |
1528 | ||
1529 | if ((cg->http = httpConnectEncrypt(hostname, ippPort(), | |
fa73b229 | 1530 | cupsEncryption())) == NULL) |
ef416fc2 | 1531 | { |
1532 | DEBUG_puts("Unable to connect to server!"); | |
1533 | ||
ecdc0628 | 1534 | _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno)); |
ef416fc2 | 1535 | |
1536 | return (NULL); | |
1537 | } | |
1538 | else | |
1539 | return (printer); | |
1540 | } | |
1541 | ||
1542 | ||
fa73b229 | 1543 | /* |
1544 | * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the first printer in a class. | |
1545 | */ | |
1546 | ||
1547 | static int /* O - 1 on success, 0 on failure */ | |
1548 | cups_get_printer_uri( | |
1549 | http_t *http, /* I - HTTP connection */ | |
1550 | const char *name, /* I - Name of printer or class */ | |
1551 | char *host, /* I - Hostname buffer */ | |
1552 | int hostsize, /* I - Size of hostname buffer */ | |
1553 | int *port, /* O - Port number */ | |
1554 | char *resource, /* I - Resource buffer */ | |
1555 | int resourcesize, /* I - Size of resource buffer */ | |
1556 | int depth) /* I - Depth of query */ | |
1557 | { | |
1558 | int i; /* Looping var */ | |
1559 | int http_port; /* Port number */ | |
1560 | http_t *http2; /* Alternate HTTP connection */ | |
1561 | ipp_t *request, /* IPP request */ | |
1562 | *response; /* IPP response */ | |
1563 | ipp_attribute_t *attr; /* Current attribute */ | |
1564 | char uri[HTTP_MAX_URI], /* printer-uri attribute */ | |
1565 | scheme[HTTP_MAX_URI], /* Scheme name */ | |
1566 | username[HTTP_MAX_URI], /* Username:password */ | |
ed486911 | 1567 | classname[255], /* Temporary class name */ |
1568 | http_hostname[HTTP_MAX_HOST]; | |
1569 | /* Hostname associated with connection */ | |
fa73b229 | 1570 | static const char * const requested_attrs[] = |
1571 | { /* Requested attributes */ | |
1572 | "printer-uri-supported", | |
1573 | "printer-type", | |
1574 | "member-uris" | |
1575 | }; | |
1576 | ||
1577 | ||
1578 | DEBUG_printf(("cups_get_printer_uri(http=%p, name=\"%s\", host=%p, " | |
1579 | "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)\n", | |
1580 | http, name ? name : "(null)", host, hostsize, | |
1581 | resource, resourcesize, depth)); | |
1582 | ||
1583 | /* | |
1584 | * Setup the printer URI... | |
1585 | */ | |
1586 | ||
a4d04587 | 1587 | if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
1588 | "localhost", 0, "/printers/%s", name) != HTTP_URI_OK) | |
fa73b229 | 1589 | { |
b423cd4c | 1590 | _cupsSetError(IPP_INTERNAL_ERROR, "Unable to create printer-uri!"); |
fa73b229 | 1591 | |
1592 | *host = '\0'; | |
1593 | *resource = '\0'; | |
1594 | ||
1595 | return (0); | |
1596 | } | |
1597 | ||
1598 | DEBUG_printf(("cups_get_printer_uri: printer-uri=\"%s\"\n", uri)); | |
1599 | ||
1600 | /* | |
ed486911 | 1601 | * Get the hostname and port number we are connected to... |
fa73b229 | 1602 | */ |
1603 | ||
ed486911 | 1604 | httpGetHostname(http, http_hostname, sizeof(http_hostname)); |
1605 | ||
fa73b229 | 1606 | #ifdef AF_INET6 |
1607 | if (http->hostaddr->addr.sa_family == AF_INET6) | |
1608 | http_port = ntohs(http->hostaddr->ipv6.sin6_port); | |
1609 | else | |
1610 | #endif /* AF_INET6 */ | |
1611 | if (http->hostaddr->addr.sa_family == AF_INET) | |
1612 | http_port = ntohs(http->hostaddr->ipv4.sin_port); | |
1613 | else | |
1614 | http_port = ippPort(); | |
1615 | ||
1616 | /* | |
1617 | * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following | |
1618 | * attributes: | |
1619 | * | |
1620 | * attributes-charset | |
1621 | * attributes-natural-language | |
1622 | * printer-uri | |
1623 | * requested-attributes | |
1624 | */ | |
1625 | ||
1626 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); | |
1627 | ||
1628 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1629 | NULL, uri); | |
1630 | ||
1631 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, | |
1632 | "requested-attributes", | |
1633 | sizeof(requested_attrs) / sizeof(requested_attrs[0]), | |
1634 | NULL, requested_attrs); | |
1635 | ||
1636 | /* | |
1637 | * Do the request and get back a response... | |
1638 | */ | |
1639 | ||
1640 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
1641 | { | |
1642 | if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) | |
1643 | { | |
1644 | /* | |
1645 | * Get the first actual printer name in the class... | |
1646 | */ | |
1647 | ||
1648 | for (i = 0; i < attr->num_values; i ++) | |
1649 | { | |
a4d04587 | 1650 | httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, |
1651 | scheme, sizeof(scheme), username, sizeof(username), | |
1652 | host, hostsize, port, resource, resourcesize); | |
fa73b229 | 1653 | if (!strncmp(resource, "/printers/", 10)) |
1654 | { | |
1655 | /* | |
1656 | * Found a printer! | |
1657 | */ | |
1658 | ||
1659 | ippDelete(response); | |
1660 | ||
1661 | return (1); | |
1662 | } | |
1663 | } | |
1664 | ||
1665 | /* | |
1666 | * No printers in this class - try recursively looking for a printer, | |
1667 | * but not more than 3 levels deep... | |
1668 | */ | |
1669 | ||
1670 | if (depth < 3) | |
1671 | { | |
1672 | for (i = 0; i < attr->num_values; i ++) | |
1673 | { | |
a4d04587 | 1674 | httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, |
1675 | scheme, sizeof(scheme), username, sizeof(username), | |
1676 | host, hostsize, port, resource, resourcesize); | |
fa73b229 | 1677 | if (!strncmp(resource, "/classes/", 9)) |
1678 | { | |
1679 | /* | |
1680 | * Found a class! Connect to the right server... | |
1681 | */ | |
1682 | ||
ed486911 | 1683 | if (!strcasecmp(http_hostname, host) && *port == http_port) |
fa73b229 | 1684 | http2 = http; |
1685 | else if ((http2 = httpConnectEncrypt(host, *port, | |
1686 | cupsEncryption())) == NULL) | |
1687 | { | |
1688 | DEBUG_puts("Unable to connect to server!"); | |
1689 | ||
1690 | continue; | |
1691 | } | |
1692 | ||
1693 | /* | |
1694 | * Look up printers on that server... | |
1695 | */ | |
1696 | ||
1697 | strlcpy(classname, resource + 9, sizeof(classname)); | |
1698 | ||
1699 | cups_get_printer_uri(http2, classname, host, hostsize, port, | |
1700 | resource, resourcesize, depth + 1); | |
1701 | ||
1702 | /* | |
1703 | * Close the connection as needed... | |
1704 | */ | |
1705 | ||
1706 | if (http2 != http) | |
1707 | httpClose(http2); | |
1708 | ||
1709 | if (*host) | |
1710 | return (1); | |
1711 | } | |
1712 | } | |
1713 | } | |
1714 | } | |
1715 | else if ((attr = ippFindAttribute(response, "printer-uri-supported", | |
1716 | IPP_TAG_URI)) != NULL) | |
1717 | { | |
a4d04587 | 1718 | httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, |
1719 | scheme, sizeof(scheme), username, sizeof(username), | |
1720 | host, hostsize, port, resource, resourcesize); | |
fa73b229 | 1721 | ippDelete(response); |
1722 | ||
1723 | return (1); | |
1724 | } | |
1725 | ||
1726 | ippDelete(response); | |
1727 | } | |
1728 | ||
b86bc4cf | 1729 | if (cupsLastError() != IPP_NOT_FOUND) |
1730 | _cupsSetError(IPP_INTERNAL_ERROR, "No printer-uri found!"); | |
b423cd4c | 1731 | |
fa73b229 | 1732 | *host = '\0'; |
1733 | *resource = '\0'; | |
1734 | ||
1735 | return (0); | |
1736 | } | |
1737 | ||
1738 | ||
ef416fc2 | 1739 | /* |
b94498cf | 1740 | * End of "$Id: util.c 6506 2007-05-03 18:12:35Z mike $". |
ef416fc2 | 1741 | */ |