2 * "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $"
4 * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * This file contains Kerberos support code, copyright 2006 by
12 * These coded instructions, statements, and computer programs are the
13 * property of Apple Inc. and are protected by Federal copyright
14 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
15 * which should have been included with this file. If this file is
16 * file is missing or damaged, see the license at "http://www.cups.org/".
20 * cupsdProcessIPPRequest() - Process an incoming IPP request.
21 * cupsdTimeoutJob() - Timeout a job waiting on job files.
22 * accept_jobs() - Accept print jobs to a printer.
23 * add_class() - Add a class to the system.
24 * add_file() - Add a file to a job.
25 * add_job() - Add a job to a print queue.
26 * add_job_state_reasons() - Add the "job-state-reasons" attribute based
27 * upon the job and printer state...
28 * add_job_subscriptions() - Add any subscriptions for a job.
29 * add_job_uuid() - Add job-uuid attribute to a job.
30 * add_printer() - Add a printer to the system.
31 * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
32 * based upon the printer state...
33 * add_queued_job_count() - Add the "queued-job-count" attribute for the
34 * specified printer or class.
35 * apple_init_profile() - Initialize a color profile.
36 * apple_register_profiles() - Register color profiles for a printer.
37 * apple_unregister_profiles() - Remove color profiles for the specified
39 * apply_printer_defaults() - Apply printer default options to a job.
40 * authenticate_job() - Set job authentication info.
41 * cancel_all_jobs() - Cancel all print jobs.
42 * cancel_job() - Cancel a print job.
43 * cancel_subscription() - Cancel a subscription.
44 * check_quotas() - Check quotas for a printer and user.
45 * check_rss_recipient() - Check that we do not have a duplicate RSS
47 * copy_attribute() - Copy a single attribute.
48 * copy_attrs() - Copy attributes from one request to another.
49 * copy_banner() - Copy a banner file to the requests directory
50 * for the specified job.
51 * copy_file() - Copy a PPD file or interface script...
52 * copy_model() - Copy a PPD model file, substituting default
54 * copy_job_attrs() - Copy job attributes.
55 * copy_printer_attrs() - Copy printer attributes.
56 * copy_subscription_attrs() - Copy subscription attributes.
57 * create_job() - Print a file to a printer or class.
58 * create_requested_array() - Create an array for the requested-attributes.
59 * create_subscription() - Create a notification subscription.
60 * delete_printer() - Remove a printer or class from the system.
61 * get_default() - Get the default destination.
62 * get_devices() - Get the list of available devices on the
64 * get_document() - Get a copy of a job file.
65 * get_job_attrs() - Get job attributes.
66 * get_jobs() - Get a list of jobs for the specified printer.
67 * get_notifications() - Get events for a subscription.
68 * get_ppd() - Get a named PPD from the local system.
69 * get_ppds() - Get the list of PPD files on the local
71 * get_printer_attrs() - Get printer attributes.
72 * get_printers() - Get a list of printers or classes.
73 * get_subscription_attrs() - Get subscription attributes.
74 * get_subscriptions() - Get subscriptions.
75 * get_username() - Get the username associated with a request.
76 * hold_job() - Hold a print job.
77 * move_job() - Move a job to a new destination.
78 * ppd_parse_line() - Parse a PPD default line.
79 * print_job() - Print a file to a printer or class.
80 * read_job_ticket() - Read a job ticket embedded in a print file.
81 * reject_jobs() - Reject print jobs to a printer.
82 * release_job() - Release a held print job.
83 * renew_subscription() - Renew an existing subscription...
84 * restart_job() - Restart an old print job.
85 * save_auth_info() - Save authentication information for a job.
86 * save_krb5_creds() - Save Kerberos credentials for the job.
87 * send_document() - Send a file to a printer or class.
88 * send_http_error() - Send a HTTP error back to the IPP client.
89 * send_ipp_status() - Send a status back to the IPP client.
90 * set_default() - Set the default destination...
91 * set_job_attrs() - Set job attributes.
92 * set_printer_attrs() - Set printer attributes.
93 * set_printer_defaults() - Set printer default options from a request.
94 * start_printer() - Start a printer.
95 * stop_printer() - Stop a printer.
96 * url_encode_attr() - URL-encode a string attribute.
97 * url_encode_string() - URL-encode a string.
98 * user_allowed() - See if a user is allowed to print to a queue.
99 * validate_job() - Validate printer options and destination.
100 * validate_name() - Make sure the printer name only contains
102 * validate_user() - Validate the user for the request.
106 * Include necessary headers...
110 #include <cups/ppd-private.h>
114 #endif /* HAVE_LIBPAPER */
117 # include <ApplicationServices/ApplicationServices.h>
118 # include <CoreFoundation/CoreFoundation.h>
119 # ifdef HAVE_MEMBERSHIP_H
120 # include <membership.h>
121 # endif /* HAVE_MEMBERSHIP_H */
122 # ifdef HAVE_MEMBERSHIPPRIV_H
123 # include <membershipPriv.h>
125 extern int mbr_user_name_to_uuid(const char* name
, uuid_t uu
);
126 extern int mbr_group_name_to_uuid(const char* name
, uuid_t uu
);
127 extern int mbr_check_membership_by_id(uuid_t user
, gid_t group
, int* ismember
);
128 # endif /* HAVE_MEMBERSHIPPRIV_H */
129 #endif /* __APPLE__ */
136 static void accept_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
137 static void add_class(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
138 static int add_file(cupsd_client_t
*con
, cupsd_job_t
*job
,
139 mime_type_t
*filetype
, int compression
);
140 static cupsd_job_t
*add_job(cupsd_client_t
*con
, cupsd_printer_t
*printer
,
141 mime_type_t
*filetype
);
142 static void add_job_state_reasons(cupsd_client_t
*con
, cupsd_job_t
*job
);
143 static void add_job_subscriptions(cupsd_client_t
*con
, cupsd_job_t
*job
);
144 static void add_job_uuid(cupsd_client_t
*con
, cupsd_job_t
*job
);
145 static void add_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
146 static void add_printer_state_reasons(cupsd_client_t
*con
,
148 static void add_queued_job_count(cupsd_client_t
*con
, cupsd_printer_t
*p
);
150 static void apple_init_profile(ppd_file_t
*ppd
, cups_array_t
*languages
,
151 CMDeviceProfileInfo
*profile
, unsigned id
,
152 const char *name
, const char *text
,
153 const char *iccfile
);
154 static void apple_register_profiles(cupsd_printer_t
*p
);
155 static void apple_unregister_profiles(cupsd_printer_t
*p
);
156 #endif /* __APPLE__ */
157 static void apply_printer_defaults(cupsd_printer_t
*printer
,
159 static void authenticate_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
160 static void cancel_all_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
161 static void cancel_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
162 static void cancel_subscription(cupsd_client_t
*con
, int id
);
163 static int check_rss_recipient(const char *recipient
);
164 static int check_quotas(cupsd_client_t
*con
, cupsd_printer_t
*p
);
165 static ipp_attribute_t
*copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
167 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, cups_array_t
*ra
,
168 ipp_tag_t group
, int quickcopy
);
169 static int copy_banner(cupsd_client_t
*con
, cupsd_job_t
*job
,
171 static int copy_file(const char *from
, const char *to
);
172 static int copy_model(cupsd_client_t
*con
, const char *from
,
174 static void copy_job_attrs(cupsd_client_t
*con
,
177 static void copy_printer_attrs(cupsd_client_t
*con
,
178 cupsd_printer_t
*printer
,
180 static void copy_subscription_attrs(cupsd_client_t
*con
,
181 cupsd_subscription_t
*sub
,
183 static void create_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
184 static cups_array_t
*create_requested_array(ipp_t
*request
);
185 static void create_subscription(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
186 static void delete_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
187 static void get_default(cupsd_client_t
*con
);
188 static void get_devices(cupsd_client_t
*con
);
189 static void get_document(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
190 static void get_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
191 static void get_job_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
192 static void get_notifications(cupsd_client_t
*con
);
193 static void get_ppd(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
194 static void get_ppds(cupsd_client_t
*con
);
195 static void get_printers(cupsd_client_t
*con
, int type
);
196 static void get_printer_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
197 static void get_printer_supported(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
198 static void get_subscription_attrs(cupsd_client_t
*con
, int sub_id
);
199 static void get_subscriptions(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
200 static const char *get_username(cupsd_client_t
*con
);
201 static void hold_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
202 static void hold_new_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
203 static void move_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
204 static int ppd_parse_line(const char *line
, char *option
, int olen
,
205 char *choice
, int clen
);
206 static void print_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
207 static void read_job_ticket(cupsd_client_t
*con
);
208 static void reject_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
209 static void release_held_new_jobs(cupsd_client_t
*con
,
210 ipp_attribute_t
*uri
);
211 static void release_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
212 static void renew_subscription(cupsd_client_t
*con
, int sub_id
);
213 static void restart_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
214 static void save_auth_info(cupsd_client_t
*con
, cupsd_job_t
*job
,
215 ipp_attribute_t
*auth_info
);
216 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
217 static void save_krb5_creds(cupsd_client_t
*con
, cupsd_job_t
*job
);
218 #endif /* HAVE_GSSAPI && HAVE_KRB5_H */
219 static void send_document(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
220 static void send_http_error(cupsd_client_t
*con
, http_status_t status
,
221 cupsd_printer_t
*printer
);
222 static void send_ipp_status(cupsd_client_t
*con
, ipp_status_t status
,
223 const char *message
, ...)
225 __attribute__ ((__format__ (__printf__
, 3, 4)))
226 # endif /* __GNUC__ */
228 static void set_default(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
229 static void set_job_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
230 static void set_printer_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
231 static void set_printer_defaults(cupsd_client_t
*con
,
232 cupsd_printer_t
*printer
);
233 static void start_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
234 static void stop_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
235 static void url_encode_attr(ipp_attribute_t
*attr
, char *buffer
,
237 static char *url_encode_string(const char *s
, char *buffer
, int bufsize
);
238 static int user_allowed(cupsd_printer_t
*p
, const char *username
);
239 static void validate_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
240 static int validate_name(const char *name
);
241 static int validate_user(cupsd_job_t
*job
, cupsd_client_t
*con
,
242 const char *owner
, char *username
,
247 * 'cupsdProcessIPPRequest()' - Process an incoming IPP request.
250 int /* O - 1 on success, 0 on failure */
251 cupsdProcessIPPRequest(
252 cupsd_client_t
*con
) /* I - Client connection */
254 ipp_tag_t group
; /* Current group tag */
255 ipp_attribute_t
*attr
; /* Current attribute */
256 ipp_attribute_t
*charset
; /* Character set attribute */
257 ipp_attribute_t
*language
; /* Language attribute */
258 ipp_attribute_t
*uri
= NULL
; /* Printer or job URI attribute */
259 ipp_attribute_t
*username
; /* requesting-user-name attr */
260 int sub_id
; /* Subscription ID */
263 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
264 "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x",
265 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
268 * First build an empty response message for this request...
271 con
->response
= ippNew();
273 con
->response
->request
.status
.version
[0] =
274 con
->request
->request
.op
.version
[0];
275 con
->response
->request
.status
.version
[1] =
276 con
->request
->request
.op
.version
[1];
277 con
->response
->request
.status
.request_id
=
278 con
->request
->request
.op
.request_id
;
281 * Then validate the request header and required attributes...
284 if (con
->request
->request
.any
.version
[0] != 1 &&
285 con
->request
->request
.any
.version
[0] != 2)
288 * Return an error, since we only support IPP 1.x and 2.x.
291 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
292 "%04X %s Bad request version number %d.%d",
293 IPP_VERSION_NOT_SUPPORTED
, con
->http
.hostname
,
294 con
->request
->request
.any
.version
[0],
295 con
->request
->request
.any
.version
[1]);
297 send_ipp_status(con
, IPP_VERSION_NOT_SUPPORTED
,
298 _("Bad request version number %d.%d!"),
299 con
->request
->request
.any
.version
[0],
300 con
->request
->request
.any
.version
[1]);
302 else if (con
->request
->request
.any
.request_id
< 1)
305 * Return an error, since request IDs must be between 1 and 2^31-1
308 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
309 "%04X %s Bad request ID %d",
310 IPP_BAD_REQUEST
, con
->http
.hostname
,
311 con
->request
->request
.any
.request_id
);
313 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad request ID %d!"),
314 con
->request
->request
.any
.request_id
);
316 else if (!con
->request
->attrs
)
318 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
319 "%04X %s No attributes in request",
320 IPP_BAD_REQUEST
, con
->http
.hostname
);
322 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No attributes in request!"));
327 * Make sure that the attributes are provided in the correct order and
328 * don't repeat groups...
331 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
334 if (attr
->group_tag
< group
&& attr
->group_tag
!= IPP_TAG_ZERO
)
337 * Out of order; return an error...
340 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
341 "%04X %s Attribute groups are out of order",
342 IPP_BAD_REQUEST
, con
->http
.hostname
);
344 send_ipp_status(con
, IPP_BAD_REQUEST
,
345 _("Attribute groups are out of order (%x < %x)!"),
346 attr
->group_tag
, group
);
350 group
= attr
->group_tag
;
355 * Then make sure that the first three attributes are:
358 * attributes-natural-language
359 * printer-uri/job-uri
362 attr
= con
->request
->attrs
;
363 if (attr
&& !strcmp(attr
->name
, "attributes-charset") &&
364 (attr
->value_tag
& IPP_TAG_MASK
) == IPP_TAG_CHARSET
)
372 if (attr
&& !strcmp(attr
->name
, "attributes-natural-language") &&
373 (attr
->value_tag
& IPP_TAG_MASK
) == IPP_TAG_LANGUAGE
)
378 if ((attr
= ippFindAttribute(con
->request
, "printer-uri",
379 IPP_TAG_URI
)) != NULL
)
381 else if ((attr
= ippFindAttribute(con
->request
, "job-uri",
382 IPP_TAG_URI
)) != NULL
)
384 else if (con
->request
->request
.op
.operation_id
== CUPS_GET_PPD
)
385 uri
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
);
390 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
391 "attributes-charset", NULL
,
392 charset
->values
[0].string
.text
);
394 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
395 "attributes-charset", NULL
, DefaultCharset
);
398 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
399 "attributes-natural-language", NULL
,
400 language
->values
[0].string
.text
);
402 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
403 "attributes-natural-language", NULL
, DefaultLanguage
);
406 strcasecmp(charset
->values
[0].string
.text
, "us-ascii") &&
407 strcasecmp(charset
->values
[0].string
.text
, "utf-8"))
410 * Bad character set...
413 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unsupported character set \"%s\"!",
414 charset
->values
[0].string
.text
);
415 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
416 "%04X %s Unsupported attributes-charset value \"%s\"",
417 IPP_CHARSET
, con
->http
.hostname
,
418 charset
->values
[0].string
.text
);
419 send_ipp_status(con
, IPP_BAD_REQUEST
,
420 _("Unsupported character set \"%s\"!"),
421 charset
->values
[0].string
.text
);
423 else if (!charset
|| !language
||
425 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
426 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
427 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
428 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
429 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
432 * Return an error, since attributes-charset,
433 * attributes-natural-language, and printer-uri/job-uri are required
434 * for all operations.
439 cupsdLogMessage(CUPSD_LOG_ERROR
,
440 "Missing attributes-charset attribute!");
442 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
443 "%04X %s Missing attributes-charset attribute",
444 IPP_BAD_REQUEST
, con
->http
.hostname
);
449 cupsdLogMessage(CUPSD_LOG_ERROR
,
450 "Missing attributes-natural-language attribute!");
452 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
453 "%04X %s Missing attributes-natural-language attribute",
454 IPP_BAD_REQUEST
, con
->http
.hostname
);
459 cupsdLogMessage(CUPSD_LOG_ERROR
,
460 "Missing printer-uri, job-uri, or ppd-name "
463 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
464 "%04X %s Missing printer-uri, job-uri, or ppd-name "
465 "attribute", IPP_BAD_REQUEST
, con
->http
.hostname
);
468 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Request attributes follow...");
470 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
471 cupsdLogMessage(CUPSD_LOG_DEBUG
,
472 "attr \"%s\": group_tag = %x, value_tag = %x",
473 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
476 cupsdLogMessage(CUPSD_LOG_DEBUG
, "End of attributes...");
478 send_ipp_status(con
, IPP_BAD_REQUEST
,
479 _("Missing required attributes!"));
484 * OK, all the checks pass so far; make sure requesting-user-name is
485 * not "root" from a remote host...
488 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name",
489 IPP_TAG_NAME
)) != NULL
)
492 * Check for root user...
495 if (!strcmp(username
->values
[0].string
.text
, "root") &&
496 strcasecmp(con
->http
.hostname
, "localhost") &&
497 strcmp(con
->username
, "root"))
500 * Remote unauthenticated user masquerading as local root...
503 _cupsStrFree(username
->values
[0].string
.text
);
504 username
->values
[0].string
.text
= _cupsStrAlloc(RemoteRoot
);
508 if ((attr
= ippFindAttribute(con
->request
, "notify-subscription-id",
509 IPP_TAG_INTEGER
)) != NULL
)
510 sub_id
= attr
->values
[0].integer
;
515 * Then try processing the operation...
519 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s %s",
520 ippOpString(con
->request
->request
.op
.operation_id
),
521 uri
->values
[0].string
.text
);
523 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s",
524 ippOpString(con
->request
->request
.op
.operation_id
));
526 switch (con
->request
->request
.op
.operation_id
)
532 case IPP_VALIDATE_JOB
:
533 validate_job(con
, uri
);
536 case IPP_CREATE_JOB
:
537 create_job(con
, uri
);
540 case IPP_SEND_DOCUMENT
:
541 send_document(con
, uri
);
544 case IPP_CANCEL_JOB
:
545 cancel_job(con
, uri
);
548 case IPP_GET_JOB_ATTRIBUTES
:
549 get_job_attrs(con
, uri
);
556 case IPP_GET_PRINTER_ATTRIBUTES
:
557 get_printer_attrs(con
, uri
);
560 case IPP_GET_PRINTER_SUPPORTED_VALUES
:
561 get_printer_supported(con
, uri
);
568 case IPP_RELEASE_JOB
:
569 release_job(con
, uri
);
572 case IPP_RESTART_JOB
:
573 restart_job(con
, uri
);
576 case IPP_PAUSE_PRINTER
:
577 stop_printer(con
, uri
);
580 case IPP_RESUME_PRINTER
:
581 start_printer(con
, uri
);
584 case IPP_PURGE_JOBS
:
585 cancel_all_jobs(con
, uri
);
588 case IPP_SET_JOB_ATTRIBUTES
:
589 set_job_attrs(con
, uri
);
592 case IPP_SET_PRINTER_ATTRIBUTES
:
593 set_printer_attrs(con
, uri
);
596 case IPP_HOLD_NEW_JOBS
:
597 hold_new_jobs(con
, uri
);
600 case IPP_RELEASE_HELD_NEW_JOBS
:
601 release_held_new_jobs(con
, uri
);
604 case CUPS_GET_DEFAULT
:
608 case CUPS_GET_PRINTERS
:
609 get_printers(con
, 0);
612 case CUPS_GET_CLASSES
:
613 get_printers(con
, CUPS_PRINTER_CLASS
);
616 case CUPS_ADD_PRINTER
:
617 add_printer(con
, uri
);
620 case CUPS_DELETE_PRINTER
:
621 delete_printer(con
, uri
);
624 case CUPS_ADD_CLASS
:
628 case CUPS_DELETE_CLASS
:
629 delete_printer(con
, uri
);
632 case CUPS_ACCEPT_JOBS
:
633 case IPP_ENABLE_PRINTER
:
634 accept_jobs(con
, uri
);
637 case CUPS_REJECT_JOBS
:
638 case IPP_DISABLE_PRINTER
:
639 reject_jobs(con
, uri
);
642 case CUPS_SET_DEFAULT
:
643 set_default(con
, uri
);
646 case CUPS_GET_DEVICES
:
650 case CUPS_GET_DOCUMENT
:
651 get_document(con
, uri
);
666 case CUPS_AUTHENTICATE_JOB
:
667 authenticate_job(con
, uri
);
670 case IPP_CREATE_PRINTER_SUBSCRIPTION
:
671 case IPP_CREATE_JOB_SUBSCRIPTION
:
672 create_subscription(con
, uri
);
675 case IPP_GET_SUBSCRIPTION_ATTRIBUTES
:
676 get_subscription_attrs(con
, sub_id
);
679 case IPP_GET_SUBSCRIPTIONS
:
680 get_subscriptions(con
, uri
);
683 case IPP_RENEW_SUBSCRIPTION
:
684 renew_subscription(con
, sub_id
);
687 case IPP_CANCEL_SUBSCRIPTION
:
688 cancel_subscription(con
, sub_id
);
691 case IPP_GET_NOTIFICATIONS
:
692 get_notifications(con
);
696 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
697 "%04X %s Operation %04X (%s) not supported",
698 IPP_OPERATION_NOT_SUPPORTED
, con
->http
.hostname
,
699 con
->request
->request
.op
.operation_id
,
700 ippOpString(con
->request
->request
.op
.operation_id
));
702 send_ipp_status(con
, IPP_OPERATION_NOT_SUPPORTED
,
703 _("%s not supported!"),
705 con
->request
->request
.op
.operation_id
));
715 * Sending data from the scheduler...
718 cupsdLogMessage(con
->response
->request
.status
.status_code
719 >= IPP_BAD_REQUEST
&&
720 con
->response
->request
.status
.status_code
721 != IPP_NOT_FOUND
? CUPSD_LOG_ERROR
: CUPSD_LOG_DEBUG
,
722 "Returning IPP %s for %s (%s) from %s",
723 ippErrorString(con
->response
->request
.status
.status_code
),
724 ippOpString(con
->request
->request
.op
.operation_id
),
725 uri
? uri
->values
[0].string
.text
: "no URI",
728 if (LogLevel
== CUPSD_LOG_DEBUG2
)
729 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
730 "cupsdProcessIPPRequest: ippLength(response)=%ld",
731 (long)ippLength(con
->response
));
733 if (cupsdSendHeader(con
, HTTP_OK
, "application/ipp", CUPSD_AUTH_NONE
))
735 #ifdef CUPSD_USE_CHUNKING
737 * Because older versions of CUPS (1.1.17 and older) and some IPP
738 * clients do not implement chunking properly, we cannot use
739 * chunking by default. This may become the default in future
740 * CUPS releases, or we might add a configuration directive for
744 if (con
->http
.version
== HTTP_1_1
)
746 if (httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n") < 0)
749 if (cupsdFlushHeader(con
) < 0)
752 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
755 #endif /* CUPSD_USE_CHUNKING */
757 size_t length
; /* Length of response */
760 length
= ippLength(con
->response
);
762 if (con
->file
>= 0 && !con
->pipe_pid
)
764 struct stat fileinfo
; /* File information */
767 if (!fstat(con
->file
, &fileinfo
))
768 length
+= fileinfo
.st_size
;
771 if (httpPrintf(HTTP(con
), "Content-Length: " CUPS_LLFMT
"\r\n\r\n",
772 CUPS_LLCAST length
) < 0)
775 if (cupsdFlushHeader(con
) < 0)
778 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
779 con
->http
.data_remaining
= length
;
781 if (con
->http
.data_remaining
<= INT_MAX
)
782 con
->http
._data_remaining
= con
->http
.data_remaining
;
784 con
->http
._data_remaining
= INT_MAX
;
787 cupsdAddSelect(con
->http
.fd
, (cupsd_selfunc_t
)cupsdReadClient
,
788 (cupsd_selfunc_t
)cupsdWriteClient
, con
);
791 * Tell the caller the response header was sent successfully...
799 * Tell the caller the response header could not be sent...
808 * Sending data from a subprocess like cups-deviced; tell the caller
809 * everything is A-OK so far...
818 * 'cupsdTimeoutJob()' - Timeout a job waiting on job files.
821 int /* O - 0 on success, -1 on error */
822 cupsdTimeoutJob(cupsd_job_t
*job
) /* I - Job to timeout */
824 cupsd_printer_t
*printer
; /* Destination printer or class */
825 ipp_attribute_t
*attr
; /* job-sheets attribute */
826 int kbytes
; /* Kilobytes in banner */
829 job
->pending_timeout
= 0;
832 * See if we need to add the ending sheet...
835 printer
= cupsdFindDest(job
->dest
);
836 attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_NAME
);
839 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
840 attr
&& attr
->num_values
> 1)
846 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Adding end banner page \"%s\".",
847 attr
->values
[1].string
.text
);
849 if ((kbytes
= copy_banner(NULL
, job
, attr
->values
[1].string
.text
)) < 0)
852 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
860 * 'accept_jobs()' - Accept print jobs to a printer.
864 accept_jobs(cupsd_client_t
*con
, /* I - Client connection */
865 ipp_attribute_t
*uri
) /* I - Printer or class URI */
867 http_status_t status
; /* Policy status */
868 cups_ptype_t dtype
; /* Destination type (printer/class) */
869 cupsd_printer_t
*printer
; /* Printer data */
872 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "accept_jobs(%p[%d], %s)", con
,
873 con
->http
.fd
, uri
->values
[0].string
.text
);
876 * Is the destination valid?
879 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
885 send_ipp_status(con
, IPP_NOT_FOUND
,
886 _("The printer or class was not found."));
894 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
896 send_http_error(con
, status
, printer
);
901 * Accept jobs sent to the printer...
904 printer
->accepting
= 1;
905 printer
->state_message
[0] = '\0';
907 cupsdAddPrinterHistory(printer
);
909 if (dtype
& CUPS_PRINTER_CLASS
)
911 cupsdMarkDirty(CUPSD_DIRTY_CLASSES
);
913 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" now accepting jobs (\"%s\").",
914 printer
->name
, get_username(con
));
918 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
);
920 cupsdLogMessage(CUPSD_LOG_INFO
,
921 "Printer \"%s\" now accepting jobs (\"%s\").",
922 printer
->name
, get_username(con
));
926 * Everything was ok, so return OK status...
929 con
->response
->request
.status
.status_code
= IPP_OK
;
934 * 'add_class()' - Add a class to the system.
938 add_class(cupsd_client_t
*con
, /* I - Client connection */
939 ipp_attribute_t
*uri
) /* I - URI of class */
941 http_status_t status
; /* Policy status */
942 int i
; /* Looping var */
943 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
944 username
[HTTP_MAX_URI
], /* Username portion of URI */
945 host
[HTTP_MAX_URI
], /* Host portion of URI */
946 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
947 int port
; /* Port portion of URI */
948 cupsd_printer_t
*pclass
, /* Class */
949 *member
; /* Member printer/class */
950 cups_ptype_t dtype
; /* Destination type */
951 ipp_attribute_t
*attr
; /* Printer attribute */
952 int modify
; /* Non-zero if we just modified */
953 char newname
[IPP_MAX_NAME
]; /* New class name */
954 int need_restart_job
; /* Need to restart job? */
957 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_class(%p[%d], %s)", con
,
958 con
->http
.fd
, uri
->values
[0].string
.text
);
961 * Do we have a valid URI?
964 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
965 sizeof(scheme
), username
, sizeof(username
), host
,
966 sizeof(host
), &port
, resource
, sizeof(resource
));
969 if (strncmp(resource
, "/classes/", 9) || strlen(resource
) == 9)
972 * No, return an error...
975 send_ipp_status(con
, IPP_BAD_REQUEST
,
976 _("The printer-uri must be of the form "
977 "\"ipp://HOSTNAME/classes/CLASSNAME\"."));
982 * Do we have a valid printer name?
985 if (!validate_name(resource
+ 9))
988 * No, return an error...
991 send_ipp_status(con
, IPP_BAD_REQUEST
,
992 _("The printer-uri \"%s\" contains invalid characters."),
993 uri
->values
[0].string
.text
);
998 * See if the class already exists; if not, create a new class...
1001 if ((pclass
= cupsdFindClass(resource
+ 9)) == NULL
)
1004 * Class doesn't exist; see if we have a printer of the same name...
1007 if ((pclass
= cupsdFindPrinter(resource
+ 9)) != NULL
&&
1008 !(pclass
->type
& CUPS_PRINTER_DISCOVERED
))
1011 * Yes, return an error...
1014 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
1015 _("A printer named \"%s\" already exists!"),
1021 * No, check the default policy and then add the class...
1024 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
1026 send_http_error(con
, status
, NULL
);
1030 pclass
= cupsdAddClass(resource
+ 9);
1033 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
1036 * Check the default policy, then rename the implicit class to "AnyClass"
1040 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
1042 send_http_error(con
, status
, NULL
);
1046 if (ImplicitAnyClasses
)
1048 snprintf(newname
, sizeof(newname
), "Any%s", resource
+ 9);
1049 cupsdRenamePrinter(pclass
, newname
);
1052 cupsdDeletePrinter(pclass
, 1);
1055 * Add the class as a new local class...
1058 pclass
= cupsdAddClass(resource
+ 9);
1061 else if (pclass
->type
& CUPS_PRINTER_DISCOVERED
)
1064 * Check the default policy, then rename the remote class to "Class"...
1067 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
1069 send_http_error(con
, status
, NULL
);
1073 snprintf(newname
, sizeof(newname
), "%s@%s", resource
+ 9, pclass
->hostname
);
1074 cupsdRenamePrinter(pclass
, newname
);
1077 * Add the class as a new local class...
1080 pclass
= cupsdAddClass(resource
+ 9);
1083 else if ((status
= cupsdCheckPolicy(pclass
->op_policy_ptr
, con
,
1086 send_http_error(con
, status
, pclass
);
1093 * Look for attributes and copy them over as needed...
1096 need_restart_job
= 0;
1098 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
1099 IPP_TAG_TEXT
)) != NULL
)
1100 cupsdSetString(&pclass
->location
, attr
->values
[0].string
.text
);
1102 if ((attr
= ippFindAttribute(con
->request
, "printer-info",
1103 IPP_TAG_TEXT
)) != NULL
)
1104 cupsdSetString(&pclass
->info
, attr
->values
[0].string
.text
);
1106 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs",
1107 IPP_TAG_BOOLEAN
)) != NULL
)
1109 cupsdLogMessage(CUPSD_LOG_INFO
,
1110 "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1111 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
1113 pclass
->accepting
= attr
->values
[0].boolean
;
1114 cupsdAddPrinterHistory(pclass
);
1117 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared",
1118 IPP_TAG_BOOLEAN
)) != NULL
)
1120 if (pclass
->shared
&& !attr
->values
[0].boolean
)
1121 cupsdDeregisterPrinter(pclass
, 1);
1123 cupsdLogMessage(CUPSD_LOG_INFO
,
1124 "Setting %s printer-is-shared to %d (was %d.)",
1125 pclass
->name
, attr
->values
[0].boolean
, pclass
->shared
);
1127 pclass
->shared
= attr
->values
[0].boolean
;
1130 if ((attr
= ippFindAttribute(con
->request
, "printer-state",
1131 IPP_TAG_ENUM
)) != NULL
)
1133 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1134 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
1136 send_ipp_status(con
, IPP_BAD_REQUEST
,
1137 _("Attempt to set %s printer-state to bad value %d!"),
1138 pclass
->name
, attr
->values
[0].integer
);
1142 cupsdLogMessage(CUPSD_LOG_INFO
, "Setting %s printer-state to %d (was %d.)",
1143 pclass
->name
, attr
->values
[0].integer
, pclass
->state
);
1145 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1146 cupsdStopPrinter(pclass
, 0);
1149 cupsdSetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1150 need_restart_job
= 1;
1153 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
1154 IPP_TAG_TEXT
)) != NULL
)
1156 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
1157 sizeof(pclass
->state_message
));
1158 cupsdAddPrinterHistory(pclass
);
1160 if ((attr
= ippFindAttribute(con
->request
, "member-uris",
1161 IPP_TAG_URI
)) != NULL
)
1164 * Clear the printer array as needed...
1167 need_restart_job
= 1;
1169 if (pclass
->num_printers
> 0)
1171 free(pclass
->printers
);
1172 pclass
->num_printers
= 0;
1176 * Add each printer or class that is listed...
1179 for (i
= 0; i
< attr
->num_values
; i
++)
1182 * Search for the printer or class URI...
1185 if (!cupsdValidateDest(attr
->values
[i
].string
.text
, &dtype
, &member
))
1191 send_ipp_status(con
, IPP_NOT_FOUND
,
1192 _("The printer or class was not found."));
1197 * Add it to the class...
1200 cupsdAddPrinterToClass(pclass
, member
);
1204 set_printer_defaults(con
, pclass
);
1206 if ((attr
= ippFindAttribute(con
->request
, "auth-info-required",
1207 IPP_TAG_KEYWORD
)) != NULL
)
1208 cupsdSetAuthInfoRequired(pclass
, NULL
, attr
);
1211 * Update the printer class attributes and return...
1214 cupsdSetPrinterAttrs(pclass
);
1215 cupsdMarkDirty(CUPSD_DIRTY_CLASSES
);
1217 if (need_restart_job
&& pclass
->job
)
1220 * Reset the current job to a "pending" status...
1223 cupsdSetJobState(pclass
->job
, IPP_JOB_PENDING
, CUPSD_JOB_FORCE
,
1224 "Job restarted because the class was modified.");
1227 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
);
1231 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1232 "Class \"%s\" modified by \"%s\".", pclass
->name
,
1235 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" modified by \"%s\".",
1236 pclass
->name
, get_username(con
));
1240 cupsdAddPrinterHistory(pclass
);
1242 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1243 "New class \"%s\" added by \"%s\".", pclass
->name
,
1246 cupsdLogMessage(CUPSD_LOG_INFO
, "New class \"%s\" added by \"%s\".",
1247 pclass
->name
, get_username(con
));
1250 con
->response
->request
.status
.status_code
= IPP_OK
;
1255 * 'add_file()' - Add a file to a job.
1258 static int /* O - 0 on success, -1 on error */
1259 add_file(cupsd_client_t
*con
, /* I - Connection to client */
1260 cupsd_job_t
*job
, /* I - Job to add to */
1261 mime_type_t
*filetype
, /* I - Type of file */
1262 int compression
) /* I - Compression */
1264 mime_type_t
**filetypes
; /* New filetypes array... */
1265 int *compressions
; /* New compressions array... */
1268 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
1269 "add_file(con=%p[%d], job=%d, filetype=%s/%s, "
1270 "compression=%d)", con
, con
? con
->http
.fd
: -1, job
->id
,
1271 filetype
->super
, filetype
->type
, compression
);
1274 * Add the file to the job...
1277 if (job
->num_files
== 0)
1279 compressions
= (int *)malloc(sizeof(int));
1280 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1284 compressions
= (int *)realloc(job
->compressions
,
1285 (job
->num_files
+ 1) * sizeof(int));
1286 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1287 (job
->num_files
+ 1) *
1288 sizeof(mime_type_t
*));
1291 if (!compressions
|| !filetypes
)
1293 cupsdSetJobState(job
, IPP_JOB_ABORTED
, CUPSD_JOB_PURGE
,
1294 "Job aborted because the scheduler ran out of memory.");
1297 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
1298 _("Unable to allocate memory for file types!"));
1303 job
->compressions
= compressions
;
1304 job
->compressions
[job
->num_files
] = compression
;
1305 job
->filetypes
= filetypes
;
1306 job
->filetypes
[job
->num_files
] = filetype
;
1311 cupsdMarkDirty(CUPSD_DIRTY_JOBS
);
1318 * 'add_job()' - Add a job to a print queue.
1321 static cupsd_job_t
* /* O - Job object */
1322 add_job(cupsd_client_t
*con
, /* I - Client connection */
1323 cupsd_printer_t
*printer
, /* I - Destination printer */
1324 mime_type_t
*filetype
) /* I - First print file type, if any */
1326 http_status_t status
; /* Policy status */
1327 ipp_attribute_t
*attr
, /* Current attribute */
1328 *auth_info
; /* auth-info attribute */
1329 const char *val
; /* Default option value */
1330 int priority
; /* Job priority */
1331 char *title
; /* Job name/title */
1332 cupsd_job_t
*job
; /* Current job */
1333 char job_uri
[HTTP_MAX_URI
]; /* Job URI */
1334 int kbytes
; /* Size of print file */
1335 int i
; /* Looping var */
1336 int lowerpagerange
; /* Page range bound */
1339 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_job(%p[%d], %p(%s), %p(%s/%s))",
1340 con
, con
->http
.fd
, printer
, printer
->name
,
1341 filetype
, filetype
? filetype
->super
: "none",
1342 filetype
? filetype
->type
: "none");
1345 * Check remote printing to non-shared printer...
1348 if (!printer
->shared
&&
1349 strcasecmp(con
->http
.hostname
, "localhost") &&
1350 strcasecmp(con
->http
.hostname
, ServerName
))
1352 send_ipp_status(con
, IPP_NOT_AUTHORIZED
,
1353 _("The printer or class is not shared!"));
1361 auth_info
= ippFindAttribute(con
->request
, "auth-info", IPP_TAG_TEXT
);
1363 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
1365 send_http_error(con
, status
, printer
);
1368 else if (printer
->num_auth_info_required
> 0 &&
1369 strcmp(printer
->auth_info_required
[0], "none") &&
1370 !con
->username
[0] && !auth_info
)
1372 send_http_error(con
, HTTP_UNAUTHORIZED
, printer
);
1376 else if (auth_info
&& !con
->http
.tls
&&
1377 !httpAddrLocalhost(con
->http
.hostaddr
))
1380 * Require encryption of auth-info over non-local connections...
1383 send_http_error(con
, HTTP_UPGRADE_REQUIRED
, printer
);
1386 #endif /* HAVE_SSL */
1389 * See if the printer is accepting jobs...
1392 if (!printer
->accepting
)
1394 send_ipp_status(con
, IPP_NOT_ACCEPTING
,
1395 _("Destination \"%s\" is not accepting jobs."),
1401 * Validate job template attributes; for now just document-format,
1402 * copies, number-up, and page-ranges...
1405 if (filetype
&& printer
->filetypes
&&
1406 !cupsArrayFind(printer
->filetypes
, filetype
))
1408 char mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
1409 /* MIME media type string */
1412 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
1415 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
1416 _("Unsupported format \'%s\'!"), mimetype
);
1418 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
1419 "document-format", NULL
, mimetype
);
1424 if ((attr
= ippFindAttribute(con
->request
, "copies",
1425 IPP_TAG_INTEGER
)) != NULL
)
1427 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
1429 send_ipp_status(con
, IPP_ATTRIBUTES
, _("Bad copies value %d."),
1430 attr
->values
[0].integer
);
1431 ippAddInteger(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_INTEGER
,
1432 "copies", attr
->values
[0].integer
);
1437 if ((attr
= ippFindAttribute(con
->request
, "job-sheets",
1438 IPP_TAG_ZERO
)) != NULL
)
1440 if (attr
->value_tag
!= IPP_TAG_KEYWORD
&&
1441 attr
->value_tag
!= IPP_TAG_NAME
)
1443 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad job-sheets value type!"));
1447 if (attr
->num_values
> 2)
1449 send_ipp_status(con
, IPP_BAD_REQUEST
,
1450 _("Too many job-sheets values (%d > 2)!"),
1455 for (i
= 0; i
< attr
->num_values
; i
++)
1456 if (strcmp(attr
->values
[i
].string
.text
, "none") &&
1457 !cupsdFindBanner(attr
->values
[i
].string
.text
))
1459 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad job-sheets value \"%s\"!"),
1460 attr
->values
[i
].string
.text
);
1465 if ((attr
= ippFindAttribute(con
->request
, "number-up",
1466 IPP_TAG_INTEGER
)) != NULL
)
1468 if (attr
->values
[0].integer
!= 1 &&
1469 attr
->values
[0].integer
!= 2 &&
1470 attr
->values
[0].integer
!= 4 &&
1471 attr
->values
[0].integer
!= 6 &&
1472 attr
->values
[0].integer
!= 9 &&
1473 attr
->values
[0].integer
!= 16)
1475 send_ipp_status(con
, IPP_ATTRIBUTES
, _("Bad number-up value %d."),
1476 attr
->values
[0].integer
);
1477 ippAddInteger(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_INTEGER
,
1478 "number-up", attr
->values
[0].integer
);
1483 if ((attr
= ippFindAttribute(con
->request
, "page-ranges",
1484 IPP_TAG_RANGE
)) != NULL
)
1486 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
1488 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
1489 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
1491 send_ipp_status(con
, IPP_BAD_REQUEST
,
1492 _("Bad page-ranges values %d-%d."),
1493 attr
->values
[i
].range
.lower
,
1494 attr
->values
[i
].range
.upper
);
1498 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
1503 * Make sure we aren't over our limit...
1506 if (MaxJobs
&& cupsArrayCount(Jobs
) >= MaxJobs
)
1509 if (MaxJobs
&& cupsArrayCount(Jobs
) >= MaxJobs
)
1511 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
1512 _("Too many active jobs."));
1516 if ((i
= check_quotas(con
, printer
)) < 0)
1518 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Quota limit reached."));
1523 send_ipp_status(con
, IPP_NOT_AUTHORIZED
, _("Not allowed to print."));
1528 * Create the job and set things up...
1531 if ((attr
= ippFindAttribute(con
->request
, "job-priority",
1532 IPP_TAG_INTEGER
)) != NULL
)
1533 priority
= attr
->values
[0].integer
;
1536 if ((val
= cupsGetOption("job-priority", printer
->num_options
,
1537 printer
->options
)) != NULL
)
1538 priority
= atoi(val
);
1542 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
1546 if ((attr
= ippFindAttribute(con
->request
, "job-name",
1547 IPP_TAG_NAME
)) != NULL
)
1548 title
= attr
->values
[0].string
.text
;
1550 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
1551 title
= "Untitled");
1553 if ((job
= cupsdAddJob(priority
, printer
->name
)) == NULL
)
1555 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
1556 _("Unable to add job for destination \"%s\"!"),
1561 job
->dtype
= printer
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
|
1562 CUPS_PRINTER_REMOTE
);
1563 job
->attrs
= con
->request
;
1565 con
->request
= ippNewRequest(job
->attrs
->request
.op
.operation_id
);
1567 cupsdMarkDirty(CUPSD_DIRTY_JOBS
);
1569 add_job_uuid(con
, job
);
1570 apply_printer_defaults(printer
, job
);
1572 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
1574 if (con
->username
[0])
1576 cupsdSetString(&job
->username
, con
->username
);
1579 cupsdSetString(&attr
->values
[0].string
.text
, con
->username
);
1583 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1584 "add_job: requesting-user-name=\"%s\"",
1585 attr
->values
[0].string
.text
);
1587 cupsdSetString(&job
->username
, attr
->values
[0].string
.text
);
1590 cupsdSetString(&job
->username
, "anonymous");
1593 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
1594 "job-originating-user-name", NULL
, job
->username
);
1597 attr
->group_tag
= IPP_TAG_JOB
;
1598 _cupsStrFree(attr
->name
);
1599 attr
->name
= _cupsStrAlloc("job-originating-user-name");
1602 if (con
->username
[0] || auth_info
)
1604 save_auth_info(con
, job
, auth_info
);
1607 * Remove the auth-info attribute from the attribute data...
1611 ippDeleteAttribute(job
->attrs
, auth_info
);
1614 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
1615 IPP_TAG_ZERO
)) != NULL
)
1618 * Request contains a job-originating-host-name attribute; validate it...
1621 if (attr
->value_tag
!= IPP_TAG_NAME
||
1622 attr
->num_values
!= 1 ||
1623 strcmp(con
->http
.hostname
, "localhost"))
1626 * Can't override the value if we aren't connected via localhost.
1627 * Also, we can only have 1 value and it must be a name value.
1630 switch (attr
->value_tag
)
1632 case IPP_TAG_STRING
:
1633 case IPP_TAG_TEXTLANG
:
1634 case IPP_TAG_NAMELANG
:
1637 case IPP_TAG_KEYWORD
:
1639 case IPP_TAG_URISCHEME
:
1640 case IPP_TAG_CHARSET
:
1641 case IPP_TAG_LANGUAGE
:
1642 case IPP_TAG_MIMETYPE
:
1644 * Free old strings...
1647 for (i
= 0; i
< attr
->num_values
; i
++)
1649 _cupsStrFree(attr
->values
[i
].string
.text
);
1650 attr
->values
[i
].string
.text
= NULL
;
1651 if (attr
->values
[i
].string
.charset
)
1653 _cupsStrFree(attr
->values
[i
].string
.charset
);
1654 attr
->values
[i
].string
.charset
= NULL
;
1663 * Use the default connection hostname instead...
1666 attr
->value_tag
= IPP_TAG_NAME
;
1667 attr
->num_values
= 1;
1668 attr
->values
[0].string
.text
= _cupsStrAlloc(con
->http
.hostname
);
1671 attr
->group_tag
= IPP_TAG_JOB
;
1676 * No job-originating-host-name attribute, so use the hostname from
1680 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
1681 "job-originating-host-name", NULL
, con
->http
.hostname
);
1684 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
1686 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1687 "time-at-processing", 0);
1688 attr
->value_tag
= IPP_TAG_NOVALUE
;
1689 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1690 "time-at-completed", 0);
1691 attr
->value_tag
= IPP_TAG_NOVALUE
;
1694 * Add remaining job attributes...
1697 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
1698 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
1699 "job-state", IPP_JOB_STOPPED
);
1700 job
->state_value
= (ipp_jstate_t
)job
->state
->values
[0].integer
;
1701 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1702 "job-media-sheets-completed", 0);
1703 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
1705 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
1708 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
1709 IPP_TAG_INTEGER
)) != NULL
)
1710 attr
->values
[0].integer
= 0;
1712 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-k-octets", 0);
1714 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
1715 IPP_TAG_KEYWORD
)) == NULL
)
1716 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
1719 if ((val
= cupsGetOption("job-hold-until", printer
->num_options
,
1720 printer
->options
)) == NULL
)
1723 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1724 "job-hold-until", NULL
, val
);
1726 if (attr
&& strcmp(attr
->values
[0].string
.text
, "no-hold") &&
1727 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1730 * Hold job until specified time...
1733 cupsdSetJobHoldUntil(job
, attr
->values
[0].string
.text
, 0);
1735 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
1736 job
->state_value
= IPP_JOB_HELD
;
1738 else if (job
->attrs
->request
.op
.operation_id
== IPP_CREATE_JOB
)
1740 job
->hold_until
= time(NULL
) + MultipleOperationTimeout
;
1741 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
1742 job
->state_value
= IPP_JOB_HELD
;
1746 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1747 job
->state_value
= IPP_JOB_PENDING
;
1750 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
1754 * Add job sheets options...
1757 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets",
1758 IPP_TAG_ZERO
)) == NULL
)
1760 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1761 "Adding default job-sheets values \"%s,%s\"...",
1762 printer
->job_sheets
[0], printer
->job_sheets
[1]);
1764 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
1766 attr
->values
[0].string
.text
= _cupsStrRetain(printer
->job_sheets
[0]);
1767 attr
->values
[1].string
.text
= _cupsStrRetain(printer
->job_sheets
[1]);
1770 job
->job_sheets
= attr
;
1773 * Enforce classification level if set...
1778 cupsdLogMessage(CUPSD_LOG_INFO
,
1779 "Classification=\"%s\", ClassifyOverride=%d",
1780 Classification
? Classification
: "(null)",
1783 if (ClassifyOverride
)
1785 if (!strcmp(attr
->values
[0].string
.text
, "none") &&
1786 (attr
->num_values
== 1 ||
1787 !strcmp(attr
->values
[1].string
.text
, "none")))
1790 * Force the leading banner to have the classification on it...
1793 cupsdSetString(&attr
->values
[0].string
.text
, Classification
);
1795 cupsdLogJob(job
, CUPSD_LOG_NOTICE
, "CLASSIFICATION FORCED "
1796 "job-sheets=\"%s,none\", "
1797 "job-originating-user-name=\"%s\"",
1798 Classification
, job
->username
);
1800 else if (attr
->num_values
== 2 &&
1801 strcmp(attr
->values
[0].string
.text
,
1802 attr
->values
[1].string
.text
) &&
1803 strcmp(attr
->values
[0].string
.text
, "none") &&
1804 strcmp(attr
->values
[1].string
.text
, "none"))
1807 * Can't put two different security markings on the same document!
1810 cupsdSetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
1812 cupsdLogJob(job
, CUPSD_LOG_NOTICE
, "CLASSIFICATION FORCED "
1813 "job-sheets=\"%s,%s\", "
1814 "job-originating-user-name=\"%s\"",
1815 attr
->values
[0].string
.text
,
1816 attr
->values
[1].string
.text
, job
->username
);
1818 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
1819 strcmp(attr
->values
[0].string
.text
, "none") &&
1820 (attr
->num_values
== 1 ||
1821 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
1822 strcmp(attr
->values
[1].string
.text
, "none"))))
1824 if (attr
->num_values
== 1)
1825 cupsdLogJob(job
, CUPSD_LOG_NOTICE
,
1826 "CLASSIFICATION OVERRIDDEN "
1827 "job-sheets=\"%s\", "
1828 "job-originating-user-name=\"%s\"",
1829 attr
->values
[0].string
.text
, job
->username
);
1831 cupsdLogJob(job
, CUPSD_LOG_NOTICE
,
1832 "CLASSIFICATION OVERRIDDEN "
1833 "job-sheets=\"%s,%s\",fffff "
1834 "job-originating-user-name=\"%s\"",
1835 attr
->values
[0].string
.text
,
1836 attr
->values
[1].string
.text
, job
->username
);
1839 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
1840 (attr
->num_values
== 1 ||
1841 strcmp(attr
->values
[1].string
.text
, Classification
)))
1844 * Force the banner to have the classification on it...
1847 if (attr
->num_values
> 1 &&
1848 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
1850 cupsdSetString(&(attr
->values
[0].string
.text
), Classification
);
1851 cupsdSetString(&(attr
->values
[1].string
.text
), Classification
);
1855 if (attr
->num_values
== 1 ||
1856 strcmp(attr
->values
[0].string
.text
, "none"))
1857 cupsdSetString(&(attr
->values
[0].string
.text
), Classification
);
1859 if (attr
->num_values
> 1 &&
1860 strcmp(attr
->values
[1].string
.text
, "none"))
1861 cupsdSetString(&(attr
->values
[1].string
.text
), Classification
);
1864 if (attr
->num_values
> 1)
1865 cupsdLogJob(job
, CUPSD_LOG_NOTICE
,
1866 "CLASSIFICATION FORCED "
1867 "job-sheets=\"%s,%s\", "
1868 "job-originating-user-name=\"%s\"",
1869 attr
->values
[0].string
.text
,
1870 attr
->values
[1].string
.text
, job
->username
);
1872 cupsdLogJob(job
, CUPSD_LOG_NOTICE
,
1873 "CLASSIFICATION FORCED "
1874 "job-sheets=\"%s\", "
1875 "job-originating-user-name=\"%s\"",
1876 Classification
, job
->username
);
1881 * See if we need to add the starting sheet...
1884 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
1886 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Adding start banner page \"%s\".",
1887 attr
->values
[0].string
.text
);
1889 if ((kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
)) < 0)
1891 cupsdSetJobState(job
, IPP_JOB_ABORTED
, CUPSD_JOB_PURGE
,
1892 "Aborting job because the start banner could not be "
1897 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
1900 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets",
1901 IPP_TAG_ZERO
)) != NULL
)
1905 * Fill in the response info...
1908 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
1909 LocalPort
, job
->id
);
1911 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
1914 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
1916 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
1918 add_job_state_reasons(con
, job
);
1920 con
->response
->request
.status
.status_code
= IPP_OK
;
1923 * Add any job subscriptions...
1926 add_job_subscriptions(con
, job
);
1929 * Set all but the first two attributes to the job attributes group...
1932 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
1933 attr
->group_tag
= IPP_TAG_JOB
;
1936 * Fire the "job created" event...
1939 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
1942 * Return the new job...
1950 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1951 * upon the job and printer state...
1955 add_job_state_reasons(
1956 cupsd_client_t
*con
, /* I - Client connection */
1957 cupsd_job_t
*job
) /* I - Job info */
1959 cupsd_printer_t
*dest
; /* Destination printer */
1962 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_job_state_reasons(%p[%d], %d)",
1963 con
, con
->http
.fd
, job
? job
->id
: 0);
1965 switch (job
? job
->state_value
: IPP_JOB_CANCELED
)
1967 case IPP_JOB_PENDING
:
1968 dest
= cupsdFindDest(job
->dest
);
1970 if (dest
&& dest
->state
== IPP_PRINTER_STOPPED
)
1971 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1972 "job-state-reasons", NULL
, "printer-stopped");
1974 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1975 "job-state-reasons", NULL
, "none");
1979 if (ippFindAttribute(job
->attrs
, "job-hold-until",
1980 IPP_TAG_KEYWORD
) != NULL
||
1981 ippFindAttribute(job
->attrs
, "job-hold-until",
1982 IPP_TAG_NAME
) != NULL
)
1983 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1984 "job-state-reasons", NULL
, "job-hold-until-specified");
1986 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1987 "job-state-reasons", NULL
, "job-incoming");
1990 case IPP_JOB_PROCESSING
:
1991 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1992 "job-state-reasons", NULL
, "job-printing");
1995 case IPP_JOB_STOPPED
:
1996 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1997 "job-state-reasons", NULL
, "job-stopped");
2000 case IPP_JOB_CANCELED
:
2001 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
2002 "job-state-reasons", NULL
, "job-canceled-by-user");
2005 case IPP_JOB_ABORTED
:
2006 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
2007 "job-state-reasons", NULL
, "aborted-by-system");
2010 case IPP_JOB_COMPLETED
:
2011 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
2012 "job-state-reasons", NULL
, "job-completed-successfully");
2019 * 'add_job_subscriptions()' - Add any subscriptions for a job.
2023 add_job_subscriptions(
2024 cupsd_client_t
*con
, /* I - Client connection */
2025 cupsd_job_t
*job
) /* I - Newly created job */
2027 int i
; /* Looping var */
2028 ipp_attribute_t
*prev
, /* Previous attribute */
2029 *next
, /* Next attribute */
2030 *attr
; /* Current attribute */
2031 cupsd_subscription_t
*sub
; /* Subscription object */
2032 const char *recipient
, /* notify-recipient-uri */
2033 *pullmethod
; /* notify-pull-method */
2034 ipp_attribute_t
*user_data
; /* notify-user-data */
2035 int interval
; /* notify-time-interval */
2036 unsigned mask
; /* notify-events */
2040 * Find the first subscription group attribute; return if we have
2044 for (attr
= job
->attrs
->attrs
; attr
; attr
= attr
->next
)
2045 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
2052 * Process the subscription attributes in the request...
2061 mask
= CUPSD_EVENT_NONE
;
2063 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
2065 if (!strcmp(attr
->name
, "notify-recipient-uri") &&
2066 attr
->value_tag
== IPP_TAG_URI
)
2069 * Validate the recipient scheme against the ServerBin/notifier
2073 char notifier
[1024], /* Notifier filename */
2074 scheme
[HTTP_MAX_URI
], /* Scheme portion of URI */
2075 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
2076 host
[HTTP_MAX_URI
], /* Host portion of URI */
2077 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2078 int port
; /* Port portion of URI */
2081 recipient
= attr
->values
[0].string
.text
;
2083 if (httpSeparateURI(HTTP_URI_CODING_ALL
, recipient
,
2084 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
2085 host
, sizeof(host
), &port
,
2086 resource
, sizeof(resource
)) < HTTP_URI_OK
)
2088 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2089 _("Bad notify-recipient-uri URI \"%s\"!"), recipient
);
2090 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
2091 "notify-status-code", IPP_URI_SCHEME
);
2095 snprintf(notifier
, sizeof(notifier
), "%s/notifier/%s", ServerBin
,
2097 if (access(notifier
, X_OK
))
2099 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2100 _("notify-recipient-uri URI \"%s\" uses unknown "
2101 "scheme!"), recipient
);
2102 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
2103 "notify-status-code", IPP_URI_SCHEME
);
2107 if (!strcmp(scheme
, "rss") && !check_rss_recipient(recipient
))
2109 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2110 _("notify-recipient-uri URI \"%s\" is already used!"),
2112 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
2113 "notify-status-code", IPP_ATTRIBUTES
);
2117 else if (!strcmp(attr
->name
, "notify-pull-method") &&
2118 attr
->value_tag
== IPP_TAG_KEYWORD
)
2120 pullmethod
= attr
->values
[0].string
.text
;
2122 if (strcmp(pullmethod
, "ippget"))
2124 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2125 _("Bad notify-pull-method \"%s\"!"), pullmethod
);
2126 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
2127 "notify-status-code", IPP_ATTRIBUTES
);
2131 else if (!strcmp(attr
->name
, "notify-charset") &&
2132 attr
->value_tag
== IPP_TAG_CHARSET
&&
2133 strcmp(attr
->values
[0].string
.text
, "us-ascii") &&
2134 strcmp(attr
->values
[0].string
.text
, "utf-8"))
2136 send_ipp_status(con
, IPP_CHARSET
,
2137 _("Character set \"%s\" not supported!"),
2138 attr
->values
[0].string
.text
);
2141 else if (!strcmp(attr
->name
, "notify-natural-language") &&
2142 (attr
->value_tag
!= IPP_TAG_LANGUAGE
||
2143 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
)))
2145 send_ipp_status(con
, IPP_CHARSET
,
2146 _("Language \"%s\" not supported!"),
2147 attr
->values
[0].string
.text
);
2150 else if (!strcmp(attr
->name
, "notify-user-data") &&
2151 attr
->value_tag
== IPP_TAG_STRING
)
2153 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
2155 send_ipp_status(con
, IPP_REQUEST_VALUE
,
2156 _("The notify-user-data value is too large "
2157 "(%d > 63 octets)!"),
2158 attr
->values
[0].unknown
.length
);
2164 else if (!strcmp(attr
->name
, "notify-events") &&
2165 attr
->value_tag
== IPP_TAG_KEYWORD
)
2167 for (i
= 0; i
< attr
->num_values
; i
++)
2168 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
2170 else if (!strcmp(attr
->name
, "notify-lease-duration"))
2172 send_ipp_status(con
, IPP_BAD_REQUEST
,
2173 _("The notify-lease-duration attribute cannot be "
2174 "used with job subscriptions."));
2177 else if (!strcmp(attr
->name
, "notify-time-interval") &&
2178 attr
->value_tag
== IPP_TAG_INTEGER
)
2179 interval
= attr
->values
[0].integer
;
2184 if (!recipient
&& !pullmethod
)
2187 if (mask
== CUPSD_EVENT_NONE
)
2188 mask
= CUPSD_EVENT_JOB_COMPLETED
;
2190 if ((sub
= cupsdAddSubscription(mask
, cupsdFindDest(job
->dest
), job
,
2191 recipient
, 0)) != NULL
)
2193 sub
->interval
= interval
;
2195 cupsdSetString(&sub
->owner
, job
->username
);
2199 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
2200 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
2201 sub
->user_data_len
);
2204 ippAddSeparator(con
->response
);
2205 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
2206 "notify-subscription-id", sub
->id
);
2213 cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS
);
2216 * Remove all of the subscription attributes from the job request...
2218 * TODO: Optimize this since subscription groups have to come at the
2219 * end of the request...
2222 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
2226 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
2227 attr
->group_tag
== IPP_TAG_ZERO
)
2230 * Free and remove this attribute...
2238 job
->attrs
->attrs
= next
;
2244 job
->attrs
->last
= prev
;
2245 job
->attrs
->current
= prev
;
2250 * 'add_job_uuid()' - Add job-uuid attribute to a job.
2252 * See RFC 4122 for the definition of UUIDs and the format.
2256 add_job_uuid(cupsd_client_t
*con
, /* I - Client connection */
2257 cupsd_job_t
*job
) /* I - Job */
2259 char uuid
[1024]; /* job-uuid string */
2260 _cups_md5_state_t md5state
; /* MD5 state */
2261 unsigned char md5sum
[16]; /* MD5 digest/sum */
2265 * First see if the job already has a job-uuid attribute; if so, return...
2268 if (ippFindAttribute(job
->attrs
, "job-uuid", IPP_TAG_URI
))
2272 * No job-uuid attribute, so build a version 3 UUID with the local job
2273 * ID at the end; see RFC 4122 for details. Start with the MD5 sum of
2274 * the ServerName, server name and port that the client connected to,
2275 * and local job ID...
2278 snprintf(uuid
, sizeof(uuid
), "%s:%s:%d:%d", ServerName
, con
->servername
,
2279 con
->serverport
, job
->id
);
2281 _cupsMD5Init(&md5state
);
2282 _cupsMD5Append(&md5state
, (unsigned char *)uuid
, strlen(uuid
));
2283 _cupsMD5Finish(&md5state
, md5sum
);
2286 * Format the UUID URI using the MD5 sum and job ID.
2289 snprintf(uuid
, sizeof(uuid
),
2290 "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
2291 "%02x%02x%02x%02x%02x%02x",
2292 md5sum
[0], md5sum
[1], md5sum
[2], md5sum
[3], md5sum
[4], md5sum
[5],
2293 (md5sum
[6] & 15) | 0x30, md5sum
[7], (md5sum
[8] & 0x3f) | 0x40,
2294 md5sum
[9], md5sum
[10], md5sum
[11], md5sum
[12], md5sum
[13],
2295 md5sum
[14], md5sum
[15]);
2297 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uuid", NULL
, uuid
);
2302 * 'add_printer()' - Add a printer to the system.
2306 add_printer(cupsd_client_t
*con
, /* I - Client connection */
2307 ipp_attribute_t
*uri
) /* I - URI of printer */
2309 http_status_t status
; /* Policy status */
2310 int i
; /* Looping var */
2311 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
2312 username
[HTTP_MAX_URI
], /* Username portion of URI */
2313 host
[HTTP_MAX_URI
], /* Host portion of URI */
2314 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2315 int port
; /* Port portion of URI */
2316 cupsd_printer_t
*printer
; /* Printer/class */
2317 ipp_attribute_t
*attr
; /* Printer attribute */
2318 cups_file_t
*fp
; /* Script/PPD file */
2319 char line
[1024]; /* Line from file... */
2320 char srcfile
[1024], /* Source Script/PPD file */
2321 dstfile
[1024]; /* Destination Script/PPD file */
2322 int modify
; /* Non-zero if we are modifying */
2323 char newname
[IPP_MAX_NAME
]; /* New printer name */
2324 int need_restart_job
; /* Need to restart job? */
2325 int set_device_uri
, /* Did we set the device URI? */
2326 set_port_monitor
; /* Did we set the port monitor? */
2329 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_printer(%p[%d], %s)", con
,
2330 con
->http
.fd
, uri
->values
[0].string
.text
);
2333 * Do we have a valid URI?
2336 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
2337 sizeof(scheme
), username
, sizeof(username
), host
,
2338 sizeof(host
), &port
, resource
, sizeof(resource
));
2340 if (strncmp(resource
, "/printers/", 10) || strlen(resource
) == 10)
2343 * No, return an error...
2346 send_ipp_status(con
, IPP_BAD_REQUEST
,
2347 _("The printer-uri must be of the form "
2348 "\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
2353 * Do we have a valid printer name?
2356 if (!validate_name(resource
+ 10))
2359 * No, return an error...
2362 send_ipp_status(con
, IPP_BAD_REQUEST
,
2363 _("The printer-uri \"%s\" contains invalid characters."),
2364 uri
->values
[0].string
.text
);
2369 * See if the printer already exists; if not, create a new printer...
2372 if ((printer
= cupsdFindPrinter(resource
+ 10)) == NULL
)
2375 * Printer doesn't exist; see if we have a class of the same name...
2378 if ((printer
= cupsdFindClass(resource
+ 10)) != NULL
&&
2379 !(printer
->type
& CUPS_PRINTER_DISCOVERED
))
2382 * Yes, return an error...
2385 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2386 _("A class named \"%s\" already exists!"),
2392 * No, check the default policy then add the printer...
2395 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
2397 send_http_error(con
, status
, NULL
);
2401 printer
= cupsdAddPrinter(resource
+ 10);
2404 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
2407 * Check the default policy, then rename the implicit printer to
2408 * "AnyPrinter" or delete it...
2411 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
2413 send_http_error(con
, status
, NULL
);
2417 if (ImplicitAnyClasses
)
2419 snprintf(newname
, sizeof(newname
), "Any%s", resource
+ 10);
2420 cupsdRenamePrinter(printer
, newname
);
2423 cupsdDeletePrinter(printer
, 1);
2426 * Add the printer as a new local printer...
2429 printer
= cupsdAddPrinter(resource
+ 10);
2432 else if (printer
->type
& CUPS_PRINTER_DISCOVERED
)
2435 * Check the default policy, then rename the remote printer to
2436 * "Printer@server"...
2439 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
2441 send_http_error(con
, status
, NULL
);
2445 snprintf(newname
, sizeof(newname
), "%s@%s", resource
+ 10,
2447 cupsdRenamePrinter(printer
, newname
);
2450 * Add the printer as a new local printer...
2453 printer
= cupsdAddPrinter(resource
+ 10);
2456 else if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
,
2459 send_http_error(con
, status
, printer
);
2466 * Look for attributes and copy them over as needed...
2469 need_restart_job
= 0;
2471 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
2472 IPP_TAG_TEXT
)) != NULL
)
2473 cupsdSetString(&printer
->location
, attr
->values
[0].string
.text
);
2475 if ((attr
= ippFindAttribute(con
->request
, "printer-info",
2476 IPP_TAG_TEXT
)) != NULL
)
2477 cupsdSetString(&printer
->info
, attr
->values
[0].string
.text
);
2481 if ((attr
= ippFindAttribute(con
->request
, "device-uri",
2482 IPP_TAG_URI
)) != NULL
)
2485 * Do we have a valid device URI?
2488 http_uri_status_t uri_status
; /* URI separation status */
2489 char old_device_uri
[1024];
2490 /* Old device URI */
2493 need_restart_job
= 1;
2495 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
2496 attr
->values
[0].string
.text
,
2497 scheme
, sizeof(scheme
),
2498 username
, sizeof(username
),
2499 host
, sizeof(host
), &port
,
2500 resource
, sizeof(resource
));
2502 if (uri_status
< HTTP_URI_OK
)
2504 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Bad device-uri \"%s\"!"),
2505 attr
->values
[0].string
.text
);
2506 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2507 "add_printer: httpSeparateURI returned %d", uri_status
);
2511 if (!strcmp(scheme
, "file"))
2514 * See if the administrator has enabled file devices...
2517 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
2520 * File devices are disabled and the URL is not file:/dev/null...
2523 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2524 _("File device URIs have been disabled! "
2525 "To enable, see the FileDevice directive in "
2526 "\"%s/cupsd.conf\"."),
2534 * See if the backend exists and is executable...
2537 snprintf(srcfile
, sizeof(srcfile
), "%s/backend/%s", ServerBin
, scheme
);
2538 if (access(srcfile
, X_OK
))
2541 * Could not find device in list!
2544 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Bad device-uri scheme \"%s\"!"),
2550 if (printer
->sanitized_device_uri
)
2551 strlcpy(old_device_uri
, printer
->sanitized_device_uri
,
2552 sizeof(old_device_uri
));
2554 old_device_uri
[0] = '\0';
2556 cupsdSetDeviceURI(printer
, attr
->values
[0].string
.text
);
2558 cupsdLogMessage(CUPSD_LOG_INFO
,
2559 "Setting %s device-uri to \"%s\" (was \"%s\".)",
2560 printer
->name
, printer
->sanitized_device_uri
,
2566 set_port_monitor
= 0;
2568 if ((attr
= ippFindAttribute(con
->request
, "port-monitor",
2569 IPP_TAG_NAME
)) != NULL
)
2571 ipp_attribute_t
*supported
; /* port-monitor-supported attribute */
2574 need_restart_job
= 1;
2576 supported
= ippFindAttribute(printer
->ppd_attrs
, "port-monitor-supported",
2580 for (i
= 0; i
< supported
->num_values
; i
++)
2581 if (!strcmp(supported
->values
[i
].string
.text
,
2582 attr
->values
[0].string
.text
))
2586 if (!supported
|| i
>= supported
->num_values
)
2588 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Bad port-monitor \"%s\"!"),
2589 attr
->values
[0].string
.text
);
2593 cupsdLogMessage(CUPSD_LOG_INFO
,
2594 "Setting %s port-monitor to \"%s\" (was \"%s\".)",
2595 printer
->name
, attr
->values
[0].string
.text
,
2596 printer
->port_monitor
? printer
->port_monitor
: "none");
2598 if (strcmp(attr
->values
[0].string
.text
, "none"))
2599 cupsdSetString(&printer
->port_monitor
, attr
->values
[0].string
.text
);
2601 cupsdClearString(&printer
->port_monitor
);
2603 set_port_monitor
= 1;
2606 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs",
2607 IPP_TAG_BOOLEAN
)) != NULL
)
2609 cupsdLogMessage(CUPSD_LOG_INFO
,
2610 "Setting %s printer-is-accepting-jobs to %d (was %d.)",
2611 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
2613 printer
->accepting
= attr
->values
[0].boolean
;
2614 cupsdAddPrinterHistory(printer
);
2617 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared",
2618 IPP_TAG_BOOLEAN
)) != NULL
)
2620 if (printer
->shared
&& !attr
->values
[0].boolean
)
2621 cupsdDeregisterPrinter(printer
, 1);
2623 cupsdLogMessage(CUPSD_LOG_INFO
,
2624 "Setting %s printer-is-shared to %d (was %d.)",
2625 printer
->name
, attr
->values
[0].boolean
, printer
->shared
);
2627 printer
->shared
= attr
->values
[0].boolean
;
2630 if ((attr
= ippFindAttribute(con
->request
, "printer-state",
2631 IPP_TAG_ENUM
)) != NULL
)
2633 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
2634 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
2636 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad printer-state value %d!"),
2637 attr
->values
[0].integer
);
2641 cupsdLogMessage(CUPSD_LOG_INFO
, "Setting %s printer-state to %d (was %d.)",
2642 printer
->name
, attr
->values
[0].integer
, printer
->state
);
2644 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
2645 cupsdStopPrinter(printer
, 0);
2648 need_restart_job
= 1;
2649 cupsdSetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
2653 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
2654 IPP_TAG_TEXT
)) != NULL
)
2656 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
2657 sizeof(printer
->state_message
));
2658 cupsdAddPrinterHistory(printer
);
2661 if ((attr
= ippFindAttribute(con
->request
, "printer-state-reasons",
2662 IPP_TAG_KEYWORD
)) != NULL
)
2664 if (attr
->num_values
>
2665 (int)(sizeof(printer
->reasons
) / sizeof(printer
->reasons
[0])))
2667 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2668 _("Too many printer-state-reasons values (%d > %d)!"),
2670 (int)(sizeof(printer
->reasons
) /
2671 sizeof(printer
->reasons
[0])));
2675 for (i
= 0; i
< printer
->num_reasons
; i
++)
2676 _cupsStrFree(printer
->reasons
[i
]);
2678 printer
->num_reasons
= 0;
2679 for (i
= 0; i
< attr
->num_values
; i
++)
2681 if (!strcmp(attr
->values
[i
].string
.text
, "none"))
2684 printer
->reasons
[printer
->num_reasons
] =
2685 _cupsStrRetain(attr
->values
[i
].string
.text
);
2686 printer
->num_reasons
++;
2688 if (!strcmp(attr
->values
[i
].string
.text
, "paused") &&
2689 printer
->state
!= IPP_PRINTER_STOPPED
)
2691 cupsdLogMessage(CUPSD_LOG_INFO
,
2692 "Setting %s printer-state to %d (was %d.)",
2693 printer
->name
, IPP_PRINTER_STOPPED
, printer
->state
);
2694 cupsdStopPrinter(printer
, 0);
2698 if (PrintcapFormat
== PRINTCAP_PLIST
)
2699 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
);
2702 set_printer_defaults(con
, printer
);
2704 if ((attr
= ippFindAttribute(con
->request
, "auth-info-required",
2705 IPP_TAG_KEYWORD
)) != NULL
)
2706 cupsdSetAuthInfoRequired(printer
, NULL
, attr
);
2709 * See if we have all required attributes...
2712 if (!printer
->device_uri
)
2713 cupsdSetString(&printer
->device_uri
, "file:///dev/null");
2716 * See if we have an interface script or PPD file attached to the request...
2721 need_restart_job
= 1;
2723 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
2725 if ((fp
= cupsFileOpen(srcfile
, "rb")))
2728 * Yes; get the first line from it...
2732 cupsFileGets(fp
, line
, sizeof(line
));
2736 * Then see what kind of file it is...
2739 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2742 if (!strncmp(line
, "*PPD-Adobe", 10))
2745 * The new file is a PPD file, so remove any old interface script
2746 * that might be lying around...
2754 * This must be an interface script, so move the file over to the
2755 * interfaces directory and make it executable...
2758 if (copy_file(srcfile
, dstfile
))
2760 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
2761 _("Unable to copy interface script - %s!"),
2766 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2767 "Copied interface script successfully!");
2768 chmod(dstfile
, 0755);
2771 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2774 if (!strncmp(line
, "*PPD-Adobe", 10))
2777 * The new file is a PPD file, so move the file over to the
2778 * ppd directory and make it readable by all...
2781 if (copy_file(srcfile
, dstfile
))
2783 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
2784 _("Unable to copy PPD file - %s!"),
2789 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2790 "Copied PPD file successfully!");
2791 chmod(dstfile
, 0644);
2795 * (Re)register color profiles...
2800 apple_unregister_profiles(printer
);
2801 apple_register_profiles(printer
);
2803 #endif /* __APPLE__ */
2808 * This must be an interface script, so remove any old PPD file that
2809 * may be lying around...
2816 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name",
2817 IPP_TAG_NAME
)) != NULL
)
2819 need_restart_job
= 1;
2821 if (!strcmp(attr
->values
[0].string
.text
, "raw"))
2824 * Raw driver, remove any existing PPD or interface script files.
2827 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2831 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2841 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2845 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2848 if (copy_model(con
, attr
->values
[0].string
.text
, dstfile
))
2850 send_ipp_status(con
, IPP_INTERNAL_ERROR
, _("Unable to copy PPD file!"));
2854 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2855 "Copied PPD file successfully!");
2856 chmod(dstfile
, 0644);
2860 * (Re)register color profiles...
2865 apple_unregister_profiles(printer
);
2866 apple_register_profiles(printer
);
2868 #endif /* __APPLE__ */
2873 * If we set the device URI but not the port monitor, check which port
2874 * monitor to use by default...
2877 if (set_device_uri
&& !set_port_monitor
)
2879 ppd_file_t
*ppd
; /* PPD file */
2880 ppd_attr_t
*ppdattr
; /* cupsPortMonitor attribute */
2883 httpSeparateURI(HTTP_URI_CODING_ALL
, printer
->device_uri
, scheme
,
2884 sizeof(scheme
), username
, sizeof(username
), host
,
2885 sizeof(host
), &port
, resource
, sizeof(resource
));
2887 snprintf(srcfile
, sizeof(srcfile
), "%s/ppd/%s.ppd", ServerRoot
,
2889 if ((ppd
= ppdOpenFile(srcfile
)) != NULL
)
2891 for (ppdattr
= ppdFindAttr(ppd
, "cupsPortMonitor", NULL
);
2893 ppdattr
= ppdFindNextAttr(ppd
, "cupsPortMonitor", NULL
))
2894 if (!strcmp(scheme
, ppdattr
->spec
))
2896 cupsdLogMessage(CUPSD_LOG_INFO
,
2897 "Setting %s port-monitor to \"%s\" (was \"%s\".)",
2898 printer
->name
, ppdattr
->value
,
2899 printer
->port_monitor
? printer
->port_monitor
2902 if (strcmp(ppdattr
->value
, "none"))
2903 cupsdSetString(&printer
->port_monitor
, ppdattr
->value
);
2905 cupsdClearString(&printer
->port_monitor
);
2915 * Update the printer attributes and return...
2918 cupsdSetPrinterAttrs(printer
);
2919 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
);
2921 if (need_restart_job
&& printer
->job
)
2924 * Restart the current job...
2927 cupsdSetJobState(printer
->job
, IPP_JOB_PENDING
, CUPSD_JOB_FORCE
,
2928 "Job restarted because the printer was modified.");
2931 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
);
2935 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
2936 "Printer \"%s\" modified by \"%s\".", printer
->name
,
2939 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" modified by \"%s\".",
2940 printer
->name
, get_username(con
));
2944 cupsdAddPrinterHistory(printer
);
2946 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
2947 "New printer \"%s\" added by \"%s\".", printer
->name
,
2950 cupsdLogMessage(CUPSD_LOG_INFO
, "New printer \"%s\" added by \"%s\".",
2951 printer
->name
, get_username(con
));
2954 con
->response
->request
.status
.status_code
= IPP_OK
;
2959 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
2960 * based upon the printer state...
2964 add_printer_state_reasons(
2965 cupsd_client_t
*con
, /* I - Client connection */
2966 cupsd_printer_t
*p
) /* I - Printer info */
2968 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
2969 "add_printer_state_reasons(%p[%d], %p[%s])",
2970 con
, con
->http
.fd
, p
, p
->name
);
2972 if (p
->num_reasons
== 0)
2973 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
2974 "printer-state-reasons", NULL
, "none");
2976 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
2977 "printer-state-reasons", p
->num_reasons
, NULL
,
2978 (const char * const *)p
->reasons
);
2983 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
2984 * the specified printer or class.
2988 add_queued_job_count(
2989 cupsd_client_t
*con
, /* I - Client connection */
2990 cupsd_printer_t
*p
) /* I - Printer or class */
2992 int count
; /* Number of jobs on destination */
2995 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])",
2996 con
, con
->http
.fd
, p
, p
->name
);
2998 count
= cupsdGetPrinterJobCount(p
->name
);
3000 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
3001 "queued-job-count", count
);
3007 * 'apple_init_profile()' - Initialize a color profile.
3012 ppd_file_t
*ppd
, /* I - PPD file */
3013 cups_array_t
*languages
, /* I - Languages in the PPD file */
3014 CMDeviceProfileInfo
*profile
, /* I - Profile record */
3015 unsigned id
, /* I - Profile ID */
3016 const char *name
, /* I - Profile name */
3017 const char *text
, /* I - Profile UI text */
3018 const char *iccfile
) /* I - ICC filename */
3020 char url
[1024]; /* URL for profile filename */
3021 CFMutableDictionaryRef dict
; /* Dictionary for name */
3022 char *language
; /* Current language */
3023 ppd_attr_t
*attr
; /* Profile attribute */
3024 CFStringRef cflang
, /* Language string */
3025 cftext
; /* Localized text */
3029 * Build the profile name dictionary...
3032 dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
3033 &kCFTypeDictionaryKeyCallBacks
,
3034 &kCFTypeDictionaryValueCallBacks
);
3036 cftext
= CFStringCreateWithCString(kCFAllocatorDefault
, text
,
3037 kCFStringEncodingUTF8
);
3041 CFDictionarySetValue(dict
, CFSTR("en"), cftext
);
3048 * Find localized names for the color profiles...
3051 cupsArraySave(ppd
->sorted_attrs
);
3053 for (language
= (char *)cupsArrayFirst(languages
);
3055 language
= (char *)cupsArrayNext(languages
))
3059 if ((attr
= _ppdLocalizedAttr(ppd
, "cupsICCProfile", name
,
3061 attr
= _ppdLocalizedAttr(ppd
, "APTiogaProfile", name
, language
);
3064 attr
= _ppdLocalizedAttr(ppd
, "ColorModel", name
, language
);
3066 if (attr
&& attr
->text
[0])
3068 cflang
= CFStringCreateWithCString(kCFAllocatorDefault
, language
,
3069 kCFStringEncodingUTF8
);
3070 cftext
= CFStringCreateWithCString(kCFAllocatorDefault
, attr
->text
,
3071 kCFStringEncodingUTF8
);
3073 if (cflang
&& cftext
)
3074 CFDictionarySetValue(dict
, cflang
, cftext
);
3084 cupsArrayRestore(ppd
->sorted_attrs
);
3088 * Fill in the profile data...
3092 httpAssembleURI(HTTP_URI_CODING_ALL
, url
, sizeof(url
), "file", NULL
, "", 0,
3095 profile
->dataVersion
= cmDeviceProfileInfoVersion1
;
3096 profile
->profileID
= id
;
3097 profile
->profileLoc
.locType
= iccfile
? cmPathBasedProfile
: cmNoProfileBase
;
3098 profile
->profileName
= dict
;
3101 strlcpy(profile
->profileLoc
.u
.pathLoc
.path
, iccfile
,
3102 sizeof(profile
->profileLoc
.u
.pathLoc
.path
));
3107 * 'apple_register_profiles()' - Register color profiles for a printer.
3111 apple_register_profiles(
3112 cupsd_printer_t
*p
) /* I - Printer */
3114 int i
; /* Looping var */
3115 char ppdfile
[1024], /* PPD filename */
3116 iccfile
[1024], /* ICC filename */
3117 selector
[PPD_MAX_NAME
];
3118 /* Profile selection string */
3119 ppd_file_t
*ppd
; /* PPD file */
3120 ppd_attr_t
*attr
, /* Profile attributes */
3121 *profileid_attr
,/* cupsProfileID attribute */
3122 *q1_attr
, /* ColorModel (or other) qualifier */
3123 *q2_attr
, /* MediaType (or other) qualifier */
3124 *q3_attr
; /* Resolution (or other) qualifier */
3125 char q_keyword
[PPD_MAX_NAME
];
3126 /* Qualifier keyword */
3127 const char *q1_choice
, /* ColorModel (or other) choice */
3128 *q2_choice
, /* MediaType (or other) choice */
3129 *q3_choice
; /* Resolution (or other) choice */
3130 const char *profile_key
; /* Profile keyword */
3131 ppd_option_t
*cm_option
; /* Color model option */
3132 ppd_choice_t
*cm_choice
; /* Color model choice */
3133 int num_profiles
; /* Number of profiles */
3134 CMError error
; /* Last error */
3135 unsigned device_id
, /* Printer device ID */
3136 profile_id
, /* Profile ID */
3137 default_profile_id
= 0;
3138 /* Default profile ID */
3139 CFMutableDictionaryRef device_name
; /* Printer device name dictionary */
3140 CFStringRef printer_name
; /* Printer name string */
3141 CMDeviceScope scope
= /* Scope of the registration */
3143 kCFPreferencesAnyUser
,
3144 kCFPreferencesCurrentHost
3146 CMDeviceProfileArrayPtr profiles
; /* Profiles */
3147 CMDeviceProfileInfo
*profile
; /* Current profile */
3148 cups_array_t
*languages
; /* Languages array */
3152 * Make sure ColorSync is available...
3155 if (CMRegisterColorDevice
== NULL
)
3159 * Try opening the PPD file for this printer...
3162 snprintf(ppdfile
, sizeof(ppdfile
), "%s/ppd/%s.ppd", ServerRoot
, p
->name
);
3163 if ((ppd
= ppdOpenFile(ppdfile
)) == NULL
)
3167 * See if we have any profiles...
3170 if ((attr
= ppdFindAttr(ppd
, "APTiogaProfile", NULL
)) != NULL
)
3171 profile_key
= "APTiogaProfile";
3174 attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
3175 profile_key
= "cupsICCProfile";
3178 for (num_profiles
= 0; attr
; attr
= ppdFindNextAttr(ppd
, profile_key
, NULL
))
3179 if (attr
->spec
[0] && attr
->value
&& attr
->value
[0])
3181 if (attr
->value
[0] != '/')
3182 snprintf(iccfile
, sizeof(iccfile
), "%s/profiles/%s", DataDir
,
3185 strlcpy(iccfile
, attr
->value
, sizeof(iccfile
));
3187 if (access(iccfile
, 0))
3195 * If we have profiles, add them...
3198 if (num_profiles
> 0)
3200 if (profile_key
[0] == 'A')
3203 * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile
3207 if ((attr
= ppdFindAttr(ppd
, "DefaultAPTiogaProfile", NULL
)) != NULL
&&
3209 default_profile_id
= atoi(attr
->value
);
3211 q1_choice
= q2_choice
= q3_choice
= NULL
;
3216 * For CUPS PPDs, figure out the default profile selector values...
3219 if ((attr
= ppdFindAttr(ppd
, "cupsICCQualifier1", NULL
)) != NULL
&&
3220 attr
->value
&& attr
->value
[0])
3222 snprintf(q_keyword
, sizeof(q_keyword
), "Default%s", attr
->value
);
3223 q1_attr
= ppdFindAttr(ppd
, q_keyword
, NULL
);
3225 else if ((q1_attr
= ppdFindAttr(ppd
, "DefaultColorModel", NULL
)) == NULL
)
3226 q1_attr
= ppdFindAttr(ppd
, "DefaultColorSpace", NULL
);
3228 if (q1_attr
&& q1_attr
->value
&& q1_attr
->value
[0])
3229 q1_choice
= q1_attr
->value
;
3233 if ((attr
= ppdFindAttr(ppd
, "cupsICCQualifier2", NULL
)) != NULL
&&
3234 attr
->value
&& attr
->value
[0])
3236 snprintf(q_keyword
, sizeof(q_keyword
), "Default%s", attr
->value
);
3237 q2_attr
= ppdFindAttr(ppd
, q_keyword
, NULL
);
3240 q2_attr
= ppdFindAttr(ppd
, "DefaultMediaType", NULL
);
3242 if (q2_attr
&& q2_attr
->value
&& q2_attr
->value
[0])
3243 q2_choice
= q2_attr
->value
;
3247 if ((attr
= ppdFindAttr(ppd
, "cupsICCQualifier3", NULL
)) != NULL
&&
3248 attr
->value
&& attr
->value
[0])
3250 snprintf(q_keyword
, sizeof(q_keyword
), "Default%s", attr
->value
);
3251 q3_attr
= ppdFindAttr(ppd
, q_keyword
, NULL
);
3254 q3_attr
= ppdFindAttr(ppd
, "DefaultResolution", NULL
);
3256 if (q3_attr
&& q3_attr
->value
&& q3_attr
->value
[0])
3257 q3_choice
= q3_attr
->value
;
3263 * Build the array of profiles...
3265 * Note: This calloc actually requests slightly more memory than needed.
3268 if ((profiles
= calloc(num_profiles
, sizeof(CMDeviceProfileArray
))) == NULL
)
3270 cupsdLogMessage(CUPSD_LOG_ERROR
,
3271 "Unable to allocate memory for %d profiles!",
3277 profiles
->profileCount
= num_profiles
;
3278 languages
= _ppdGetLanguages(ppd
);
3280 for (profile
= profiles
->profiles
,
3281 attr
= ppdFindAttr(ppd
, profile_key
, NULL
);
3283 attr
= ppdFindNextAttr(ppd
, profile_key
, NULL
))
3284 if (attr
->spec
[0] && attr
->value
&& attr
->value
[0])
3287 * Add this profile...
3290 if (attr
->value
[0] != '/')
3291 snprintf(iccfile
, sizeof(iccfile
), "%s/profiles/%s", DataDir
,
3294 strlcpy(iccfile
, attr
->value
, sizeof(iccfile
));
3296 if (access(iccfile
, 0))
3299 if (profile_key
[0] == 'c')
3301 cupsArraySave(ppd
->sorted_attrs
);
3303 if ((profileid_attr
= ppdFindAttr(ppd
, "cupsProfileID",
3304 attr
->spec
)) != NULL
&&
3305 profileid_attr
->value
&& isdigit(profileid_attr
->value
[0] & 255))
3306 profile_id
= (unsigned)strtoul(profileid_attr
->value
, NULL
, 10);
3308 profile_id
= _ppdHashName(attr
->spec
);
3310 cupsArrayRestore(ppd
->sorted_attrs
);
3313 profile_id
= atoi(attr
->spec
);
3315 apple_init_profile(ppd
, languages
, profile
, profile_id
, attr
->spec
,
3316 attr
->text
[0] ? attr
->text
: attr
->spec
, iccfile
);
3321 * See if this is the default profile...
3324 if (!default_profile_id
)
3330 snprintf(selector
, sizeof(selector
), "%s.%s.%s",
3331 q1_choice
, q2_choice
, q3_choice
);
3332 if (!strcmp(selector
, attr
->spec
))
3333 default_profile_id
= profile_id
;
3336 if (!default_profile_id
)
3338 snprintf(selector
, sizeof(selector
), "%s.%s.", q1_choice
,
3340 if (!strcmp(selector
, attr
->spec
))
3341 default_profile_id
= profile_id
;
3345 if (!default_profile_id
&& q3_choice
)
3347 snprintf(selector
, sizeof(selector
), "%s..%s", q1_choice
,
3349 if (!strcmp(selector
, attr
->spec
))
3350 default_profile_id
= profile_id
;
3353 if (!default_profile_id
)
3355 snprintf(selector
, sizeof(selector
), "%s..", q1_choice
);
3356 if (!strcmp(selector
, attr
->spec
))
3357 default_profile_id
= profile_id
;
3362 _ppdFreeLanguages(languages
);
3364 else if ((cm_option
= ppdFindOption(ppd
, "ColorModel")) != NULL
)
3367 * Extract profiles from ColorModel option...
3370 const char *profile_name
; /* Name of generic profile */
3373 num_profiles
= cm_option
->num_choices
;
3375 if ((profiles
= calloc(num_profiles
, sizeof(CMDeviceProfileArray
))) == NULL
)
3377 cupsdLogMessage(CUPSD_LOG_ERROR
,
3378 "Unable to allocate memory for %d profiles!",
3384 profiles
->profileCount
= num_profiles
;
3386 for (profile
= profiles
->profiles
, i
= cm_option
->num_choices
,
3387 cm_choice
= cm_option
->choices
;
3389 i
--, cm_choice
++, profile
++)
3391 if (!strcmp(cm_choice
->choice
, "Gray") ||
3392 !strcmp(cm_choice
->choice
, "Black"))
3393 profile_name
= "Gray";
3394 else if (!strcmp(cm_choice
->choice
, "RGB") ||
3395 !strcmp(cm_choice
->choice
, "CMY"))
3396 profile_name
= "RGB";
3397 else if (!strcmp(cm_choice
->choice
, "CMYK") ||
3398 !strcmp(cm_choice
->choice
, "KCMY"))
3399 profile_name
= "CMYK";
3401 profile_name
= "DeviceN";
3403 snprintf(selector
, sizeof(selector
), "%s..", profile_name
);
3404 profile_id
= _ppdHashName(selector
);
3406 apple_init_profile(ppd
, NULL
, profile
, profile_id
, cm_choice
->choice
,
3407 cm_choice
->text
, NULL
);
3409 if (cm_choice
->marked
)
3410 default_profile_id
= profile_id
;
3416 * Use the default colorspace...
3419 attr
= ppdFindAttr(ppd
, "DefaultColorSpace", NULL
);
3421 num_profiles
= (attr
&& ppd
->colorspace
== PPD_CS_GRAY
) ? 1 : 2;
3423 if ((profiles
= calloc(num_profiles
, sizeof(CMDeviceProfileArray
))) == NULL
)
3425 cupsdLogMessage(CUPSD_LOG_ERROR
,
3426 "Unable to allocate memory for %d profiles!",
3432 profiles
->profileCount
= num_profiles
;
3434 apple_init_profile(ppd
, NULL
, profiles
->profiles
, _ppdHashName("Gray.."),
3435 "Gray", "Gray", NULL
);
3437 switch (ppd
->colorspace
)
3441 apple_init_profile(ppd
, NULL
, profiles
->profiles
+ 1,
3442 _ppdHashName("RGB.."), "RGB", "RGB", NULL
);
3446 apple_init_profile(ppd
, NULL
, profiles
->profiles
+ 1,
3447 _ppdHashName("CMYK.."), "CMYK", "CMYK", NULL
);
3455 apple_init_profile(ppd
, NULL
, profiles
->profiles
+ 1,
3456 _ppdHashName("DeviceN.."), "DeviceN", "DeviceN",
3462 if (num_profiles
> 0)
3465 * Make sure we have a default profile ID...
3468 if (!default_profile_id
)
3469 default_profile_id
= profiles
->profiles
[num_profiles
- 1].profileID
;
3472 * Get the device ID hash and pathelogical name dictionary.
3475 cupsdLogMessage(CUPSD_LOG_INFO
, "Registering ICC color profiles for \"%s\"",
3478 device_id
= _ppdHashName(p
->name
);
3479 device_name
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
3480 &kCFTypeDictionaryKeyCallBacks
,
3481 &kCFTypeDictionaryValueCallBacks
);
3482 printer_name
= CFStringCreateWithCString(kCFAllocatorDefault
,
3483 p
->name
, kCFStringEncodingUTF8
);
3485 if (device_name
&& printer_name
)
3487 CFDictionarySetValue(device_name
, CFSTR("en"), printer_name
);
3490 * Register the device with ColorSync...
3493 error
= CMRegisterColorDevice(cmPrinterDeviceClass
, device_id
,
3494 device_name
, &scope
);
3497 * Register the profiles...
3501 error
= CMSetDeviceFactoryProfiles(cmPrinterDeviceClass
, device_id
,
3502 default_profile_id
, profiles
);
3512 cupsdLogMessage(CUPSD_LOG_ERROR
,
3513 "Unable to register ICC color profiles for \"%s\" - %d",
3514 p
->name
, (int)error
);
3516 for (profile
= profiles
->profiles
;
3518 profile
++, num_profiles
--)
3519 CFRelease(profile
->profileName
);
3524 CFRelease(printer_name
);
3527 CFRelease(device_name
);
3535 * 'apple_unregister_profiles()' - Remove color profiles for the specified
3540 apple_unregister_profiles(
3541 cupsd_printer_t
*p
) /* I - Printer */
3544 * Make sure ColorSync is available...
3547 if (CMUnregisterColorDevice
!= NULL
)
3548 CMUnregisterColorDevice(cmPrinterDeviceClass
, _ppdHashName(p
->name
));
3550 #endif /* __APPLE__ */
3553 * 'apply_printer_defaults()' - Apply printer default options to a job.
3557 apply_printer_defaults(
3558 cupsd_printer_t
*printer
, /* I - Printer */
3559 cupsd_job_t
*job
) /* I - Job */
3561 int i
, /* Looping var */
3562 num_options
; /* Number of default options */
3563 cups_option_t
*options
, /* Default options */
3564 *option
; /* Current option */
3568 * Collect all of the default options and add the missing ones to the
3572 for (i
= printer
->num_options
, num_options
= 0, options
= NULL
,
3573 option
= printer
->options
;
3576 if (!ippFindAttribute(job
->attrs
, option
->name
, IPP_TAG_ZERO
))
3578 num_options
= cupsAddOption(option
->name
, option
->value
, num_options
,
3583 * Encode these options as attributes in the job object...
3586 cupsEncodeOptions2(job
->attrs
, num_options
, options
, IPP_TAG_JOB
);
3587 cupsFreeOptions(num_options
, options
);
3592 * 'authenticate_job()' - Set job authentication info.
3596 authenticate_job(cupsd_client_t
*con
, /* I - Client connection */
3597 ipp_attribute_t
*uri
) /* I - Job URI */
3599 ipp_attribute_t
*attr
, /* job-id attribute */
3600 *auth_info
; /* auth-info attribute */
3601 int jobid
; /* Job ID */
3602 cupsd_job_t
*job
; /* Current job */
3603 char scheme
[HTTP_MAX_URI
],
3604 /* Method portion of URI */
3605 username
[HTTP_MAX_URI
],
3606 /* Username portion of URI */
3608 /* Host portion of URI */
3609 resource
[HTTP_MAX_URI
];
3610 /* Resource portion of URI */
3611 int port
; /* Port portion of URI */
3614 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "authenticate_job(%p[%d], %s)",
3615 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
3618 * Start with "everything is OK" status...
3621 con
->response
->request
.status
.status_code
= IPP_OK
;
3624 * See if we have a job URI or a printer URI...
3627 if (!strcmp(uri
->name
, "printer-uri"))
3630 * Got a printer URI; see if we also have a job-id attribute...
3633 if ((attr
= ippFindAttribute(con
->request
, "job-id",
3634 IPP_TAG_INTEGER
)) == NULL
)
3636 send_ipp_status(con
, IPP_BAD_REQUEST
,
3637 _("Got a printer-uri attribute but no job-id!"));
3641 jobid
= attr
->values
[0].integer
;
3646 * Got a job URI; parse it to get the job ID...
3649 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
3650 sizeof(scheme
), username
, sizeof(username
), host
,
3651 sizeof(host
), &port
, resource
, sizeof(resource
));
3653 if (strncmp(resource
, "/jobs/", 6))
3659 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad job-uri attribute \"%s\"!"),
3660 uri
->values
[0].string
.text
);
3664 jobid
= atoi(resource
+ 6);
3668 * See if the job exists...
3671 if ((job
= cupsdFindJob(jobid
)) == NULL
)
3674 * Nope - return a "not found" error...
3677 send_ipp_status(con
, IPP_NOT_FOUND
,
3678 _("Job #%d does not exist!"), jobid
);
3683 * See if the job has been completed...
3686 if (job
->state_value
!= IPP_JOB_HELD
)
3689 * Return a "not-possible" error...
3692 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
3693 _("Job #%d is not held for authentication!"),
3699 * See if we have already authenticated...
3702 auth_info
= ippFindAttribute(con
->request
, "auth-info", IPP_TAG_TEXT
);
3704 if (!con
->username
[0] && !auth_info
)
3706 cupsd_printer_t
*printer
; /* Job destination */
3710 * No auth data. If we need to authenticate via Kerberos, send a
3711 * HTTP auth challenge, otherwise just return an IPP error...
3714 printer
= cupsdFindDest(job
->dest
);
3716 if (printer
&& printer
->num_auth_info_required
> 0 &&
3717 !strcmp(printer
->auth_info_required
[0], "negotiate"))
3718 send_http_error(con
, HTTP_UNAUTHORIZED
, printer
);
3720 send_ipp_status(con
, IPP_NOT_AUTHORIZED
,
3721 _("No authentication information provided!"));
3726 * See if the job is owned by the requesting user...
3729 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
3731 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
3736 * Save the authentication information for this job...
3739 save_auth_info(con
, job
, auth_info
);
3742 * Reset the job-hold-until value to "no-hold"...
3745 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
3746 IPP_TAG_KEYWORD
)) == NULL
)
3747 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3751 attr
->value_tag
= IPP_TAG_KEYWORD
;
3752 cupsdSetString(&(attr
->values
[0].string
.text
), "no-hold");
3756 * Release the job and return...
3759 cupsdReleaseJob(job
);
3761 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Authenticated by \"%s\".", con
->username
);
3766 * 'cancel_all_jobs()' - Cancel all print jobs.
3770 cancel_all_jobs(cupsd_client_t
*con
, /* I - Client connection */
3771 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
3773 http_status_t status
; /* Policy status */
3774 cups_ptype_t dtype
; /* Destination type */
3775 char scheme
[HTTP_MAX_URI
], /* Scheme portion of URI */
3776 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
3777 hostname
[HTTP_MAX_URI
], /* Host portion of URI */
3778 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3779 int port
; /* Port portion of URI */
3780 ipp_attribute_t
*attr
; /* Attribute in request */
3781 const char *username
; /* Username */
3782 int purge
; /* Purge? */
3783 cupsd_printer_t
*printer
; /* Printer */
3786 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cancel_all_jobs(%p[%d], %s)", con
,
3787 con
->http
.fd
, uri
->values
[0].string
.text
);
3790 * See if we have a printer URI...
3793 if (strcmp(uri
->name
, "printer-uri"))
3795 send_ipp_status(con
, IPP_BAD_REQUEST
,
3796 _("The printer-uri attribute is required!"));
3801 * Get the username (if any) for the jobs we want to cancel (only if
3802 * "my-jobs" is specified...
3805 if ((attr
= ippFindAttribute(con
->request
, "my-jobs",
3806 IPP_TAG_BOOLEAN
)) != NULL
&&
3807 attr
->values
[0].boolean
)
3809 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
3810 IPP_TAG_NAME
)) != NULL
)
3811 username
= attr
->values
[0].string
.text
;
3814 send_ipp_status(con
, IPP_BAD_REQUEST
,
3815 _("Missing requesting-user-name attribute!"));
3823 * Look for the "purge-jobs" attribute...
3826 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs",
3827 IPP_TAG_BOOLEAN
)) != NULL
)
3828 purge
= attr
->values
[0].boolean
;
3833 * And if the destination is valid...
3836 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
3842 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
,
3843 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
3844 hostname
, sizeof(hostname
), &port
,
3845 resource
, sizeof(resource
));
3847 if ((!strncmp(resource
, "/printers/", 10) && resource
[10]) ||
3848 (!strncmp(resource
, "/classes/", 9) && resource
[9]))
3850 send_ipp_status(con
, IPP_NOT_FOUND
,
3851 _("The printer or class was not found."));
3859 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
3861 send_http_error(con
, status
, NULL
);
3866 * Cancel all jobs on all printers...
3869 cupsdCancelJobs(NULL
, username
, purge
);
3871 cupsdLogMessage(CUPSD_LOG_INFO
, "All jobs were %s by \"%s\".",
3872 purge
? "purged" : "canceled", get_username(con
));
3880 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
,
3883 send_http_error(con
, status
, printer
);
3888 * Cancel all of the jobs on the named printer...
3891 cupsdCancelJobs(printer
->name
, username
, purge
);
3893 cupsdLogMessage(CUPSD_LOG_INFO
, "All jobs on \"%s\" were %s by \"%s\".",
3894 printer
->name
, purge
? "purged" : "canceled",
3898 con
->response
->request
.status
.status_code
= IPP_OK
;
3903 * 'cancel_job()' - Cancel a print job.
3907 cancel_job(cupsd_client_t
*con
, /* I - Client connection */
3908 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
3910 ipp_attribute_t
*attr
; /* Current attribute */
3911 int jobid
; /* Job ID */
3912 char scheme
[HTTP_MAX_URI
], /* Scheme portion of URI */
3913 username
[HTTP_MAX_URI
], /* Username portion of URI */
3914 host
[HTTP_MAX_URI
], /* Host portion of URI */
3915 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3916 int port
; /* Port portion of URI */
3917 cupsd_job_t
*job
; /* Job information */
3918 cups_ptype_t dtype
; /* Destination type (printer/class) */
3919 cupsd_printer_t
*printer
; /* Printer data */
3920 int purge
; /* Purge the job? */
3923 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cancel_job(%p[%d], %s)", con
,
3924 con
->http
.fd
, uri
->values
[0].string
.text
);
3927 * See if we have a job URI or a printer URI...
3930 if (!strcmp(uri
->name
, "printer-uri"))
3933 * Got a printer URI; see if we also have a job-id attribute...
3936 if ((attr
= ippFindAttribute(con
->request
, "job-id",
3937 IPP_TAG_INTEGER
)) == NULL
)
3939 send_ipp_status(con
, IPP_BAD_REQUEST
,
3940 _("Got a printer-uri attribute but no job-id!"));
3944 if ((jobid
= attr
->values
[0].integer
) == 0)
3947 * Find the current job on the specified printer...
3950 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
3956 send_ipp_status(con
, IPP_NOT_FOUND
,
3957 _("The printer or class was not found."));
3962 * See if there are any pending jobs...
3965 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
3967 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
3968 if (job
->state_value
<= IPP_JOB_PROCESSING
&&
3969 !strcasecmp(job
->dest
, printer
->name
))
3977 * No, try stopped jobs...
3980 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
3982 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
3983 if (job
->state_value
== IPP_JOB_STOPPED
&&
3984 !strcasecmp(job
->dest
, printer
->name
))
3991 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("No active jobs on %s!"),
4001 * Got a job URI; parse it to get the job ID...
4004 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
4005 sizeof(scheme
), username
, sizeof(username
), host
,
4006 sizeof(host
), &port
, resource
, sizeof(resource
));
4008 if (strncmp(resource
, "/jobs/", 6))
4014 send_ipp_status(con
, IPP_BAD_REQUEST
,
4015 _("Bad job-uri attribute \"%s\"!"),
4016 uri
->values
[0].string
.text
);
4020 jobid
= atoi(resource
+ 6);
4024 * Look for the "purge-job" attribute...
4027 if ((attr
= ippFindAttribute(con
->request
, "purge-job",
4028 IPP_TAG_BOOLEAN
)) != NULL
)
4029 purge
= attr
->values
[0].boolean
;
4034 * See if the job exists...
4037 if ((job
= cupsdFindJob(jobid
)) == NULL
)
4040 * Nope - return a "not found" error...
4043 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
4048 * See if the job is owned by the requesting user...
4051 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4053 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
4058 * See if the job is already completed, canceled, or aborted; if so,
4059 * we can't cancel...
4062 if (job
->state_value
>= IPP_JOB_CANCELED
&& !purge
)
4064 switch (job
->state_value
)
4066 case IPP_JOB_CANCELED
:
4067 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4068 _("Job #%d is already canceled - can\'t cancel."),
4072 case IPP_JOB_ABORTED
:
4073 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4074 _("Job #%d is already aborted - can\'t cancel."),
4079 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4080 _("Job #%d is already completed - can\'t cancel."),
4089 * Cancel the job and return...
4092 cupsdSetJobState(job
, IPP_JOB_CANCELED
, purge
,
4093 purge
? "Job purged by \"%s\"" : "Job canceled by \"%s\"",
4098 cupsdLogMessage(CUPSD_LOG_INFO
, "[Job %d] Purged by \"%s\".", jobid
,
4101 cupsdLogMessage(CUPSD_LOG_INFO
, "[Job %d] Canceled by \"%s\".", jobid
,
4104 con
->response
->request
.status
.status_code
= IPP_OK
;
4109 * 'cancel_subscription()' - Cancel a subscription.
4113 cancel_subscription(
4114 cupsd_client_t
*con
, /* I - Client connection */
4115 int sub_id
) /* I - Subscription ID */
4117 http_status_t status
; /* Policy status */
4118 cupsd_subscription_t
*sub
; /* Subscription */
4121 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4122 "cancel_subscription(con=%p[%d], sub_id=%d)",
4123 con
, con
->http
.fd
, sub_id
);
4126 * Is the subscription ID valid?
4129 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
4132 * Bad subscription ID...
4135 send_ipp_status(con
, IPP_NOT_FOUND
,
4136 _("notify-subscription-id %d no good!"), sub_id
);
4144 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
4146 con
, sub
->owner
)) != HTTP_OK
)
4148 send_http_error(con
, status
, sub
->dest
);
4153 * Cancel the subscription...
4156 cupsdDeleteSubscription(sub
, 1);
4158 con
->response
->request
.status
.status_code
= IPP_OK
;
4163 * 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI.
4166 static int /* O - 1 if OK, 0 if not */
4167 check_rss_recipient(
4168 const char *recipient
) /* I - Recipient URI */
4170 cupsd_subscription_t
*sub
; /* Current subscription */
4173 for (sub
= (cupsd_subscription_t
*)cupsArrayFirst(Subscriptions
);
4175 sub
= (cupsd_subscription_t
*)cupsArrayNext(Subscriptions
))
4179 * Compare the URIs up to the first ?...
4182 const char *r1
, *r2
;
4184 for (r1
= recipient
, r2
= sub
->recipient
;
4185 *r1
== *r2
&& *r1
&& *r1
!= '?' && *r2
&& *r2
!= '?';
4197 * 'check_quotas()' - Check quotas for a printer and user.
4200 static int /* O - 1 if OK, 0 if not */
4201 check_quotas(cupsd_client_t
*con
, /* I - Client connection */
4202 cupsd_printer_t
*p
) /* I - Printer or class */
4204 int i
; /* Looping var */
4205 char username
[33]; /* Username */
4206 cupsd_quota_t
*q
; /* Quota data */
4207 #ifdef HAVE_MBR_UID_TO_UUID
4209 * Use Apple membership APIs which require that all names represent
4210 * valid user account or group records accessible by the server.
4213 uuid_t usr_uuid
; /* UUID for job requesting user */
4214 uuid_t usr2_uuid
; /* UUID for ACL user name entry */
4215 uuid_t grp_uuid
; /* UUID for ACL group name entry */
4216 int mbr_err
; /* Error from membership function */
4217 int is_member
; /* Is this user a member? */
4220 * Use standard POSIX APIs for checking users and groups...
4223 struct passwd
*pw
; /* User password data */
4224 #endif /* HAVE_MBR_UID_TO_UUID */
4227 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "check_quotas(%p[%d], %p[%s])",
4228 con
, con
->http
.fd
, p
, p
->name
);
4231 * Figure out who is printing...
4234 strlcpy(username
, get_username(con
), sizeof(username
));
4237 * Check global active job limits for printers and users...
4240 if (MaxJobsPerPrinter
)
4243 * Check if there are too many pending jobs on this printer...
4246 if (cupsdGetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
4248 cupsdLogMessage(CUPSD_LOG_INFO
, "Too many jobs for printer \"%s\"...",
4257 * Check if there are too many pending jobs for this user...
4260 if (cupsdGetUserJobCount(username
) >= MaxJobsPerUser
)
4262 cupsdLogMessage(CUPSD_LOG_INFO
, "Too many jobs for user \"%s\"...",
4269 * Check against users...
4272 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
4277 #ifdef HAVE_MBR_UID_TO_UUID
4279 * Get UUID for job requesting user...
4282 if (mbr_user_name_to_uuid((char *)username
, usr_uuid
))
4288 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4289 "check_quotas: UUID lookup failed for user \"%s\"",
4291 cupsdLogMessage(CUPSD_LOG_INFO
,
4292 "Denying user \"%s\" access to printer \"%s\" "
4293 "(unknown user)...",
4299 * Get UID and GID of requesting user...
4302 pw
= getpwnam(username
);
4304 #endif /* HAVE_MBR_UID_TO_UUID */
4306 for (i
= 0; i
< p
->num_users
; i
++)
4307 if (p
->users
[i
][0] == '@')
4310 * Check group membership...
4313 #ifdef HAVE_MBR_UID_TO_UUID
4314 if (p
->users
[i
][1] == '#')
4316 if (uuid_parse((char *)p
->users
[i
] + 2, grp_uuid
))
4317 uuid_clear(grp_uuid
);
4319 else if ((mbr_err
= mbr_group_name_to_uuid((char *)p
->users
[i
] + 1,
4323 * Invalid ACL entries are ignored for matching; just record a
4324 * warning in the log...
4327 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4328 "check_quotas: UUID lookup failed for ACL entry "
4329 "\"%s\" (err=%d)", p
->users
[i
], mbr_err
);
4330 cupsdLogMessage(CUPSD_LOG_WARN
,
4331 "Access control entry \"%s\" not a valid group name; "
4332 "entry ignored", p
->users
[i
]);
4335 if ((mbr_err
= mbr_check_membership(usr_uuid
, grp_uuid
,
4339 * At this point, there should be no errors, but check anyways...
4342 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4343 "check_quotas: group \"%s\" membership check "
4344 "failed (err=%d)", p
->users
[i
] + 1, mbr_err
);
4349 * Stop if we found a match...
4356 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
4358 #endif /* HAVE_MBR_UID_TO_UUID */
4360 #ifdef HAVE_MBR_UID_TO_UUID
4363 if (p
->users
[i
][0] == '#')
4365 if (uuid_parse((char *)p
->users
[i
] + 1, usr2_uuid
))
4366 uuid_clear(usr2_uuid
);
4368 else if ((mbr_err
= mbr_user_name_to_uuid((char *)p
->users
[i
],
4372 * Invalid ACL entries are ignored for matching; just record a
4373 * warning in the log...
4376 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4377 "check_quotas: UUID lookup failed for ACL entry "
4378 "\"%s\" (err=%d)", p
->users
[i
], mbr_err
);
4379 cupsdLogMessage(CUPSD_LOG_WARN
,
4380 "Access control entry \"%s\" not a valid user name; "
4381 "entry ignored", p
->users
[i
]);
4384 if (!uuid_compare(usr_uuid
, usr2_uuid
))
4388 else if (!strcasecmp(username
, p
->users
[i
]))
4390 #endif /* HAVE_MBR_UID_TO_UUID */
4392 if ((i
< p
->num_users
) == p
->deny_users
)
4394 cupsdLogMessage(CUPSD_LOG_INFO
,
4395 "Denying user \"%s\" access to printer \"%s\"...",
4406 if (AppleQuotas
&& (q
= cupsdFindQuota(p
, username
)) != NULL
)
4409 * TODO: Define these special page count values as constants!
4412 if (q
->page_count
== -4) /* special case: unlimited user */
4414 cupsdLogMessage(CUPSD_LOG_INFO
,
4415 "User \"%s\" request approved for printer %s (%s): "
4417 username
, p
->name
, p
->info
);
4418 q
->page_count
= 0; /* allow user to print */
4421 else if (q
->page_count
== -3) /* quota exceeded */
4423 cupsdLogMessage(CUPSD_LOG_INFO
,
4424 "User \"%s\" request denied for printer %s (%s): "
4425 "quota limit exceeded.",
4426 username
, p
->name
, p
->info
);
4427 q
->page_count
= 2; /* force quota exceeded failure */
4430 else if (q
->page_count
== -2) /* quota disabled for user */
4432 cupsdLogMessage(CUPSD_LOG_INFO
,
4433 "User \"%s\" request denied for printer %s (%s): "
4434 "printing disabled for user.",
4435 username
, p
->name
, p
->info
);
4436 q
->page_count
= 2; /* force quota exceeded failure */
4439 else if (q
->page_count
== -1) /* quota access error */
4441 cupsdLogMessage(CUPSD_LOG_INFO
,
4442 "User \"%s\" request denied for printer %s (%s): "
4443 "unable to determine quota limit.",
4444 username
, p
->name
, p
->info
);
4445 q
->page_count
= 2; /* force quota exceeded failure */
4448 else if (q
->page_count
< 0) /* user not found or other error */
4450 cupsdLogMessage(CUPSD_LOG_INFO
,
4451 "User \"%s\" request denied for printer %s (%s): "
4452 "user disabled / missing quota.",
4453 username
, p
->name
, p
->info
);
4454 q
->page_count
= 2; /* force quota exceeded failure */
4457 else /* page within user limits */
4459 q
->page_count
= 0; /* allow user to print */
4464 #endif /* __APPLE__ */
4465 if (p
->k_limit
|| p
->page_limit
)
4467 if ((q
= cupsdUpdateQuota(p
, username
, 0, 0)) == NULL
)
4469 cupsdLogMessage(CUPSD_LOG_ERROR
,
4470 "Unable to allocate quota data for user \"%s\"!",
4475 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
4476 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
4478 cupsdLogMessage(CUPSD_LOG_INFO
, "User \"%s\" is over the quota limit...",
4485 * If we have gotten this far, we're done!
4493 * 'copy_attribute()' - Copy a single attribute.
4496 static ipp_attribute_t
* /* O - New attribute */
4498 ipp_t
*to
, /* O - Destination request/response */
4499 ipp_attribute_t
*attr
, /* I - Attribute to copy */
4500 int quickcopy
) /* I - Do a quick copy? */
4502 int i
; /* Looping var */
4503 ipp_attribute_t
*toattr
; /* Destination attribute */
4506 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4507 "copy_attribute(%p, %p[%s,%x,%x])", to
, attr
,
4508 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
4511 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
4514 toattr
= ippAddSeparator(to
);
4517 case IPP_TAG_INTEGER
:
4519 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
4520 attr
->name
, attr
->num_values
, NULL
);
4522 for (i
= 0; i
< attr
->num_values
; i
++)
4523 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
4526 case IPP_TAG_BOOLEAN
:
4527 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
4528 attr
->num_values
, NULL
);
4530 for (i
= 0; i
< attr
->num_values
; i
++)
4531 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
4534 case IPP_TAG_STRING
:
4537 case IPP_TAG_KEYWORD
:
4539 case IPP_TAG_URISCHEME
:
4540 case IPP_TAG_CHARSET
:
4541 case IPP_TAG_LANGUAGE
:
4542 case IPP_TAG_MIMETYPE
:
4543 toattr
= ippAddStrings(to
, attr
->group_tag
,
4544 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
4545 attr
->name
, attr
->num_values
, NULL
, NULL
);
4549 for (i
= 0; i
< attr
->num_values
; i
++)
4550 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
4552 else if (attr
->value_tag
& IPP_TAG_COPY
)
4554 for (i
= 0; i
< attr
->num_values
; i
++)
4555 toattr
->values
[i
].string
.text
=
4556 _cupsStrAlloc(attr
->values
[i
].string
.text
);
4560 for (i
= 0; i
< attr
->num_values
; i
++)
4561 toattr
->values
[i
].string
.text
=
4562 _cupsStrRetain(attr
->values
[i
].string
.text
);
4567 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
4568 attr
->values
[0].date
);
4571 case IPP_TAG_RESOLUTION
:
4572 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
4573 attr
->num_values
, IPP_RES_PER_INCH
,
4576 for (i
= 0; i
< attr
->num_values
; i
++)
4578 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
4579 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
4580 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
4584 case IPP_TAG_RANGE
:
4585 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
4586 attr
->num_values
, NULL
, NULL
);
4588 for (i
= 0; i
< attr
->num_values
; i
++)
4590 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
4591 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
4595 case IPP_TAG_TEXTLANG
:
4596 case IPP_TAG_NAMELANG
:
4597 toattr
= ippAddStrings(to
, attr
->group_tag
,
4598 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
4599 attr
->name
, attr
->num_values
, NULL
, NULL
);
4603 for (i
= 0; i
< attr
->num_values
; i
++)
4605 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
4606 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
4609 else if (attr
->value_tag
& IPP_TAG_COPY
)
4611 for (i
= 0; i
< attr
->num_values
; i
++)
4614 toattr
->values
[i
].string
.charset
=
4615 _cupsStrAlloc(attr
->values
[i
].string
.charset
);
4617 toattr
->values
[i
].string
.charset
=
4618 toattr
->values
[0].string
.charset
;
4620 toattr
->values
[i
].string
.text
=
4621 _cupsStrAlloc(attr
->values
[i
].string
.text
);
4626 for (i
= 0; i
< attr
->num_values
; i
++)
4629 toattr
->values
[i
].string
.charset
=
4630 _cupsStrRetain(attr
->values
[i
].string
.charset
);
4632 toattr
->values
[i
].string
.charset
=
4633 toattr
->values
[0].string
.charset
;
4635 toattr
->values
[i
].string
.text
=
4636 _cupsStrRetain(attr
->values
[i
].string
.text
);
4641 case IPP_TAG_BEGIN_COLLECTION
:
4642 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
4643 attr
->num_values
, NULL
);
4645 for (i
= 0; i
< attr
->num_values
; i
++)
4647 toattr
->values
[i
].collection
= ippNew();
4648 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
4649 NULL
, IPP_TAG_ZERO
, 0);
4654 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
4655 attr
->name
, attr
->num_values
, NULL
);
4657 for (i
= 0; i
< attr
->num_values
; i
++)
4659 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
4661 if (toattr
->values
[i
].unknown
.length
> 0)
4663 if ((toattr
->values
[i
].unknown
.data
=
4664 malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
4665 toattr
->values
[i
].unknown
.length
= 0;
4667 memcpy(toattr
->values
[i
].unknown
.data
,
4668 attr
->values
[i
].unknown
.data
,
4669 toattr
->values
[i
].unknown
.length
);
4672 break; /* anti-compiler-warning-code */
4680 * 'copy_attrs()' - Copy attributes from one request to another.
4684 copy_attrs(ipp_t
*to
, /* I - Destination request */
4685 ipp_t
*from
, /* I - Source request */
4686 cups_array_t
*ra
, /* I - Requested attributes */
4687 ipp_tag_t group
, /* I - Group to copy */
4688 int quickcopy
) /* I - Do a quick copy? */
4690 ipp_attribute_t
*fromattr
; /* Source attribute */
4693 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4694 "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
4695 to
, from
, ra
, group
, quickcopy
);
4700 for (fromattr
= from
->attrs
; fromattr
; fromattr
= fromattr
->next
)
4703 * Filter attributes as needed...
4706 if ((group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
4707 fromattr
->group_tag
!= IPP_TAG_ZERO
) || !fromattr
->name
)
4710 if (!ra
|| cupsArrayFind(ra
, fromattr
->name
))
4713 * Don't send collection attributes by default to IPP/1.x clients
4714 * since many do not support collections...
4717 if (fromattr
->value_tag
== IPP_TAG_BEGIN_COLLECTION
&&
4718 !ra
&& to
->request
.status
.version
[0] == 1)
4721 copy_attribute(to
, fromattr
, quickcopy
);
4728 * 'copy_banner()' - Copy a banner file to the requests directory for the
4732 static int /* O - Size of banner file in kbytes */
4733 copy_banner(cupsd_client_t
*con
, /* I - Client connection */
4734 cupsd_job_t
*job
, /* I - Job information */
4735 const char *name
) /* I - Name of banner */
4737 int i
; /* Looping var */
4738 int kbytes
; /* Size of banner file in kbytes */
4739 char filename
[1024]; /* Job filename */
4740 cupsd_banner_t
*banner
; /* Pointer to banner */
4741 cups_file_t
*in
; /* Input file */
4742 cups_file_t
*out
; /* Output file */
4743 int ch
; /* Character from file */
4744 char attrname
[255], /* Name of attribute */
4745 *s
; /* Pointer into name */
4746 ipp_attribute_t
*attr
; /* Attribute */
4749 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4750 "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")",
4751 con
, con
? con
->http
.fd
: -1, job
, job
->id
,
4752 name
? name
: "(null)");
4755 * Find the banner; return if not found or "none"...
4758 if (!name
|| !strcmp(name
, "none") ||
4759 (banner
= cupsdFindBanner(name
)) == NULL
)
4763 * Open the banner and job files...
4766 if (add_file(con
, job
, banner
->filetype
, 0))
4769 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
4771 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
4773 cupsdLogMessage(CUPSD_LOG_ERROR
,
4774 "Unable to create banner job file %s - %s",
4775 filename
, strerror(errno
));
4780 fchmod(cupsFileNumber(out
), 0640);
4781 fchown(cupsFileNumber(out
), RunUser
, Group
);
4784 * Try the localized banner file under the subdirectory...
4787 strlcpy(attrname
, job
->attrs
->attrs
->next
->values
[0].string
.text
,
4789 if (strlen(attrname
) > 2 && attrname
[2] == '-')
4792 * Convert ll-cc to ll_CC...
4796 attrname
[3] = toupper(attrname
[3] & 255);
4797 attrname
[4] = toupper(attrname
[4] & 255);
4800 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
4803 if (access(filename
, 0) && strlen(attrname
) > 2)
4806 * Wasn't able to find "ll_CC" locale file; try the non-national
4807 * localization banner directory.
4812 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
4816 if (access(filename
, 0))
4819 * Use the non-localized banner file.
4822 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
4825 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
4829 cupsdLogMessage(CUPSD_LOG_ERROR
,
4830 "Unable to open banner template file %s - %s",
4831 filename
, strerror(errno
));
4837 * Parse the file to the end...
4840 while ((ch
= cupsFileGetChar(in
)) != EOF
)
4844 * Get an attribute name...
4847 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
4848 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
4850 else if (s
< (attrname
+ sizeof(attrname
) - 1))
4860 * Ignore { followed by stuff that is not an attribute name...
4863 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
4868 * See if it is defined...
4871 if (attrname
[0] == '?')
4876 if (!strcmp(s
, "printer-name"))
4878 cupsFilePuts(out
, job
->dest
);
4881 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
4884 * See if we have a leading question mark...
4887 if (attrname
[0] != '?')
4890 * Nope, write to file as-is; probably a PostScript procedure...
4893 cupsFilePrintf(out
, "{%s}", attrname
);
4900 * Output value(s)...
4903 for (i
= 0; i
< attr
->num_values
; i
++)
4906 cupsFilePutChar(out
, ',');
4908 switch (attr
->value_tag
)
4910 case IPP_TAG_INTEGER
:
4912 if (!strncmp(s
, "time-at-", 8))
4914 struct timeval tv
= { attr
->values
[i
].integer
, 0 };
4915 cupsFilePuts(out
, cupsdGetDateTime(&tv
, CUPSD_TIME_STANDARD
));
4918 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
4921 case IPP_TAG_BOOLEAN
:
4922 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
4925 case IPP_TAG_NOVALUE
:
4926 cupsFilePuts(out
, "novalue");
4929 case IPP_TAG_RANGE
:
4930 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
4931 attr
->values
[i
].range
.upper
);
4934 case IPP_TAG_RESOLUTION
:
4935 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
4936 attr
->values
[i
].resolution
.yres
,
4937 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
4942 case IPP_TAG_STRING
:
4945 case IPP_TAG_KEYWORD
:
4946 case IPP_TAG_CHARSET
:
4947 case IPP_TAG_LANGUAGE
:
4948 if (!strcasecmp(banner
->filetype
->type
, "postscript"))
4951 * Need to quote strings for PS banners...
4956 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
4958 if (*p
== '(' || *p
== ')' || *p
== '\\')
4960 cupsFilePutChar(out
, '\\');
4961 cupsFilePutChar(out
, *p
);
4963 else if (*p
< 32 || *p
> 126)
4964 cupsFilePrintf(out
, "\\%03o", *p
& 255);
4966 cupsFilePutChar(out
, *p
);
4970 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
4974 break; /* anti-compiler-warning-code */
4978 else if (ch
== '\\') /* Quoted char */
4980 ch
= cupsFileGetChar(in
);
4982 if (ch
!= '{') /* Only do special handling for \{ */
4983 cupsFilePutChar(out
, '\\');
4985 cupsFilePutChar(out
, ch
);
4988 cupsFilePutChar(out
, ch
);
4992 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
4994 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
4995 IPP_TAG_INTEGER
)) != NULL
)
4996 attr
->values
[0].integer
+= kbytes
;
5005 * 'copy_file()' - Copy a PPD file or interface script...
5008 static int /* O - 0 = success, -1 = error */
5009 copy_file(const char *from
, /* I - Source file */
5010 const char *to
) /* I - Destination file */
5012 cups_file_t
*src
, /* Source file */
5013 *dst
; /* Destination file */
5014 int bytes
; /* Bytes to read/write */
5015 char buffer
[2048]; /* Copy buffer */
5018 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "copy_file(\"%s\", \"%s\")", from
, to
);
5021 * Open the source and destination file for a copy...
5024 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
5027 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
5034 * Copy the source file to the destination...
5037 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
5038 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
5046 * Close both files and return...
5051 return (cupsFileClose(dst
));
5056 * 'copy_model()' - Copy a PPD model file, substituting default values
5060 static int /* O - 0 = success, -1 = error */
5061 copy_model(cupsd_client_t
*con
, /* I - Client connection */
5062 const char *from
, /* I - Source file */
5063 const char *to
) /* I - Destination file */
5065 fd_set input
; /* select() input set */
5066 struct timeval timeout
; /* select() timeout */
5067 int maxfd
; /* Max file descriptor for select() */
5068 char tempfile
[1024]; /* Temporary PPD file */
5069 int tempfd
; /* Temporary PPD file descriptor */
5070 int temppid
; /* Process ID of cups-driverd */
5071 int temppipe
[2]; /* Temporary pipes */
5072 char *argv
[4], /* Command-line arguments */
5073 *envp
[MAX_ENV
]; /* Environment */
5074 cups_file_t
*src
, /* Source file */
5075 *dst
; /* Destination file */
5076 ppd_file_t
*ppd
; /* PPD file */
5077 int bytes
, /* Bytes from pipe */
5078 total
; /* Total bytes from pipe */
5079 char buffer
[2048]; /* Copy buffer */
5080 int i
; /* Looping var */
5081 char option
[PPD_MAX_NAME
], /* Option name */
5082 choice
[PPD_MAX_NAME
]; /* Choice name */
5083 int num_defaults
; /* Number of default options */
5084 cups_option_t
*defaults
; /* Default options */
5085 char cups_protocol
[PPD_MAX_LINE
];
5086 /* cupsProtocol attribute */
5089 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
5090 "copy_model(con=%p, from=\"%s\", to=\"%s\")",
5094 * Run cups-driverd to get the PPD file...
5097 argv
[0] = "cups-driverd";
5099 argv
[2] = (char *)from
;
5102 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
5104 snprintf(buffer
, sizeof(buffer
), "%s/daemon/cups-driverd", ServerBin
);
5105 snprintf(tempfile
, sizeof(tempfile
), "%s/%d.ppd", TempDir
, con
->http
.fd
);
5106 tempfd
= open(tempfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
5110 cupsdOpenPipe(temppipe
);
5112 cupsdLogMessage(CUPSD_LOG_DEBUG
,
5113 "copy_model: Running \"cups-driverd cat %s\"...", from
);
5115 if (!cupsdStartProcess(buffer
, argv
, envp
, -1, temppipe
[1], CGIPipes
[1],
5116 -1, -1, 0, DefaultProfile
, 0, &temppid
))
5127 * Wait up to 30 seconds for the PPD file to be copied...
5132 if (temppipe
[0] > CGIPipes
[0])
5133 maxfd
= temppipe
[0] + 1;
5135 maxfd
= CGIPipes
[0] + 1;
5140 * See if we have data ready...
5144 FD_SET(temppipe
[0], &input
);
5145 FD_SET(CGIPipes
[0], &input
);
5147 timeout
.tv_sec
= 30;
5148 timeout
.tv_usec
= 0;
5150 if ((i
= select(maxfd
, &input
, NULL
, NULL
, &timeout
)) < 0)
5160 * We have timed out...
5166 if (FD_ISSET(temppipe
[0], &input
))
5169 * Read the PPD file from the pipe, and write it to the PPD file.
5172 if ((bytes
= read(temppipe
[0], buffer
, sizeof(buffer
))) > 0)
5174 if (write(tempfd
, buffer
, bytes
) < bytes
)
5183 if (FD_ISSET(CGIPipes
[0], &input
))
5193 * No data from cups-deviced...
5196 cupsdLogMessage(CUPSD_LOG_ERROR
, "copy_model: empty PPD file!");
5202 * Read the source file and see what page sizes are supported...
5205 if ((ppd
= ppdOpenFile(tempfile
)) == NULL
)
5212 * Open the destination (if possible) and set the default options...
5217 cups_protocol
[0] = '\0';
5219 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
5222 * Read all of the default lines from the old PPD...
5225 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)))
5226 if (!strncmp(buffer
, "*Default", 8))
5229 * Add the default option...
5232 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
5233 choice
, sizeof(choice
)))
5235 ppd_option_t
*ppdo
; /* PPD option */
5239 * Only add the default if the default hasn't already been
5240 * set and the choice exists in the new PPD...
5243 if (!cupsGetOption(option
, num_defaults
, defaults
) &&
5244 (ppdo
= ppdFindOption(ppd
, option
)) != NULL
&&
5245 ppdFindChoice(ppdo
, choice
))
5246 num_defaults
= cupsAddOption(option
, choice
, num_defaults
,
5250 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
5251 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
5255 else if (ppdPageSize(ppd
, DefaultPaperSize
))
5258 * Add the default media sizes...
5261 num_defaults
= cupsAddOption("PageSize", DefaultPaperSize
,
5262 num_defaults
, &defaults
);
5263 num_defaults
= cupsAddOption("PageRegion", DefaultPaperSize
,
5264 num_defaults
, &defaults
);
5265 num_defaults
= cupsAddOption("PaperDimension", DefaultPaperSize
,
5266 num_defaults
, &defaults
);
5267 num_defaults
= cupsAddOption("ImageableArea", DefaultPaperSize
,
5268 num_defaults
, &defaults
);
5274 * Open the source file for a copy...
5277 if ((src
= cupsFileOpen(tempfile
, "rb")) == NULL
)
5279 cupsFreeOptions(num_defaults
, defaults
);
5285 * Open the destination file for a copy...
5288 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
5290 cupsFreeOptions(num_defaults
, defaults
);
5297 * Copy the source file to the destination...
5300 while (cupsFileGets(src
, buffer
, sizeof(buffer
)))
5302 if (!strncmp(buffer
, "*Default", 8))
5305 * Check for an previous default option choice...
5308 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
5309 choice
, sizeof(choice
)))
5311 const char *val
; /* Default option value */
5314 if ((val
= cupsGetOption(option
, num_defaults
, defaults
)) != NULL
)
5317 * Substitute the previous choice...
5320 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
, val
);
5325 cupsFilePrintf(dst
, "%s\n", buffer
);
5328 if (cups_protocol
[0])
5329 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
5331 cupsFreeOptions(num_defaults
, defaults
);
5334 * Close both files and return...
5341 return (cupsFileClose(dst
));
5346 * 'copy_job_attrs()' - Copy job attributes.
5350 copy_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
5351 cupsd_job_t
*job
, /* I - Job */
5352 cups_array_t
*ra
) /* I - Requested attributes array */
5354 char job_uri
[HTTP_MAX_URI
]; /* Job URI */
5358 * Send the requested attributes for each job...
5361 httpAssembleURIf(HTTP_URI_CODING_ALL
, job_uri
, sizeof(job_uri
), "ipp", NULL
,
5362 con
->servername
, con
->serverport
, "/jobs/%d",
5365 if (!ra
|| cupsArrayFind(ra
, "document-count"))
5366 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5367 "document-count", job
->num_files
);
5369 if (!ra
|| cupsArrayFind(ra
, "job-media-progress"))
5370 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5371 "job-media-progress", job
->progress
);
5373 if (!ra
|| cupsArrayFind(ra
, "job-more-info"))
5374 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
5375 "job-more-info", NULL
, job_uri
);
5377 if (job
->state_value
> IPP_JOB_PROCESSING
&&
5378 (!ra
|| cupsArrayFind(ra
, "job-preserved")))
5379 ippAddBoolean(con
->response
, IPP_TAG_JOB
, "job-preserved",
5380 job
->num_files
> 0);
5382 if (!ra
|| cupsArrayFind(ra
, "job-printer-up-time"))
5383 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5384 "job-printer-up-time", time(NULL
));
5386 if (!ra
|| cupsArrayFind(ra
, "job-state-reasons"))
5387 add_job_state_reasons(con
, job
);
5389 if (!ra
|| cupsArrayFind(ra
, "job-uri"))
5390 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
5391 "job-uri", NULL
, job_uri
);
5393 copy_attrs(con
->response
, job
->attrs
, ra
, IPP_TAG_JOB
, 0);
5398 * 'copy_printer_attrs()' - Copy printer attributes.
5403 cupsd_client_t
*con
, /* I - Client connection */
5404 cupsd_printer_t
*printer
, /* I - Printer */
5405 cups_array_t
*ra
) /* I - Requested attributes array */
5407 char printer_uri
[HTTP_MAX_URI
];
5409 time_t curtime
; /* Current time */
5410 int i
; /* Looping var */
5411 ipp_attribute_t
*history
; /* History collection */
5415 * Copy the printer attributes to the response using requested-attributes
5416 * and document-format attributes that may be provided by the client.
5419 curtime
= time(NULL
);
5422 if ((!ra
|| cupsArrayFind(ra
, "com.apple.print.recoverable-message")) &&
5423 printer
->recoverable
)
5424 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
5425 "com.apple.print.recoverable-message", NULL
,
5426 printer
->recoverable
);
5427 #endif /* __APPLE__ */
5429 if (!ra
|| cupsArrayFind(ra
, "marker-change-time"))
5430 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
5431 "marker-change-time", printer
->marker_time
);
5433 if (printer
->num_printers
> 0 &&
5434 (!ra
|| cupsArrayFind(ra
, "member-uris")))
5436 ipp_attribute_t
*member_uris
; /* member-uris attribute */
5437 cupsd_printer_t
*p2
; /* Printer in class */
5438 ipp_attribute_t
*p2_uri
; /* printer-uri-supported for class printer */
5441 if ((member_uris
= ippAddStrings(con
->response
, IPP_TAG_PRINTER
,
5442 IPP_TAG_URI
, "member-uris",
5443 printer
->num_printers
, NULL
,
5446 for (i
= 0; i
< printer
->num_printers
; i
++)
5448 p2
= printer
->printers
[i
];
5450 if ((p2_uri
= ippFindAttribute(p2
->attrs
, "printer-uri-supported",
5451 IPP_TAG_URI
)) != NULL
)
5452 member_uris
->values
[i
].string
.text
=
5453 _cupsStrRetain(p2_uri
->values
[0].string
.text
);
5456 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
,
5457 sizeof(printer_uri
), "ipp", NULL
, con
->servername
,
5459 (p2
->type
& CUPS_PRINTER_CLASS
) ?
5460 "/classes/%s" : "/printers/%s", p2
->name
);
5461 member_uris
->values
[i
].string
.text
= _cupsStrAlloc(printer_uri
);
5467 if (printer
->alert
&& (!ra
|| cupsArrayFind(ra
, "printer-alert")))
5468 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_STRING
,
5469 "printer-alert", NULL
, printer
->alert
);
5471 if (printer
->alert_description
&&
5472 (!ra
|| cupsArrayFind(ra
, "printer-alert-description")))
5473 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
5474 "printer-alert-description", NULL
,
5475 printer
->alert_description
);
5477 if (!ra
|| cupsArrayFind(ra
, "printer-current-time"))
5478 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
5479 ippTimeToDate(curtime
));
5482 if (!ra
|| cupsArrayFind(ra
, "printer-dns-sd-name"))
5484 if (printer
->reg_name
)
5485 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
5486 "printer-dns-sd-name", NULL
, printer
->reg_name
);
5488 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NOVALUE
,
5489 "printer-dns-sd-name", 0);
5491 #endif /* HAVE_DNSSD */
5493 if (!ra
|| cupsArrayFind(ra
, "printer-error-policy"))
5494 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
5495 "printer-error-policy", NULL
, printer
->error_policy
);
5497 if (!ra
|| cupsArrayFind(ra
, "printer-is-accepting-jobs"))
5498 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
5499 printer
->accepting
);
5501 if (!ra
|| cupsArrayFind(ra
, "printer-is-shared"))
5502 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
5505 if ((!ra
|| cupsArrayFind(ra
, "printer-more-info")) &&
5506 !(printer
->type
& CUPS_PRINTER_DISCOVERED
))
5508 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
),
5509 "http", NULL
, con
->servername
, con
->serverport
,
5510 (printer
->type
& CUPS_PRINTER_CLASS
) ?
5511 "/classes/%s" : "/printers/%s", printer
->name
);
5512 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
5513 "printer-more-info", NULL
, printer_uri
);
5516 if (!ra
|| cupsArrayFind(ra
, "printer-op-policy"))
5517 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
5518 "printer-op-policy", NULL
, printer
->op_policy
);
5520 if (!ra
|| cupsArrayFind(ra
, "printer-state"))
5521 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
5524 if (!ra
|| cupsArrayFind(ra
, "printer-state-change-time"))
5525 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
5526 "printer-state-change-time", printer
->state_time
);
5528 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 &&
5529 cupsArrayFind(ra
, "printer-state-history"))
5532 * Printer history is only sent if specifically requested, so that
5533 * older CUPS/IPP clients won't barf on the collection attributes.
5536 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
5537 "printer-state-history",
5538 printer
->num_history
, NULL
);
5540 for (i
= 0; i
< printer
->num_history
; i
++)
5541 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
5542 NULL
, IPP_TAG_ZERO
, 0);
5545 if (!ra
|| cupsArrayFind(ra
, "printer-state-message"))
5546 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
5547 "printer-state-message", NULL
, printer
->state_message
);
5549 if (!ra
|| cupsArrayFind(ra
, "printer-state-reasons"))
5550 add_printer_state_reasons(con
, printer
);
5552 if (!ra
|| cupsArrayFind(ra
, "printer-type"))
5554 int type
; /* printer-type value */
5558 * Add the CUPS-specific printer-type attribute...
5561 type
= printer
->type
;
5563 if (printer
== DefaultPrinter
)
5564 type
|= CUPS_PRINTER_DEFAULT
;
5566 if (!printer
->accepting
)
5567 type
|= CUPS_PRINTER_REJECTING
;
5569 if (!printer
->shared
)
5570 type
|= CUPS_PRINTER_NOT_SHARED
;
5572 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-type",
5576 if (!ra
|| cupsArrayFind(ra
, "printer-up-time"))
5577 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
5578 "printer-up-time", curtime
);
5580 if ((!ra
|| cupsArrayFind(ra
, "printer-uri-supported")) &&
5581 !(printer
->type
& CUPS_PRINTER_DISCOVERED
))
5583 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
),
5584 "ipp", NULL
, con
->servername
, con
->serverport
,
5585 (printer
->type
& CUPS_PRINTER_CLASS
) ?
5586 "/classes/%s" : "/printers/%s", printer
->name
);
5587 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
5588 "printer-uri-supported", NULL
, printer_uri
);
5589 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "printer-uri-supported=\"%s\"",
5593 if (!ra
|| cupsArrayFind(ra
, "queued-job-count"))
5594 add_queued_job_count(con
, printer
);
5596 copy_attrs(con
->response
, printer
->attrs
, ra
, IPP_TAG_ZERO
, 0);
5597 if (printer
->ppd_attrs
)
5598 copy_attrs(con
->response
, printer
->ppd_attrs
, ra
, IPP_TAG_ZERO
, 0);
5599 copy_attrs(con
->response
, CommonData
, ra
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
5604 * 'copy_subscription_attrs()' - Copy subscription attributes.
5608 copy_subscription_attrs(
5609 cupsd_client_t
*con
, /* I - Client connection */
5610 cupsd_subscription_t
*sub
, /* I - Subscription */
5611 cups_array_t
*ra
) /* I - Requested attributes array */
5613 ipp_attribute_t
*attr
; /* Current attribute */
5614 char printer_uri
[HTTP_MAX_URI
];
5616 int count
; /* Number of events */
5617 unsigned mask
; /* Current event mask */
5618 const char *name
; /* Current event name */
5622 * Copy the subscription attributes to the response using the
5623 * requested-attributes attribute that may be provided by the client.
5626 if (!ra
|| cupsArrayFind(ra
, "notify-events"))
5628 if ((name
= cupsdEventName((cupsd_eventmask_t
)sub
->mask
)) != NULL
)
5631 * Simple event list...
5634 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
,
5635 (ipp_tag_t
)(IPP_TAG_KEYWORD
| IPP_TAG_COPY
),
5636 "notify-events", NULL
, name
);
5641 * Complex event list...
5644 for (mask
= 1, count
= 0; mask
< CUPSD_EVENT_ALL
; mask
<<= 1)
5645 if (sub
->mask
& mask
)
5648 attr
= ippAddStrings(con
->response
, IPP_TAG_SUBSCRIPTION
,
5649 (ipp_tag_t
)(IPP_TAG_KEYWORD
| IPP_TAG_COPY
),
5650 "notify-events", count
, NULL
, NULL
);
5652 for (mask
= 1, count
= 0; mask
< CUPSD_EVENT_ALL
; mask
<<= 1)
5653 if (sub
->mask
& mask
)
5655 attr
->values
[count
].string
.text
=
5656 (char *)cupsdEventName((cupsd_eventmask_t
)mask
);
5663 if (sub
->job
&& (!ra
|| cupsArrayFind(ra
, "notify-job-id")))
5664 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
5665 "notify-job-id", sub
->job
->id
);
5667 if (!sub
->job
&& (!ra
|| cupsArrayFind(ra
, "notify-lease-duration")))
5668 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
5669 "notify-lease-duration", sub
->lease
);
5671 if (sub
->dest
&& (!ra
|| cupsArrayFind(ra
, "notify-printer-uri")))
5673 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
),
5674 "ipp", NULL
, con
->servername
, con
->serverport
,
5675 "/printers/%s", sub
->dest
->name
);
5676 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
5677 "notify-printer-uri", NULL
, printer_uri
);
5680 if (sub
->recipient
&& (!ra
|| cupsArrayFind(ra
, "notify-recipient-uri")))
5681 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
5682 "notify-recipient-uri", NULL
, sub
->recipient
);
5683 else if (!ra
|| cupsArrayFind(ra
, "notify-pull-method"))
5684 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
,
5685 "notify-pull-method", NULL
, "ippget");
5687 if (!ra
|| cupsArrayFind(ra
, "notify-subscriber-user-name"))
5688 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_NAME
,
5689 "notify-subscriber-user-name", NULL
, sub
->owner
);
5691 if (!ra
|| cupsArrayFind(ra
, "notify-subscription-id"))
5692 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
5693 "notify-subscription-id", sub
->id
);
5695 if (!ra
|| cupsArrayFind(ra
, "notify-time-interval"))
5696 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
5697 "notify-time-interval", sub
->interval
);
5699 if (sub
->user_data_len
> 0 && (!ra
|| cupsArrayFind(ra
, "notify-user-data")))
5700 ippAddOctetString(con
->response
, IPP_TAG_SUBSCRIPTION
, "notify-user-data",
5701 sub
->user_data
, sub
->user_data_len
);
5706 * 'create_job()' - Print a file to a printer or class.
5710 create_job(cupsd_client_t
*con
, /* I - Client connection */
5711 ipp_attribute_t
*uri
) /* I - Printer URI */
5713 cupsd_printer_t
*printer
; /* Printer */
5714 cupsd_job_t
*job
; /* New job */
5717 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "create_job(%p[%d], %s)", con
,
5718 con
->http
.fd
, uri
->values
[0].string
.text
);
5721 * Is the destination valid?
5724 if (!cupsdValidateDest(uri
->values
[0].string
.text
, NULL
, &printer
))
5730 send_ipp_status(con
, IPP_NOT_FOUND
,
5731 _("The printer or class was not found."));
5736 * Create the job object...
5739 if ((job
= add_job(con
, printer
, NULL
)) == NULL
)
5742 job
->pending_timeout
= 1;
5745 * Save and log the job...
5748 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Queued on \"%s\" by \"%s\".",
5749 job
->dest
, job
->username
);
5754 * 'create_requested_array()' - Create an array for the requested-attributes.
5757 static cups_array_t
* /* O - Array of attributes or NULL */
5758 create_requested_array(ipp_t
*request
) /* I - IPP request */
5760 int i
; /* Looping var */
5761 ipp_attribute_t
*requested
; /* requested-attributes attribute */
5762 cups_array_t
*ra
; /* Requested attributes array */
5763 char *value
; /* Current value */
5767 * Get the requested-attributes attribute, and return NULL if we don't
5771 if ((requested
= ippFindAttribute(request
, "requested-attributes",
5772 IPP_TAG_KEYWORD
)) == NULL
)
5776 * If the attribute contains a single "all" keyword, return NULL...
5779 if (requested
->num_values
== 1 &&
5780 !strcmp(requested
->values
[0].string
.text
, "all"))
5784 * Create an array using "strcmp" as the comparison function...
5787 ra
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
5789 for (i
= 0; i
< requested
->num_values
; i
++)
5791 value
= requested
->values
[i
].string
.text
;
5793 if (!strcmp(value
, "job-template"))
5795 cupsArrayAdd(ra
, "copies");
5796 cupsArrayAdd(ra
, "copies-default");
5797 cupsArrayAdd(ra
, "copies-supported");
5798 cupsArrayAdd(ra
, "finishings");
5799 cupsArrayAdd(ra
, "finishings-default");
5800 cupsArrayAdd(ra
, "finishings-supported");
5801 cupsArrayAdd(ra
, "job-hold-until");
5802 cupsArrayAdd(ra
, "job-hold-until-default");
5803 cupsArrayAdd(ra
, "job-hold-until-supported");
5804 cupsArrayAdd(ra
, "job-priority");
5805 cupsArrayAdd(ra
, "job-priority-default");
5806 cupsArrayAdd(ra
, "job-priority-supported");
5807 cupsArrayAdd(ra
, "job-sheets");
5808 cupsArrayAdd(ra
, "job-sheets-default");
5809 cupsArrayAdd(ra
, "job-sheets-supported");
5810 cupsArrayAdd(ra
, "media");
5811 cupsArrayAdd(ra
, "media-default");
5812 cupsArrayAdd(ra
, "media-supported");
5813 cupsArrayAdd(ra
, "multiple-document-handling");
5814 cupsArrayAdd(ra
, "multiple-document-handling-default");
5815 cupsArrayAdd(ra
, "multiple-document-handling-supported");
5816 cupsArrayAdd(ra
, "number-up");
5817 cupsArrayAdd(ra
, "number-up-default");
5818 cupsArrayAdd(ra
, "number-up-supported");
5819 cupsArrayAdd(ra
, "orientation-requested");
5820 cupsArrayAdd(ra
, "orientation-requested-default");
5821 cupsArrayAdd(ra
, "orientation-requested-supported");
5822 cupsArrayAdd(ra
, "page-ranges");
5823 cupsArrayAdd(ra
, "page-ranges-supported");
5824 cupsArrayAdd(ra
, "printer-resolution");
5825 cupsArrayAdd(ra
, "printer-resolution-default");
5826 cupsArrayAdd(ra
, "printer-resolution-supported");
5827 cupsArrayAdd(ra
, "print-quality");
5828 cupsArrayAdd(ra
, "print-quality-default");
5829 cupsArrayAdd(ra
, "print-quality-supported");
5830 cupsArrayAdd(ra
, "sides");
5831 cupsArrayAdd(ra
, "sides-default");
5832 cupsArrayAdd(ra
, "sides-supported");
5834 else if (!strcmp(value
, "job-description"))
5836 cupsArrayAdd(ra
, "date-time-at-completed");
5837 cupsArrayAdd(ra
, "date-time-at-creation");
5838 cupsArrayAdd(ra
, "date-time-at-processing");
5839 cupsArrayAdd(ra
, "job-detailed-status-message");
5840 cupsArrayAdd(ra
, "job-document-access-errors");
5841 cupsArrayAdd(ra
, "job-id");
5842 cupsArrayAdd(ra
, "job-impressions");
5843 cupsArrayAdd(ra
, "job-impressions-completed");
5844 cupsArrayAdd(ra
, "job-k-octets");
5845 cupsArrayAdd(ra
, "job-k-octets-processed");
5846 cupsArrayAdd(ra
, "job-media-progress");
5847 cupsArrayAdd(ra
, "job-media-sheets");
5848 cupsArrayAdd(ra
, "job-media-sheets-completed");
5849 cupsArrayAdd(ra
, "job-message-from-operator");
5850 cupsArrayAdd(ra
, "job-more-info");
5851 cupsArrayAdd(ra
, "job-name");
5852 cupsArrayAdd(ra
, "job-originating-user-name");
5853 cupsArrayAdd(ra
, "job-printer-up-time");
5854 cupsArrayAdd(ra
, "job-printer-uri");
5855 cupsArrayAdd(ra
, "job-state");
5856 cupsArrayAdd(ra
, "job-state-message");
5857 cupsArrayAdd(ra
, "job-state-reasons");
5858 cupsArrayAdd(ra
, "job-uri");
5859 cupsArrayAdd(ra
, "number-of-documents");
5860 cupsArrayAdd(ra
, "number-of-intervening-jobs");
5861 cupsArrayAdd(ra
, "output-device-assigned");
5862 cupsArrayAdd(ra
, "time-at-completed");
5863 cupsArrayAdd(ra
, "time-at-creation");
5864 cupsArrayAdd(ra
, "time-at-processing");
5866 else if (!strcmp(value
, "printer-description"))
5868 cupsArrayAdd(ra
, "charset-configured");
5869 cupsArrayAdd(ra
, "charset-supported");
5870 cupsArrayAdd(ra
, "color-supported");
5871 cupsArrayAdd(ra
, "compression-supported");
5872 cupsArrayAdd(ra
, "document-format-default");
5873 cupsArrayAdd(ra
, "document-format-supported");
5874 cupsArrayAdd(ra
, "generated-natural-language-supported");
5875 cupsArrayAdd(ra
, "ipp-versions-supported");
5876 cupsArrayAdd(ra
, "job-impressions-supported");
5877 cupsArrayAdd(ra
, "job-k-octets-supported");
5878 cupsArrayAdd(ra
, "job-media-sheets-supported");
5879 cupsArrayAdd(ra
, "job-settable-attributes-supported");
5880 cupsArrayAdd(ra
, "multiple-document-jobs-supported");
5881 cupsArrayAdd(ra
, "multiple-operation-time-out");
5882 cupsArrayAdd(ra
, "natural-language-configured");
5883 cupsArrayAdd(ra
, "notify-attributes-supported");
5884 cupsArrayAdd(ra
, "notify-lease-duration-default");
5885 cupsArrayAdd(ra
, "notify-lease-duration-supported");
5886 cupsArrayAdd(ra
, "notify-max-events-supported");
5887 cupsArrayAdd(ra
, "notify-events-default");
5888 cupsArrayAdd(ra
, "notify-events-supported");
5889 cupsArrayAdd(ra
, "notify-pull-method-supported");
5890 cupsArrayAdd(ra
, "notify-schemes-supported");
5891 cupsArrayAdd(ra
, "operations-supported");
5892 cupsArrayAdd(ra
, "pages-per-minute");
5893 cupsArrayAdd(ra
, "pages-per-minute-color");
5894 cupsArrayAdd(ra
, "pdl-override-supported");
5895 cupsArrayAdd(ra
, "printer-alert");
5896 cupsArrayAdd(ra
, "printer-alert-description");
5897 cupsArrayAdd(ra
, "printer-commands");
5898 cupsArrayAdd(ra
, "printer-current-time");
5899 cupsArrayAdd(ra
, "printer-driver-installer");
5900 cupsArrayAdd(ra
, "printer-dns-sd-name");
5901 cupsArrayAdd(ra
, "printer-info");
5902 cupsArrayAdd(ra
, "printer-is-accepting-jobs");
5903 cupsArrayAdd(ra
, "printer-location");
5904 cupsArrayAdd(ra
, "printer-make-and-model");
5905 cupsArrayAdd(ra
, "printer-message-from-operator");
5906 cupsArrayAdd(ra
, "printer-more-info");
5907 cupsArrayAdd(ra
, "printer-more-info-manufacturer");
5908 cupsArrayAdd(ra
, "printer-name");
5909 cupsArrayAdd(ra
, "printer-state");
5910 cupsArrayAdd(ra
, "printer-state-message");
5911 cupsArrayAdd(ra
, "printer-state-reasons");
5912 cupsArrayAdd(ra
, "printer-settable-attributes-supported");
5913 cupsArrayAdd(ra
, "printer-type");
5914 cupsArrayAdd(ra
, "printer-up-time");
5915 cupsArrayAdd(ra
, "printer-uri-supported");
5916 cupsArrayAdd(ra
, "queued-job-count");
5917 cupsArrayAdd(ra
, "reference-uri-schemes-supported");
5918 cupsArrayAdd(ra
, "uri-authentication-supported");
5919 cupsArrayAdd(ra
, "uri-security-supported");
5921 else if (!strcmp(value
, "printer-defaults"))
5923 char *name
; /* Option name */
5926 for (name
= (char *)cupsArrayFirst(CommonDefaults
);
5928 name
= (char *)cupsArrayNext(CommonDefaults
))
5929 cupsArrayAdd(ra
, name
);
5931 else if (!strcmp(value
, "subscription-template"))
5933 cupsArrayAdd(ra
, "notify-attributes");
5934 cupsArrayAdd(ra
, "notify-charset");
5935 cupsArrayAdd(ra
, "notify-events");
5936 cupsArrayAdd(ra
, "notify-lease-duration");
5937 cupsArrayAdd(ra
, "notify-natural-language");
5938 cupsArrayAdd(ra
, "notify-pull-method");
5939 cupsArrayAdd(ra
, "notify-recipient-uri");
5940 cupsArrayAdd(ra
, "notify-time-interval");
5941 cupsArrayAdd(ra
, "notify-user-data");
5944 cupsArrayAdd(ra
, value
);
5952 * 'create_subscription()' - Create a notification subscription.
5956 create_subscription(
5957 cupsd_client_t
*con
, /* I - Client connection */
5958 ipp_attribute_t
*uri
) /* I - Printer URI */
5960 http_status_t status
; /* Policy status */
5961 int i
; /* Looping var */
5962 ipp_attribute_t
*attr
; /* Current attribute */
5963 cups_ptype_t dtype
; /* Destination type (printer/class) */
5964 char scheme
[HTTP_MAX_URI
],
5965 /* Scheme portion of URI */
5966 userpass
[HTTP_MAX_URI
],
5967 /* Username portion of URI */
5969 /* Host portion of URI */
5970 resource
[HTTP_MAX_URI
];
5971 /* Resource portion of URI */
5972 int port
; /* Port portion of URI */
5973 cupsd_printer_t
*printer
; /* Printer/class */
5974 cupsd_job_t
*job
; /* Job */
5975 int jobid
; /* Job ID */
5976 cupsd_subscription_t
*sub
; /* Subscription object */
5977 const char *username
, /* requesting-user-name or
5978 authenticated username */
5979 *recipient
, /* notify-recipient-uri */
5980 *pullmethod
; /* notify-pull-method */
5981 ipp_attribute_t
*user_data
; /* notify-user-data */
5982 int interval
, /* notify-time-interval */
5983 lease
; /* notify-lease-duration */
5984 unsigned mask
; /* notify-events */
5985 ipp_attribute_t
*notify_events
,/* notify-events(-default) */
5986 *notify_lease
; /* notify-lease-duration(-default) */
5990 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
5992 if (attr
->group_tag
!= IPP_TAG_ZERO
)
5993 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "g%04x v%04x %s", attr
->group_tag
,
5994 attr
->value_tag
, attr
->name
);
5996 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "----SEP----");
6001 * Is the destination valid?
6004 cupsdLogMessage(CUPSD_LOG_DEBUG
,
6005 "cupsdCreateSubscription(con=%p(%d), uri=\"%s\")",
6006 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
6008 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
6009 sizeof(scheme
), userpass
, sizeof(userpass
), host
,
6010 sizeof(host
), &port
, resource
, sizeof(resource
));
6012 if (!strcmp(resource
, "/"))
6014 dtype
= (cups_ptype_t
)0;
6017 else if (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10)
6019 dtype
= (cups_ptype_t
)0;
6022 else if (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9)
6024 dtype
= CUPS_PRINTER_CLASS
;
6027 else if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
6033 send_ipp_status(con
, IPP_NOT_FOUND
,
6034 _("The printer or class was not found."));
6044 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
,
6047 send_http_error(con
, status
, printer
);
6051 else if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6053 send_http_error(con
, status
, NULL
);
6058 * Get the user that is requesting the subscription...
6061 username
= get_username(con
);
6064 * Find the first subscription group attribute; return if we have
6068 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
6069 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
6074 send_ipp_status(con
, IPP_BAD_REQUEST
,
6075 _("No subscription attributes in request!"));
6080 * Process the subscription attributes in the request...
6083 con
->response
->request
.status
.status_code
= IPP_BAD_REQUEST
;
6091 lease
= DefaultLeaseDuration
;
6093 mask
= CUPSD_EVENT_NONE
;
6097 notify_events
= ippFindAttribute(printer
->attrs
, "notify-events-default",
6099 notify_lease
= ippFindAttribute(printer
->attrs
,
6100 "notify-lease-duration-default",
6104 lease
= notify_lease
->values
[0].integer
;
6108 notify_events
= NULL
;
6109 notify_lease
= NULL
;
6112 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
6114 if (!strcmp(attr
->name
, "notify-recipient-uri") &&
6115 attr
->value_tag
== IPP_TAG_URI
)
6118 * Validate the recipient scheme against the ServerBin/notifier
6122 char notifier
[1024]; /* Notifier filename */
6125 recipient
= attr
->values
[0].string
.text
;
6127 if (httpSeparateURI(HTTP_URI_CODING_ALL
, recipient
,
6128 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
6129 host
, sizeof(host
), &port
,
6130 resource
, sizeof(resource
)) < HTTP_URI_OK
)
6132 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
6133 _("Bad notify-recipient-uri URI \"%s\"!"), recipient
);
6134 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
6135 "notify-status-code", IPP_URI_SCHEME
);
6139 snprintf(notifier
, sizeof(notifier
), "%s/notifier/%s", ServerBin
,
6141 if (access(notifier
, X_OK
))
6143 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
6144 _("notify-recipient-uri URI \"%s\" uses unknown "
6145 "scheme!"), recipient
);
6146 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
6147 "notify-status-code", IPP_URI_SCHEME
);
6151 if (!strcmp(scheme
, "rss") && !check_rss_recipient(recipient
))
6153 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
6154 _("notify-recipient-uri URI \"%s\" is already used!"),
6156 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
6157 "notify-status-code", IPP_ATTRIBUTES
);
6161 else if (!strcmp(attr
->name
, "notify-pull-method") &&
6162 attr
->value_tag
== IPP_TAG_KEYWORD
)
6164 pullmethod
= attr
->values
[0].string
.text
;
6166 if (strcmp(pullmethod
, "ippget"))
6168 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
6169 _("Bad notify-pull-method \"%s\"!"), pullmethod
);
6170 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
6171 "notify-status-code", IPP_ATTRIBUTES
);
6175 else if (!strcmp(attr
->name
, "notify-charset") &&
6176 attr
->value_tag
== IPP_TAG_CHARSET
&&
6177 strcmp(attr
->values
[0].string
.text
, "us-ascii") &&
6178 strcmp(attr
->values
[0].string
.text
, "utf-8"))
6180 send_ipp_status(con
, IPP_CHARSET
,
6181 _("Character set \"%s\" not supported!"),
6182 attr
->values
[0].string
.text
);
6185 else if (!strcmp(attr
->name
, "notify-natural-language") &&
6186 (attr
->value_tag
!= IPP_TAG_LANGUAGE
||
6187 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
)))
6189 send_ipp_status(con
, IPP_CHARSET
,
6190 _("Language \"%s\" not supported!"),
6191 attr
->values
[0].string
.text
);
6194 else if (!strcmp(attr
->name
, "notify-user-data") &&
6195 attr
->value_tag
== IPP_TAG_STRING
)
6197 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
6199 send_ipp_status(con
, IPP_REQUEST_VALUE
,
6200 _("The notify-user-data value is too large "
6201 "(%d > 63 octets)!"),
6202 attr
->values
[0].unknown
.length
);
6208 else if (!strcmp(attr
->name
, "notify-events") &&
6209 attr
->value_tag
== IPP_TAG_KEYWORD
)
6210 notify_events
= attr
;
6211 else if (!strcmp(attr
->name
, "notify-lease-duration") &&
6212 attr
->value_tag
== IPP_TAG_INTEGER
)
6213 lease
= attr
->values
[0].integer
;
6214 else if (!strcmp(attr
->name
, "notify-time-interval") &&
6215 attr
->value_tag
== IPP_TAG_INTEGER
)
6216 interval
= attr
->values
[0].integer
;
6217 else if (!strcmp(attr
->name
, "notify-job-id") &&
6218 attr
->value_tag
== IPP_TAG_INTEGER
)
6219 jobid
= attr
->values
[0].integer
;
6226 for (i
= 0; i
< notify_events
->num_values
; i
++)
6227 mask
|= cupsdEventValue(notify_events
->values
[i
].string
.text
);
6231 cupsdLogMessage(CUPSD_LOG_DEBUG
, "recipient=\"%s\"", recipient
);
6233 cupsdLogMessage(CUPSD_LOG_DEBUG
, "pullmethod=\"%s\"", pullmethod
);
6234 cupsdLogMessage(CUPSD_LOG_DEBUG
, "notify-lease-duration=%d", lease
);
6235 cupsdLogMessage(CUPSD_LOG_DEBUG
, "notify-time-interval=%d", interval
);
6237 if (!recipient
&& !pullmethod
)
6240 if (mask
== CUPSD_EVENT_NONE
)
6243 mask
= CUPSD_EVENT_JOB_COMPLETED
;
6245 mask
= CUPSD_EVENT_PRINTER_STATE_CHANGED
;
6248 send_ipp_status(con
, IPP_BAD_REQUEST
,
6249 _("notify-events not specified!"));
6254 if (MaxLeaseDuration
&& (lease
== 0 || lease
> MaxLeaseDuration
))
6256 cupsdLogMessage(CUPSD_LOG_INFO
,
6257 "create_subscription: Limiting notify-lease-duration to "
6260 lease
= MaxLeaseDuration
;
6265 if ((job
= cupsdFindJob(jobid
)) == NULL
)
6267 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job %d not found!"), jobid
);
6274 if ((sub
= cupsdAddSubscription(mask
, printer
, job
, recipient
, 0)) == NULL
)
6276 send_ipp_status(con
, IPP_TOO_MANY_SUBSCRIPTIONS
,
6277 _("There are too many subscriptions."));
6282 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added subscription %d for job %d",
6285 cupsdLogMessage(CUPSD_LOG_DEBUG
,
6286 "Added subscription %d for printer \"%s\"",
6287 sub
->id
, printer
->name
);
6289 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added subscription %d for server",
6292 sub
->interval
= interval
;
6294 sub
->expire
= lease
? time(NULL
) + lease
: 0;
6296 cupsdSetString(&sub
->owner
, username
);
6300 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
6301 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
6302 sub
->user_data_len
);
6305 ippAddSeparator(con
->response
);
6306 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
6307 "notify-subscription-id", sub
->id
);
6309 con
->response
->request
.status
.status_code
= IPP_OK
;
6315 cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS
);
6320 * 'delete_printer()' - Remove a printer or class from the system.
6324 delete_printer(cupsd_client_t
*con
, /* I - Client connection */
6325 ipp_attribute_t
*uri
) /* I - URI of printer or class */
6327 http_status_t status
; /* Policy status */
6328 cups_ptype_t dtype
; /* Destination type (printer/class) */
6329 cupsd_printer_t
*printer
; /* Printer/class */
6330 char filename
[1024]; /* Script/PPD filename */
6333 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "delete_printer(%p[%d], %s)", con
,
6334 con
->http
.fd
, uri
->values
[0].string
.text
);
6337 * Do we have a valid URI?
6340 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
6346 send_ipp_status(con
, IPP_NOT_FOUND
,
6347 _("The printer or class was not found."));
6355 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6357 send_http_error(con
, status
, NULL
);
6362 * Remove old jobs...
6365 cupsdCancelJobs(printer
->name
, NULL
, 1);
6368 * Remove old subscriptions and send a "deleted printer" event...
6371 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
6372 "%s \"%s\" deleted by \"%s\".",
6373 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
6374 printer
->name
, get_username(con
));
6376 cupsdExpireSubscriptions(printer
, NULL
);
6379 * Remove any old PPD or script files...
6382 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
,
6386 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
,
6390 snprintf(filename
, sizeof(filename
), "%s/%s.ipp", CacheDir
, printer
->name
);
6395 * Unregister color profiles...
6398 apple_unregister_profiles(printer
);
6399 #endif /* __APPLE__ */
6401 if (dtype
& CUPS_PRINTER_CLASS
)
6403 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" deleted by \"%s\".",
6404 printer
->name
, get_username(con
));
6406 cupsdDeletePrinter(printer
, 0);
6407 cupsdMarkDirty(CUPSD_DIRTY_CLASSES
);
6411 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" deleted by \"%s\".",
6412 printer
->name
, get_username(con
));
6414 cupsdDeletePrinter(printer
, 0);
6415 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
);
6418 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
);
6421 * Return with no errors...
6424 con
->response
->request
.status
.status_code
= IPP_OK
;
6429 * 'get_default()' - Get the default destination.
6433 get_default(cupsd_client_t
*con
) /* I - Client connection */
6435 http_status_t status
; /* Policy status */
6436 cups_array_t
*ra
; /* Requested attributes array */
6439 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_default(%p[%d])", con
, con
->http
.fd
);
6445 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6447 send_http_error(con
, status
, NULL
);
6453 ra
= create_requested_array(con
->request
);
6455 copy_printer_attrs(con
, DefaultPrinter
, ra
);
6457 cupsArrayDelete(ra
);
6459 con
->response
->request
.status
.status_code
= IPP_OK
;
6462 send_ipp_status(con
, IPP_NOT_FOUND
, _("No default printer"));
6467 * 'get_devices()' - Get the list of available devices on the local system.
6471 get_devices(cupsd_client_t
*con
) /* I - Client connection */
6473 http_status_t status
; /* Policy status */
6474 ipp_attribute_t
*limit
, /* limit attribute */
6475 *timeout
, /* timeout attribute */
6476 *requested
, /* requested-attributes attribute */
6477 *exclude
, /* exclude-schemes attribute */
6478 *include
; /* include-schemes attribute */
6479 char command
[1024], /* cups-deviced command */
6480 options
[2048], /* Options to pass to command */
6482 /* String for requested attributes */
6484 /* String for excluded schemes */
6486 /* String for included schemes */
6489 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_devices(%p[%d])", con
, con
->http
.fd
);
6495 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6497 send_http_error(con
, status
, NULL
);
6502 * Run cups-deviced command with the given options...
6505 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
6506 timeout
= ippFindAttribute(con
->request
, "timeout", IPP_TAG_INTEGER
);
6507 requested
= ippFindAttribute(con
->request
, "requested-attributes",
6509 exclude
= ippFindAttribute(con
->request
, "exclude-schemes", IPP_TAG_NAME
);
6510 include
= ippFindAttribute(con
->request
, "include-schemes", IPP_TAG_NAME
);
6513 url_encode_attr(requested
, requested_str
, sizeof(requested_str
));
6515 strlcpy(requested_str
, "requested-attributes=all", sizeof(requested_str
));
6518 url_encode_attr(exclude
, exclude_str
, sizeof(exclude_str
));
6520 exclude_str
[0] = '\0';
6523 url_encode_attr(include
, include_str
, sizeof(include_str
));
6525 include_str
[0] = '\0';
6527 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
6528 snprintf(options
, sizeof(options
),
6529 "%d+%d+%d+%d+%s%s%s%s%s",
6530 con
->request
->request
.op
.request_id
,
6531 limit
? limit
->values
[0].integer
: 0,
6532 timeout
? timeout
->values
[0].integer
: 10,
6535 exclude_str
[0] ? "%20" : "", exclude_str
,
6536 include_str
[0] ? "%20" : "", include_str
);
6538 if (cupsdSendCommand(con
, command
, options
, 1))
6541 * Command started successfully, don't send an IPP response here...
6544 ippDelete(con
->response
);
6545 con
->response
= NULL
;
6550 * Command failed, return "internal error" so the user knows something
6554 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
6555 _("cups-deviced failed to execute."));
6561 * 'get_document()' - Get a copy of a job file.
6565 get_document(cupsd_client_t
*con
, /* I - Client connection */
6566 ipp_attribute_t
*uri
) /* I - Job URI */
6568 http_status_t status
; /* Policy status */
6569 ipp_attribute_t
*attr
; /* Current attribute */
6570 int jobid
; /* Job ID */
6571 int docnum
; /* Document number */
6572 cupsd_job_t
*job
; /* Current job */
6573 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
6574 username
[HTTP_MAX_URI
], /* Username portion of URI */
6575 host
[HTTP_MAX_URI
], /* Host portion of URI */
6576 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6577 int port
; /* Port portion of URI */
6578 char filename
[1024], /* Filename for document */
6579 format
[1024]; /* Format for document */
6582 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_document(%p[%d], %s)", con
,
6583 con
->http
.fd
, uri
->values
[0].string
.text
);
6586 * See if we have a job URI or a printer URI...
6589 if (!strcmp(uri
->name
, "printer-uri"))
6592 * Got a printer URI; see if we also have a job-id attribute...
6595 if ((attr
= ippFindAttribute(con
->request
, "job-id",
6596 IPP_TAG_INTEGER
)) == NULL
)
6598 send_ipp_status(con
, IPP_BAD_REQUEST
,
6599 _("Got a printer-uri attribute but no job-id!"));
6603 jobid
= attr
->values
[0].integer
;
6608 * Got a job URI; parse it to get the job ID...
6611 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
6612 sizeof(scheme
), username
, sizeof(username
), host
,
6613 sizeof(host
), &port
, resource
, sizeof(resource
));
6615 if (strncmp(resource
, "/jobs/", 6))
6621 send_ipp_status(con
, IPP_BAD_REQUEST
,
6622 _("Bad job-uri attribute \"%s\"!"),
6623 uri
->values
[0].string
.text
);
6627 jobid
= atoi(resource
+ 6);
6631 * See if the job exists...
6634 if ((job
= cupsdFindJob(jobid
)) == NULL
)
6637 * Nope - return a "not found" error...
6640 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
6648 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6650 send_http_error(con
, status
, NULL
);
6655 * Get the document number...
6658 if ((attr
= ippFindAttribute(con
->request
, "document-number",
6659 IPP_TAG_INTEGER
)) == NULL
)
6661 send_ipp_status(con
, IPP_BAD_REQUEST
,
6662 _("Missing document-number attribute!"));
6666 if ((docnum
= attr
->values
[0].integer
) < 1 || docnum
> job
->num_files
||
6667 attr
->num_values
> 1)
6669 send_ipp_status(con
, IPP_NOT_FOUND
, _("Document %d not found in job %d."),
6674 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, jobid
,
6676 if ((con
->file
= open(filename
, O_RDONLY
)) == -1)
6678 cupsdLogMessage(CUPSD_LOG_ERROR
,
6679 "Unable to open document %d in job %d - %s", docnum
, jobid
,
6681 send_ipp_status(con
, IPP_NOT_FOUND
,
6682 _("Unable to open document %d in job %d!"), docnum
, jobid
);
6686 fcntl(con
->file
, F_SETFD
, fcntl(con
->file
, F_GETFD
) | FD_CLOEXEC
);
6690 snprintf(format
, sizeof(format
), "%s/%s", job
->filetypes
[docnum
- 1]->super
,
6691 job
->filetypes
[docnum
- 1]->type
);
6693 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
, "document-format",
6695 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "document-number",
6697 if ((attr
= ippFindAttribute(job
->attrs
, "document-name",
6698 IPP_TAG_NAME
)) != NULL
)
6699 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_NAME
, "document-name",
6700 NULL
, attr
->values
[0].string
.text
);
6705 * 'get_job_attrs()' - Get job attributes.
6709 get_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
6710 ipp_attribute_t
*uri
) /* I - Job URI */
6712 http_status_t status
; /* Policy status */
6713 ipp_attribute_t
*attr
; /* Current attribute */
6714 int jobid
; /* Job ID */
6715 cupsd_job_t
*job
; /* Current job */
6716 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
6717 username
[HTTP_MAX_URI
], /* Username portion of URI */
6718 host
[HTTP_MAX_URI
], /* Host portion of URI */
6719 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6720 int port
; /* Port portion of URI */
6721 cups_array_t
*ra
; /* Requested attributes array */
6724 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_job_attrs(%p[%d], %s)", con
,
6725 con
->http
.fd
, uri
->values
[0].string
.text
);
6728 * See if we have a job URI or a printer URI...
6731 if (!strcmp(uri
->name
, "printer-uri"))
6734 * Got a printer URI; see if we also have a job-id attribute...
6737 if ((attr
= ippFindAttribute(con
->request
, "job-id",
6738 IPP_TAG_INTEGER
)) == NULL
)
6740 send_ipp_status(con
, IPP_BAD_REQUEST
,
6741 _("Got a printer-uri attribute but no job-id!"));
6745 jobid
= attr
->values
[0].integer
;
6750 * Got a job URI; parse it to get the job ID...
6753 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
6754 sizeof(scheme
), username
, sizeof(username
), host
,
6755 sizeof(host
), &port
, resource
, sizeof(resource
));
6757 if (strncmp(resource
, "/jobs/", 6))
6763 send_ipp_status(con
, IPP_BAD_REQUEST
,
6764 _("Bad job-uri attribute \"%s\"!"),
6765 uri
->values
[0].string
.text
);
6769 jobid
= atoi(resource
+ 6);
6773 * See if the job exists...
6776 if ((job
= cupsdFindJob(jobid
)) == NULL
)
6779 * Nope - return a "not found" error...
6782 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
6790 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6792 send_http_error(con
, status
, NULL
);
6797 * Copy attributes...
6802 ra
= create_requested_array(con
->request
);
6803 copy_job_attrs(con
, job
, ra
);
6804 cupsArrayDelete(ra
);
6806 con
->response
->request
.status
.status_code
= IPP_OK
;
6811 * 'get_jobs()' - Get a list of jobs for the specified printer.
6815 get_jobs(cupsd_client_t
*con
, /* I - Client connection */
6816 ipp_attribute_t
*uri
) /* I - Printer URI */
6818 http_status_t status
; /* Policy status */
6819 ipp_attribute_t
*attr
; /* Current attribute */
6820 const char *dest
; /* Destination */
6821 cups_ptype_t dtype
; /* Destination type (printer/class) */
6822 cups_ptype_t dmask
; /* Destination type mask */
6823 char scheme
[HTTP_MAX_URI
], /* Scheme portion of URI */
6824 username
[HTTP_MAX_URI
], /* Username portion of URI */
6825 host
[HTTP_MAX_URI
], /* Host portion of URI */
6826 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6827 int port
; /* Port portion of URI */
6828 int completed
; /* Completed jobs? */
6829 int first_job_id
; /* First job ID */
6830 int limit
; /* Maximum number of jobs to return */
6831 int count
; /* Number of jobs that match */
6832 cupsd_job_t
*job
; /* Current job pointer */
6833 cupsd_printer_t
*printer
; /* Printer */
6834 cups_array_t
*list
; /* Which job list... */
6835 cups_array_t
*ra
; /* Requested attributes array */
6838 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs(%p[%d], %s)", con
, con
->http
.fd
,
6839 uri
->values
[0].string
.text
);
6842 * Is the destination valid?
6845 if (strcmp(uri
->name
, "printer-uri"))
6847 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No printer-uri in request!"));
6851 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
6852 sizeof(scheme
), username
, sizeof(username
), host
,
6853 sizeof(host
), &port
, resource
, sizeof(resource
));
6855 if (!strcmp(resource
, "/") || !strcmp(resource
, "/jobs"))
6858 dtype
= (cups_ptype_t
)0;
6859 dmask
= (cups_ptype_t
)0;
6862 else if (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10)
6865 dtype
= (cups_ptype_t
)0;
6866 dmask
= CUPS_PRINTER_CLASS
;
6869 else if (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9)
6872 dtype
= CUPS_PRINTER_CLASS
;
6873 dmask
= CUPS_PRINTER_CLASS
;
6876 else if ((dest
= cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
,
6883 send_ipp_status(con
, IPP_NOT_FOUND
,
6884 _("The printer or class was not found."));
6889 dtype
&= CUPS_PRINTER_CLASS
;
6890 dmask
= CUPS_PRINTER_CLASS
;
6899 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
,
6902 send_http_error(con
, status
, printer
);
6906 else if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
6908 send_http_error(con
, status
, NULL
);
6913 * See if the "which-jobs" attribute have been specified...
6916 if ((attr
= ippFindAttribute(con
->request
, "which-jobs",
6917 IPP_TAG_KEYWORD
)) != NULL
&&
6918 !strcmp(attr
->values
[0].string
.text
, "completed"))
6923 else if (attr
&& !strcmp(attr
->values
[0].string
.text
, "all"))
6928 else if (attr
&& !strcmp(attr
->values
[0].string
.text
, "processing"))
6931 list
= PrintingJobs
;
6940 * See if they want to limit the number of jobs reported...
6943 if ((attr
= ippFindAttribute(con
->request
, "limit",
6944 IPP_TAG_INTEGER
)) != NULL
)
6945 limit
= attr
->values
[0].integer
;
6949 if ((attr
= ippFindAttribute(con
->request
, "first-job-id",
6950 IPP_TAG_INTEGER
)) != NULL
)
6951 first_job_id
= attr
->values
[0].integer
;
6956 * See if we only want to see jobs for a specific user...
6959 if ((attr
= ippFindAttribute(con
->request
, "my-jobs",
6960 IPP_TAG_BOOLEAN
)) != NULL
&&
6961 attr
->values
[0].boolean
)
6962 strlcpy(username
, get_username(con
), sizeof(username
));
6966 ra
= create_requested_array(con
->request
);
6969 * OK, build a list of jobs for this printer...
6972 for (count
= 0, job
= (cupsd_job_t
*)cupsArrayFirst(list
);
6973 (limit
<= 0 || count
< limit
) && job
;
6974 job
= (cupsd_job_t
*)cupsArrayNext(list
))
6977 * Filter out jobs that don't match...
6980 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
6981 "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
6982 "state_value=%d, attrs=%p", job
->id
, job
->dest
,
6983 job
->username
, job
->state_value
, job
->attrs
);
6985 if (!job
->dest
|| !job
->username
)
6988 if (!job
->dest
|| !job
->username
)
6991 if ((dest
&& strcmp(job
->dest
, dest
)) &&
6992 (!job
->printer
|| !dest
|| strcmp(job
->printer
->name
, dest
)))
6994 if ((job
->dtype
& dmask
) != dtype
&&
6995 (!job
->printer
|| (job
->printer
->type
& dmask
) != dtype
))
6997 if (completed
&& job
->state_value
<= IPP_JOB_STOPPED
)
7000 if (job
->id
< first_job_id
)
7007 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs: No attributes for job %d!",
7012 if (username
[0] && strcasecmp(username
, job
->username
))
7016 ippAddSeparator(con
->response
);
7020 copy_job_attrs(con
, job
, ra
);
7023 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs: count=%d", count
);
7025 cupsArrayDelete(ra
);
7027 con
->response
->request
.status
.status_code
= IPP_OK
;
7032 * 'get_notifications()' - Get events for a subscription.
7036 get_notifications(cupsd_client_t
*con
) /* I - Client connection */
7038 int i
, j
; /* Looping vars */
7039 http_status_t status
; /* Policy status */
7040 cupsd_subscription_t
*sub
; /* Subscription */
7041 ipp_attribute_t
*ids
, /* notify-subscription-ids */
7042 *sequences
; /* notify-sequence-numbers */
7043 int min_seq
; /* Minimum sequence number */
7044 int interval
; /* Poll interval */
7047 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_notifications(con=%p[%d])",
7051 * Get subscription attributes...
7054 ids
= ippFindAttribute(con
->request
, "notify-subscription-ids",
7056 sequences
= ippFindAttribute(con
->request
, "notify-sequence-numbers",
7061 send_ipp_status(con
, IPP_BAD_REQUEST
,
7062 _("Missing notify-subscription-ids attribute!"));
7067 * Are the subscription IDs valid?
7070 for (i
= 0, interval
= 60; i
< ids
->num_values
; i
++)
7072 if ((sub
= cupsdFindSubscription(ids
->values
[i
].integer
)) == NULL
)
7075 * Bad subscription ID...
7078 send_ipp_status(con
, IPP_NOT_FOUND
,
7079 _("notify-subscription-id %d no good!"),
7080 ids
->values
[i
].integer
);
7088 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
7090 con
, sub
->owner
)) != HTTP_OK
)
7092 send_http_error(con
, status
, sub
->dest
);
7097 * Check the subscription type and update the interval accordingly.
7100 if (sub
->job
&& sub
->job
->state_value
== IPP_JOB_PROCESSING
&&
7103 else if (sub
->job
&& sub
->job
->state_value
>= IPP_JOB_STOPPED
)
7105 else if (sub
->dest
&& sub
->dest
->state
== IPP_PRINTER_PROCESSING
&&
7111 * Tell the client to poll again in N seconds...
7115 ippAddInteger(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
7116 "notify-get-interval", interval
);
7118 ippAddInteger(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
7119 "printer-up-time", time(NULL
));
7122 * Copy the subscription event attributes to the response.
7125 con
->response
->request
.status
.status_code
=
7126 interval
? IPP_OK
: IPP_OK_EVENTS_COMPLETE
;
7128 for (i
= 0; i
< ids
->num_values
; i
++)
7131 * Get the subscription and sequence number...
7134 sub
= cupsdFindSubscription(ids
->values
[i
].integer
);
7136 if (sequences
&& i
< sequences
->num_values
)
7137 min_seq
= sequences
->values
[i
].integer
;
7142 * If we don't have any new events, nothing to do here...
7145 if (min_seq
> (sub
->first_event_id
+ sub
->num_events
))
7149 * Otherwise copy all of the new events...
7152 if (sub
->first_event_id
> min_seq
)
7155 j
= min_seq
- sub
->first_event_id
;
7157 for (; j
< sub
->num_events
; j
++)
7159 ippAddSeparator(con
->response
);
7161 copy_attrs(con
->response
, sub
->events
[j
]->attrs
, NULL
,
7162 IPP_TAG_EVENT_NOTIFICATION
, 0);
7169 * 'get_ppd()' - Get a named PPD from the local system.
7173 get_ppd(cupsd_client_t
*con
, /* I - Client connection */
7174 ipp_attribute_t
*uri
) /* I - Printer URI or PPD name */
7176 http_status_t status
; /* Policy status */
7177 cupsd_printer_t
*dest
; /* Destination */
7178 cups_ptype_t dtype
; /* Destination type */
7181 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_ppd(%p[%d], %p[%s=%s])", con
,
7182 con
->http
.fd
, uri
, uri
->name
, uri
->values
[0].string
.text
);
7184 if (!strcmp(uri
->name
, "ppd-name"))
7187 * Return a PPD file from cups-driverd...
7190 char command
[1024], /* cups-driverd command */
7191 options
[1024], /* Options to pass to command */
7192 ppd_name
[1024]; /* ppd-name */
7199 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
7201 send_http_error(con
, status
, NULL
);
7206 * Run cups-driverd command with the given options...
7209 snprintf(command
, sizeof(command
), "%s/daemon/cups-driverd", ServerBin
);
7210 url_encode_string(uri
->values
[0].string
.text
, ppd_name
, sizeof(ppd_name
));
7211 snprintf(options
, sizeof(options
), "get+%d+%s",
7212 con
->request
->request
.op
.request_id
, ppd_name
);
7214 if (cupsdSendCommand(con
, command
, options
, 0))
7217 * Command started successfully, don't send an IPP response here...
7220 ippDelete(con
->response
);
7221 con
->response
= NULL
;
7226 * Command failed, return "internal error" so the user knows something
7230 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
7231 _("cups-driverd failed to execute."));
7234 else if (!strcmp(uri
->name
, "printer-uri") &&
7235 cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &dest
))
7237 int i
; /* Looping var */
7238 char filename
[1024]; /* PPD filename */
7245 if ((status
= cupsdCheckPolicy(dest
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
7247 send_http_error(con
, status
, dest
);
7252 * See if we need the PPD for a class or remote printer...
7255 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
,
7258 if ((dtype
& CUPS_PRINTER_REMOTE
) && access(filename
, 0))
7260 con
->response
->request
.status
.status_code
= CUPS_SEE_OTHER
;
7261 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
7262 "printer-uri", NULL
, dest
->uri
);
7265 else if (dtype
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
7267 for (i
= 0; i
< dest
->num_printers
; i
++)
7268 if (!(dest
->printers
[i
]->type
&
7269 (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
)))
7271 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
,
7272 dest
->printers
[i
]->name
);
7274 if (!access(filename
, 0))
7278 if (i
< dest
->num_printers
)
7279 dest
= dest
->printers
[i
];
7282 con
->response
->request
.status
.status_code
= CUPS_SEE_OTHER
;
7283 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
7284 "printer-uri", NULL
, dest
->printers
[0]->uri
);
7290 * Found the printer with the PPD file, now see if there is one...
7293 if ((con
->file
= open(filename
, O_RDONLY
)) < 0)
7295 send_ipp_status(con
, IPP_NOT_FOUND
,
7296 _("The PPD file \"%s\" could not be opened: %s"),
7297 uri
->values
[0].string
.text
, strerror(errno
));
7301 fcntl(con
->file
, F_SETFD
, fcntl(con
->file
, F_GETFD
) | FD_CLOEXEC
);
7305 con
->response
->request
.status
.status_code
= IPP_OK
;
7308 send_ipp_status(con
, IPP_NOT_FOUND
,
7309 _("The PPD file \"%s\" could not be found."),
7310 uri
->values
[0].string
.text
);
7315 * 'get_ppds()' - Get the list of PPD files on the local system.
7319 get_ppds(cupsd_client_t
*con
) /* I - Client connection */
7321 http_status_t status
; /* Policy status */
7322 ipp_attribute_t
*limit
, /* Limit attribute */
7323 *device
, /* ppd-device-id attribute */
7324 *language
, /* ppd-natural-language attribute */
7325 *make
, /* ppd-make attribute */
7326 *model
, /* ppd-make-and-model attribute */
7327 *model_number
, /* ppd-model-number attribute */
7328 *product
, /* ppd-product attribute */
7329 *psversion
, /* ppd-psverion attribute */
7330 *type
, /* ppd-type attribute */
7331 *requested
, /* requested-attributes attribute */
7332 *exclude
, /* exclude-schemes attribute */
7333 *include
; /* include-schemes attribute */
7334 char command
[1024], /* cups-driverd command */
7335 options
[4096], /* Options to pass to command */
7336 device_str
[256],/* Escaped ppd-device-id string */
7338 /* Escaped ppd-natural-language */
7339 make_str
[256], /* Escaped ppd-make string */
7340 model_str
[256], /* Escaped ppd-make-and-model string */
7341 model_number_str
[256],
7342 /* ppd-model-number string */
7344 /* Escaped ppd-product string */
7346 /* Escaped ppd-psversion string */
7347 type_str
[256], /* Escaped ppd-type string */
7349 /* String for requested attributes */
7351 /* String for excluded schemes */
7353 /* String for included schemes */
7356 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_ppds(%p[%d])", con
, con
->http
.fd
);
7362 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
7364 send_http_error(con
, status
, NULL
);
7369 * Run cups-driverd command with the given options...
7372 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
7373 device
= ippFindAttribute(con
->request
, "ppd-device-id", IPP_TAG_TEXT
);
7374 language
= ippFindAttribute(con
->request
, "ppd-natural-language",
7376 make
= ippFindAttribute(con
->request
, "ppd-make", IPP_TAG_TEXT
);
7377 model
= ippFindAttribute(con
->request
, "ppd-make-and-model",
7379 model_number
= ippFindAttribute(con
->request
, "ppd-model-number",
7381 product
= ippFindAttribute(con
->request
, "ppd-product", IPP_TAG_TEXT
);
7382 psversion
= ippFindAttribute(con
->request
, "ppd-psversion", IPP_TAG_TEXT
);
7383 type
= ippFindAttribute(con
->request
, "ppd-type", IPP_TAG_KEYWORD
);
7384 requested
= ippFindAttribute(con
->request
, "requested-attributes",
7386 exclude
= ippFindAttribute(con
->request
, "exclude-schemes",
7388 include
= ippFindAttribute(con
->request
, "include-schemes",
7392 url_encode_attr(requested
, requested_str
, sizeof(requested_str
));
7394 strlcpy(requested_str
, "requested-attributes=all", sizeof(requested_str
));
7397 url_encode_attr(device
, device_str
, sizeof(device_str
));
7399 device_str
[0] = '\0';
7402 url_encode_attr(language
, language_str
, sizeof(language_str
));
7404 language_str
[0] = '\0';
7407 url_encode_attr(make
, make_str
, sizeof(make_str
));
7412 url_encode_attr(model
, model_str
, sizeof(model_str
));
7414 model_str
[0] = '\0';
7417 snprintf(model_number_str
, sizeof(model_number_str
), "ppd-model-number=%d",
7418 model_number
->values
[0].integer
);
7420 model_number_str
[0] = '\0';
7423 url_encode_attr(product
, product_str
, sizeof(product_str
));
7425 product_str
[0] = '\0';
7428 url_encode_attr(psversion
, psversion_str
, sizeof(psversion_str
));
7430 psversion_str
[0] = '\0';
7433 url_encode_attr(type
, type_str
, sizeof(type_str
));
7438 url_encode_attr(exclude
, exclude_str
, sizeof(exclude_str
));
7440 exclude_str
[0] = '\0';
7443 url_encode_attr(include
, include_str
, sizeof(include_str
));
7445 include_str
[0] = '\0';
7447 snprintf(command
, sizeof(command
), "%s/daemon/cups-driverd", ServerBin
);
7448 snprintf(options
, sizeof(options
),
7449 "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
7450 con
->request
->request
.op
.request_id
,
7451 limit
? limit
->values
[0].integer
: 0,
7453 device
? "%20" : "", device_str
,
7454 language
? "%20" : "", language_str
,
7455 make
? "%20" : "", make_str
,
7456 model
? "%20" : "", model_str
,
7457 model_number
? "%20" : "", model_number_str
,
7458 product
? "%20" : "", product_str
,
7459 psversion
? "%20" : "", psversion_str
,
7460 type
? "%20" : "", type_str
,
7461 exclude_str
[0] ? "%20" : "", exclude_str
,
7462 include_str
[0] ? "%20" : "", include_str
);
7464 if (cupsdSendCommand(con
, command
, options
, 0))
7467 * Command started successfully, don't send an IPP response here...
7470 ippDelete(con
->response
);
7471 con
->response
= NULL
;
7476 * Command failed, return "internal error" so the user knows something
7480 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
7481 _("cups-driverd failed to execute."));
7487 * 'get_printer_attrs()' - Get printer attributes.
7491 get_printer_attrs(cupsd_client_t
*con
, /* I - Client connection */
7492 ipp_attribute_t
*uri
) /* I - Printer URI */
7494 http_status_t status
; /* Policy status */
7495 cups_ptype_t dtype
; /* Destination type (printer/class) */
7496 cupsd_printer_t
*printer
; /* Printer/class */
7497 cups_array_t
*ra
; /* Requested attributes array */
7500 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_printer_attrs(%p[%d], %s)", con
,
7501 con
->http
.fd
, uri
->values
[0].string
.text
);
7504 * Is the destination valid?
7507 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
7513 send_ipp_status(con
, IPP_NOT_FOUND
,
7514 _("The printer or class was not found."));
7522 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
7524 send_http_error(con
, status
, printer
);
7529 * Send the attributes...
7532 ra
= create_requested_array(con
->request
);
7534 copy_printer_attrs(con
, printer
, ra
);
7536 cupsArrayDelete(ra
);
7538 con
->response
->request
.status
.status_code
= IPP_OK
;
7543 * 'get_printer_supported()' - Get printer supported values.
7547 get_printer_supported(
7548 cupsd_client_t
*con
, /* I - Client connection */
7549 ipp_attribute_t
*uri
) /* I - Printer URI */
7551 http_status_t status
; /* Policy status */
7552 cups_ptype_t dtype
; /* Destination type (printer/class) */
7553 cupsd_printer_t
*printer
; /* Printer/class */
7556 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_printer_supported(%p[%d], %s)", con
,
7557 con
->http
.fd
, uri
->values
[0].string
.text
);
7560 * Is the destination valid?
7563 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
7569 send_ipp_status(con
, IPP_NOT_FOUND
,
7570 _("The printer or class was not found."));
7578 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
7580 send_http_error(con
, status
, printer
);
7585 * Return a list of attributes that can be set via Set-Printer-Attributes.
7588 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ADMINDEFINE
,
7590 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ADMINDEFINE
,
7591 "printer-location", 0);
7593 con
->response
->request
.status
.status_code
= IPP_OK
;
7598 * 'get_printers()' - Get a list of printers or classes.
7602 get_printers(cupsd_client_t
*con
, /* I - Client connection */
7603 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
7605 http_status_t status
; /* Policy status */
7606 ipp_attribute_t
*attr
; /* Current attribute */
7607 int limit
; /* Max number of printers to return */
7608 int count
; /* Number of printers that match */
7609 cupsd_printer_t
*printer
; /* Current printer pointer */
7610 int printer_type
, /* printer-type attribute */
7611 printer_mask
; /* printer-type-mask attribute */
7612 char *location
; /* Location string */
7613 const char *username
; /* Current user */
7614 char *first_printer_name
; /* first-printer-name attribute */
7615 cups_array_t
*ra
; /* Requested attributes array */
7618 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_printers(%p[%d], %x)", con
,
7619 con
->http
.fd
, type
);
7625 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
7627 send_http_error(con
, status
, NULL
);
7632 * Check for printers...
7635 if (!Printers
|| !cupsArrayCount(Printers
))
7637 send_ipp_status(con
, IPP_NOT_FOUND
, _("No destinations added."));
7642 * See if they want to limit the number of printers reported...
7645 if ((attr
= ippFindAttribute(con
->request
, "limit",
7646 IPP_TAG_INTEGER
)) != NULL
)
7647 limit
= attr
->values
[0].integer
;
7651 if ((attr
= ippFindAttribute(con
->request
, "first-printer-name",
7652 IPP_TAG_NAME
)) != NULL
)
7653 first_printer_name
= attr
->values
[0].string
.text
;
7655 first_printer_name
= NULL
;
7658 * Support filtering...
7661 if ((attr
= ippFindAttribute(con
->request
, "printer-type",
7662 IPP_TAG_ENUM
)) != NULL
)
7663 printer_type
= attr
->values
[0].integer
;
7667 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask",
7668 IPP_TAG_ENUM
)) != NULL
)
7669 printer_mask
= attr
->values
[0].integer
;
7673 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
7674 IPP_TAG_TEXT
)) != NULL
)
7675 location
= attr
->values
[0].string
.text
;
7679 if (con
->username
[0])
7680 username
= con
->username
;
7681 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
7682 IPP_TAG_NAME
)) != NULL
)
7683 username
= attr
->values
[0].string
.text
;
7687 ra
= create_requested_array(con
->request
);
7690 * OK, build a list of printers for this printer...
7693 if (first_printer_name
)
7695 if ((printer
= cupsdFindDest(first_printer_name
)) == NULL
)
7696 printer
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
7699 printer
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
7702 count
< limit
&& printer
;
7703 printer
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
7705 if ((!type
|| (printer
->type
& CUPS_PRINTER_CLASS
) == type
) &&
7706 (printer
->type
& printer_mask
) == printer_type
&&
7708 (printer
->location
&& !strcasecmp(printer
->location
, location
))))
7711 * If HideImplicitMembers is enabled, see if this printer or class
7712 * is a member of an implicit class...
7715 if (ImplicitClasses
&& HideImplicitMembers
&&
7716 printer
->in_implicit_class
)
7720 * If a username is specified, see if it is allowed or denied
7724 if (!(printer
->type
& CUPS_PRINTER_AUTHENTICATED
) &&
7725 printer
->num_users
&& username
&& !user_allowed(printer
, username
))
7729 * Add the group separator as needed...
7733 ippAddSeparator(con
->response
);
7738 * Send the attributes...
7741 copy_printer_attrs(con
, printer
, ra
);
7745 cupsArrayDelete(ra
);
7747 con
->response
->request
.status
.status_code
= IPP_OK
;
7752 * 'get_subscription_attrs()' - Get subscription attributes.
7756 get_subscription_attrs(
7757 cupsd_client_t
*con
, /* I - Client connection */
7758 int sub_id
) /* I - Subscription ID */
7760 http_status_t status
; /* Policy status */
7761 cupsd_subscription_t
*sub
; /* Subscription */
7762 cups_array_t
*ra
; /* Requested attributes array */
7765 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
7766 "get_subscription_attrs(con=%p[%d], sub_id=%d)",
7767 con
, con
->http
.fd
, sub_id
);
7770 * Is the subscription ID valid?
7773 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
7776 * Bad subscription ID...
7779 send_ipp_status(con
, IPP_NOT_FOUND
,
7780 _("notify-subscription-id %d no good!"), sub_id
);
7788 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
7790 con
, sub
->owner
)) != HTTP_OK
)
7792 send_http_error(con
, status
, sub
->dest
);
7797 * Copy the subscription attributes to the response using the
7798 * requested-attributes attribute that may be provided by the client.
7801 ra
= create_requested_array(con
->request
);
7803 copy_subscription_attrs(con
, sub
, ra
);
7805 cupsArrayDelete(ra
);
7807 con
->response
->request
.status
.status_code
= IPP_OK
;
7812 * 'get_subscriptions()' - Get subscriptions.
7816 get_subscriptions(cupsd_client_t
*con
, /* I - Client connection */
7817 ipp_attribute_t
*uri
) /* I - Printer/job URI */
7819 http_status_t status
; /* Policy status */
7820 int count
; /* Number of subscriptions */
7821 int limit
; /* Limit */
7822 cupsd_subscription_t
*sub
; /* Subscription */
7823 cups_array_t
*ra
; /* Requested attributes array */
7824 ipp_attribute_t
*attr
; /* Attribute */
7825 cups_ptype_t dtype
; /* Destination type (printer/class) */
7826 char scheme
[HTTP_MAX_URI
],
7827 /* Scheme portion of URI */
7828 username
[HTTP_MAX_URI
],
7829 /* Username portion of URI */
7831 /* Host portion of URI */
7832 resource
[HTTP_MAX_URI
];
7833 /* Resource portion of URI */
7834 int port
; /* Port portion of URI */
7835 cupsd_job_t
*job
; /* Job pointer */
7836 cupsd_printer_t
*printer
; /* Printer */
7839 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
7840 "get_subscriptions(con=%p[%d], uri=%s)",
7841 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
7844 * Is the destination valid?
7847 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
7848 sizeof(scheme
), username
, sizeof(username
), host
,
7849 sizeof(host
), &port
, resource
, sizeof(resource
));
7851 if (!strcmp(resource
, "/") ||
7852 (!strncmp(resource
, "/jobs", 5) && strlen(resource
) <= 6) ||
7853 (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10) ||
7854 (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9))
7859 else if (!strncmp(resource
, "/jobs/", 6) && resource
[6])
7862 job
= cupsdFindJob(atoi(resource
+ 6));
7866 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%s does not exist!"),
7871 else if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
7877 send_ipp_status(con
, IPP_NOT_FOUND
,
7878 _("The printer or class was not found."));
7881 else if ((attr
= ippFindAttribute(con
->request
, "notify-job-id",
7882 IPP_TAG_INTEGER
)) != NULL
)
7884 job
= cupsdFindJob(attr
->values
[0].integer
);
7888 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"),
7889 attr
->values
[0].integer
);
7900 if ((status
= cupsdCheckPolicy(printer
? printer
->op_policy_ptr
:
7902 con
, NULL
)) != HTTP_OK
)
7904 send_http_error(con
, status
, printer
);
7909 * Copy the subscription attributes to the response using the
7910 * requested-attributes attribute that may be provided by the client.
7913 ra
= create_requested_array(con
->request
);
7915 if ((attr
= ippFindAttribute(con
->request
, "limit",
7916 IPP_TAG_INTEGER
)) != NULL
)
7917 limit
= attr
->values
[0].integer
;
7922 * See if we only want to see subscriptions for a specific user...
7925 if ((attr
= ippFindAttribute(con
->request
, "my-subscriptions",
7926 IPP_TAG_BOOLEAN
)) != NULL
&&
7927 attr
->values
[0].boolean
)
7928 strlcpy(username
, get_username(con
), sizeof(username
));
7932 for (sub
= (cupsd_subscription_t
*)cupsArrayFirst(Subscriptions
), count
= 0;
7934 sub
= (cupsd_subscription_t
*)cupsArrayNext(Subscriptions
))
7935 if ((!printer
|| sub
->dest
== printer
) && (!job
|| sub
->job
== job
) &&
7936 (!username
[0] || !strcasecmp(username
, sub
->owner
)))
7938 ippAddSeparator(con
->response
);
7939 copy_subscription_attrs(con
, sub
, ra
);
7942 if (limit
&& count
>= limit
)
7946 cupsArrayDelete(ra
);
7949 con
->response
->request
.status
.status_code
= IPP_OK
;
7951 send_ipp_status(con
, IPP_NOT_FOUND
, _("No subscriptions found."));
7956 * 'get_username()' - Get the username associated with a request.
7959 static const char * /* O - Username */
7960 get_username(cupsd_client_t
*con
) /* I - Connection */
7962 ipp_attribute_t
*attr
; /* Attribute */
7965 if (con
->username
[0])
7966 return (con
->username
);
7967 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
7968 IPP_TAG_NAME
)) != NULL
)
7969 return (attr
->values
[0].string
.text
);
7971 return ("anonymous");
7976 * 'hold_job()' - Hold a print job.
7980 hold_job(cupsd_client_t
*con
, /* I - Client connection */
7981 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
7983 ipp_attribute_t
*attr
; /* Current job-hold-until */
7984 const char *when
; /* New value */
7985 int jobid
; /* Job ID */
7986 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
7987 username
[HTTP_MAX_URI
], /* Username portion of URI */
7988 host
[HTTP_MAX_URI
], /* Host portion of URI */
7989 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
7990 int port
; /* Port portion of URI */
7991 cupsd_job_t
*job
; /* Job information */
7994 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "hold_job(%p[%d], %s)", con
, con
->http
.fd
,
7995 uri
->values
[0].string
.text
);
7998 * See if we have a job URI or a printer URI...
8001 if (!strcmp(uri
->name
, "printer-uri"))
8004 * Got a printer URI; see if we also have a job-id attribute...
8007 if ((attr
= ippFindAttribute(con
->request
, "job-id",
8008 IPP_TAG_INTEGER
)) == NULL
)
8010 send_ipp_status(con
, IPP_BAD_REQUEST
,
8011 _("Got a printer-uri attribute but no job-id!"));
8015 jobid
= attr
->values
[0].integer
;
8020 * Got a job URI; parse it to get the job ID...
8023 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
8024 sizeof(scheme
), username
, sizeof(username
), host
,
8025 sizeof(host
), &port
, resource
, sizeof(resource
));
8027 if (strncmp(resource
, "/jobs/", 6))
8033 send_ipp_status(con
, IPP_BAD_REQUEST
,
8034 _("Bad job-uri attribute \"%s\"!"),
8035 uri
->values
[0].string
.text
);
8039 jobid
= atoi(resource
+ 6);
8043 * See if the job exists...
8046 if ((job
= cupsdFindJob(jobid
)) == NULL
)
8049 * Nope - return a "not found" error...
8052 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
8057 * See if the job is owned by the requesting user...
8060 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
8062 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
8067 * Hold the job and return...
8070 if ((attr
= ippFindAttribute(con
->request
, "job-hold-until",
8071 IPP_TAG_KEYWORD
)) == NULL
)
8072 attr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
8076 when
= attr
->values
[0].string
.text
;
8078 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, cupsdFindDest(job
->dest
), job
,
8079 "Job job-hold-until value changed by user.");
8082 when
= "indefinite";
8084 cupsdSetJobHoldUntil(job
, when
, 1);
8085 cupsdSetJobState(job
, IPP_JOB_HELD
, CUPSD_JOB_DEFAULT
, "Job held by \"%s\".",
8088 con
->response
->request
.status
.status_code
= IPP_OK
;
8093 * 'hold_new_jobs()' - Hold pending/new jobs on a printer or class.
8097 hold_new_jobs(cupsd_client_t
*con
, /* I - Connection */
8098 ipp_attribute_t
*uri
) /* I - Printer URI */
8100 http_status_t status
; /* Policy status */
8101 cups_ptype_t dtype
; /* Destination type (printer/class) */
8102 cupsd_printer_t
*printer
; /* Printer data */
8105 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "hold_new_jobs(%p[%d], %s)", con
,
8106 con
->http
.fd
, uri
->values
[0].string
.text
);
8109 * Is the destination valid?
8112 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
8118 send_ipp_status(con
, IPP_NOT_FOUND
,
8119 _("The printer or class was not found."));
8127 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
8129 send_http_error(con
, status
, printer
);
8134 * Hold pending/new jobs sent to the printer...
8137 printer
->holding_new_jobs
= 1;
8139 cupsdSetPrinterReasons(printer
, "+hold-new-jobs");
8140 cupsdAddPrinterHistory(printer
);
8142 if (dtype
& CUPS_PRINTER_CLASS
)
8143 cupsdLogMessage(CUPSD_LOG_INFO
,
8144 "Class \"%s\" now holding pending/new jobs (\"%s\").",
8145 printer
->name
, get_username(con
));
8147 cupsdLogMessage(CUPSD_LOG_INFO
,
8148 "Printer \"%s\" now holding pending/new jobs (\"%s\").",
8149 printer
->name
, get_username(con
));
8152 * Everything was ok, so return OK status...
8155 con
->response
->request
.status
.status_code
= IPP_OK
;
8160 * 'move_job()' - Move a job to a new destination.
8164 move_job(cupsd_client_t
*con
, /* I - Client connection */
8165 ipp_attribute_t
*uri
) /* I - Job URI */
8167 http_status_t status
; /* Policy status */
8168 ipp_attribute_t
*attr
; /* Current attribute */
8169 int jobid
; /* Job ID */
8170 cupsd_job_t
*job
; /* Current job */
8171 const char *src
; /* Source printer/class */
8172 cups_ptype_t stype
, /* Source type (printer or class) */
8173 dtype
; /* Destination type (printer/class) */
8174 char scheme
[HTTP_MAX_URI
], /* Scheme portion of URI */
8175 username
[HTTP_MAX_URI
], /* Username portion of URI */
8176 host
[HTTP_MAX_URI
], /* Host portion of URI */
8177 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
8178 int port
; /* Port portion of URI */
8179 cupsd_printer_t
*sprinter
, /* Source printer */
8180 *dprinter
; /* Destination printer */
8183 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "move_job(%p[%d], %s)", con
, con
->http
.fd
,
8184 uri
->values
[0].string
.text
);
8187 * Get the new printer or class...
8190 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri",
8191 IPP_TAG_URI
)) == NULL
)
8194 * Need job-printer-uri...
8197 send_ipp_status(con
, IPP_BAD_REQUEST
,
8198 _("job-printer-uri attribute missing!"));
8202 if (!cupsdValidateDest(attr
->values
[0].string
.text
, &dtype
, &dprinter
))
8208 send_ipp_status(con
, IPP_NOT_FOUND
,
8209 _("The printer or class was not found."));
8214 * See if we have a job URI or a printer URI...
8217 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
8218 sizeof(scheme
), username
, sizeof(username
), host
,
8219 sizeof(host
), &port
, resource
, sizeof(resource
));
8221 if (!strcmp(uri
->name
, "printer-uri"))
8224 * Got a printer URI; see if we also have a job-id attribute...
8227 if ((attr
= ippFindAttribute(con
->request
, "job-id",
8228 IPP_TAG_INTEGER
)) == NULL
)
8234 if ((src
= cupsdValidateDest(uri
->values
[0].string
.text
, &stype
,
8235 &sprinter
)) == NULL
)
8241 send_ipp_status(con
, IPP_NOT_FOUND
,
8242 _("The printer or class was not found."));
8251 * Otherwise, just move a single job...
8254 if ((job
= cupsdFindJob(attr
->values
[0].integer
)) == NULL
)
8257 * Nope - return a "not found" error...
8260 send_ipp_status(con
, IPP_NOT_FOUND
,
8261 _("Job #%d does not exist!"), attr
->values
[0].integer
);
8267 * Job found, initialize source pointers...
8278 * Got a job URI; parse it to get the job ID...
8281 if (strncmp(resource
, "/jobs/", 6))
8287 send_ipp_status(con
, IPP_BAD_REQUEST
,
8288 _("Bad job-uri attribute \"%s\"!"),
8289 uri
->values
[0].string
.text
);
8294 * See if the job exists...
8297 jobid
= atoi(resource
+ 6);
8299 if ((job
= cupsdFindJob(jobid
)) == NULL
)
8302 * Nope - return a "not found" error...
8305 send_ipp_status(con
, IPP_NOT_FOUND
,
8306 _("Job #%d does not exist!"), jobid
);
8312 * Job found, initialize source pointers...
8321 * Check the policy of the destination printer...
8324 if ((status
= cupsdCheckPolicy(dprinter
->op_policy_ptr
, con
,
8325 job
? job
->username
: NULL
)) != HTTP_OK
)
8327 send_http_error(con
, status
, dprinter
);
8332 * Now move the job or jobs...
8338 * See if the job has been completed...
8341 if (job
->state_value
> IPP_JOB_STOPPED
)
8344 * Return a "not-possible" error...
8347 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8348 _("Job #%d is finished and cannot be altered!"),
8354 * See if the job is owned by the requesting user...
8357 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
8359 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
8364 * Move the job to a different printer or class...
8367 cupsdMoveJob(job
, dprinter
);
8372 * Got the source printer, now look through the jobs...
8375 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
8377 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
8380 * See if the job is pointing at the source printer or has not been
8384 if (strcasecmp(job
->dest
, src
) ||
8385 job
->state_value
> IPP_JOB_STOPPED
)
8389 * See if the job can be moved by the requesting user...
8392 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
8396 * Move the job to a different printer or class...
8399 cupsdMoveJob(job
, dprinter
);
8404 * Start jobs if possible...
8410 * Return with "everything is OK" status...
8413 con
->response
->request
.status
.status_code
= IPP_OK
;
8418 * 'ppd_parse_line()' - Parse a PPD default line.
8421 static int /* O - 0 on success, -1 on failure */
8422 ppd_parse_line(const char *line
, /* I - Line */
8423 char *option
, /* O - Option name */
8424 int olen
, /* I - Size of option name */
8425 char *choice
, /* O - Choice name */
8426 int clen
) /* I - Size of choice name */
8429 * Verify this is a default option line...
8432 if (strncmp(line
, "*Default", 8))
8436 * Read the option name...
8439 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
8449 * Skip everything else up to the colon (:)...
8452 while (*line
&& *line
!= ':')
8461 * Now grab the option choice, skipping leading whitespace...
8464 while (isspace(*line
& 255))
8467 for (clen
--; isalnum(*line
& 255); line
++)
8477 * Return with no errors...
8485 * 'print_job()' - Print a file to a printer or class.
8489 print_job(cupsd_client_t
*con
, /* I - Client connection */
8490 ipp_attribute_t
*uri
) /* I - Printer URI */
8492 ipp_attribute_t
*attr
; /* Current attribute */
8493 ipp_attribute_t
*format
; /* Document-format attribute */
8494 const char *default_format
; /* document-format-default value */
8495 cupsd_job_t
*job
; /* New job */
8496 char filename
[1024]; /* Job filename */
8497 mime_type_t
*filetype
; /* Type of file */
8498 char super
[MIME_MAX_SUPER
], /* Supertype of file */
8499 type
[MIME_MAX_TYPE
], /* Subtype of file */
8500 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
8501 /* Textual name of mime type */
8502 cupsd_printer_t
*printer
; /* Printer data */
8503 struct stat fileinfo
; /* File information */
8504 int kbytes
; /* Size of file */
8505 int compression
; /* Document compression */
8508 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "print_job(%p[%d], %s)", con
, con
->http
.fd
,
8509 uri
->values
[0].string
.text
);
8512 * Validate print file attributes, for now just document-format and
8513 * compression (CUPS only supports "none" and "gzip")...
8516 compression
= CUPS_FILE_NONE
;
8518 if ((attr
= ippFindAttribute(con
->request
, "compression",
8519 IPP_TAG_KEYWORD
)) != NULL
)
8521 if (strcmp(attr
->values
[0].string
.text
, "none")
8523 && strcmp(attr
->values
[0].string
.text
, "gzip")
8524 #endif /* HAVE_LIBZ */
8527 send_ipp_status(con
, IPP_ATTRIBUTES
,
8528 _("Unsupported compression \"%s\"!"),
8529 attr
->values
[0].string
.text
);
8530 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
8531 "compression", NULL
, attr
->values
[0].string
.text
);
8536 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
8537 compression
= CUPS_FILE_GZIP
;
8538 #endif /* HAVE_LIBZ */
8542 * Do we have a file to print?
8547 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No file!?!"));
8552 * Is the destination valid?
8555 if (!cupsdValidateDest(uri
->values
[0].string
.text
, NULL
, &printer
))
8561 send_ipp_status(con
, IPP_NOT_FOUND
,
8562 _("The printer or class was not found."));
8567 * Is it a format we support?
8570 if ((format
= ippFindAttribute(con
->request
, "document-format",
8571 IPP_TAG_MIMETYPE
)) != NULL
)
8574 * Grab format from client...
8577 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
,
8580 send_ipp_status(con
, IPP_BAD_REQUEST
,
8581 _("Could not scan type \"%s\"!"),
8582 format
->values
[0].string
.text
);
8586 else if ((default_format
= cupsGetOption("document-format",
8587 printer
->num_options
,
8588 printer
->options
)) != NULL
)
8591 * Use default document format...
8594 if (sscanf(default_format
, "%15[^/]/%31[^;]", super
, type
) != 2)
8596 send_ipp_status(con
, IPP_BAD_REQUEST
,
8597 _("Could not scan type \"%s\"!"),
8608 strcpy(super
, "application");
8609 strcpy(type
, "octet-stream");
8612 if (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))
8615 * Auto-type the file...
8618 ipp_attribute_t
*doc_name
; /* document-name attribute */
8621 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Job ???] Auto-typing file...");
8623 doc_name
= ippFindAttribute(con
->request
, "document-name", IPP_TAG_NAME
);
8624 filetype
= mimeFileType(MimeDatabase
, con
->filename
,
8625 doc_name
? doc_name
->values
[0].string
.text
: NULL
,
8629 filetype
= mimeType(MimeDatabase
, super
, type
);
8631 cupsdLogMessage(CUPSD_LOG_INFO
, "[Job ???] Request file type is %s/%s.",
8632 filetype
->super
, filetype
->type
);
8635 filetype
= mimeType(MimeDatabase
, super
, type
);
8639 (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))))
8642 * Replace the document-format attribute value with the auto-typed or
8646 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
8651 _cupsStrFree(format
->values
[0].string
.text
);
8653 format
->values
[0].string
.text
= _cupsStrAlloc(mimetype
);
8656 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
8657 "document-format", NULL
, mimetype
);
8661 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
8662 _("Unsupported format \'%s/%s\'!"), super
, type
);
8663 cupsdLogMessage(CUPSD_LOG_INFO
,
8664 "Hint: Do you have the raw file printing rules enabled?");
8667 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
8668 "document-format", NULL
, format
->values
[0].string
.text
);
8674 * Read any embedded job ticket info from PS files...
8677 if (!strcasecmp(filetype
->super
, "application") &&
8678 (!strcasecmp(filetype
->type
, "postscript") ||
8679 !strcasecmp(filetype
->type
, "pdf")))
8680 read_job_ticket(con
);
8683 * Create the job object...
8686 if ((job
= add_job(con
, printer
, filetype
)) == NULL
)
8690 * Update quota data...
8693 if (stat(con
->filename
, &fileinfo
))
8696 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
8698 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
8700 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
8701 IPP_TAG_INTEGER
)) != NULL
)
8702 attr
->values
[0].integer
+= kbytes
;
8705 * Add the job file...
8708 if (add_file(con
, job
, filetype
, compression
))
8711 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
8713 rename(con
->filename
, filename
);
8714 cupsdClearString(&con
->filename
);
8717 * See if we need to add the ending sheet...
8720 if (cupsdTimeoutJob(job
))
8724 * Log and save the job...
8727 cupsdLogJob(job
, CUPSD_LOG_INFO
,
8728 "File of type %s/%s queued by \"%s\".",
8729 filetype
->super
, filetype
->type
, job
->username
);
8730 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "hold_until=%d", (int)job
->hold_until
);
8731 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Queued on \"%s\" by \"%s\".",
8732 job
->dest
, job
->username
);
8735 * Start the job if possible...
8743 * 'read_job_ticket()' - Read a job ticket embedded in a print file.
8745 * This function only gets called when printing a single PDF or PostScript
8746 * file using the Print-Job operation. It doesn't work for Create-Job +
8747 * Send-File, since the job attributes need to be set at job creation
8748 * time for banners to work. The embedded job ticket stuff is here
8749 * primarily to allow the Windows printer driver for CUPS to pass in JCL
8750 * options and IPP attributes which otherwise would be lost.
8752 * The format of a job ticket is simple:
8754 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
8756 * %cupsJobTicket: attr1=value1
8757 * %cupsJobTicket: attr2=value2
8759 * %cupsJobTicket: attrN=valueN
8761 * Job ticket lines must appear immediately after the first line that
8762 * specifies PostScript (%!PS-Adobe-3.0) or PDF (%PDF) format, and CUPS
8763 * stops looking for job ticket info when it finds a line that does not begin
8764 * with "%cupsJobTicket:".
8766 * The maximum length of a job ticket line, including the prefix, is
8767 * 255 characters to conform with the Adobe DSC.
8769 * Read-only attributes are rejected with a notice to the error log in
8770 * case a malicious user tries anything. Since the job ticket is read
8771 * prior to attribute validation in print_job(), job ticket attributes
8772 * will go through the same validation as IPP attributes...
8776 read_job_ticket(cupsd_client_t
*con
) /* I - Client connection */
8778 cups_file_t
*fp
; /* File to read from */
8779 char line
[256]; /* Line data */
8780 int num_options
; /* Number of options */
8781 cups_option_t
*options
; /* Options */
8782 ipp_t
*ticket
; /* New attributes */
8783 ipp_attribute_t
*attr
, /* Current attribute */
8784 *attr2
, /* Job attribute */
8785 *prev2
; /* Previous job attribute */
8789 * First open the print file...
8792 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
8794 cupsdLogMessage(CUPSD_LOG_ERROR
,
8795 "Unable to open print file for job ticket - %s",
8801 * Skip the first line...
8804 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
8806 cupsdLogMessage(CUPSD_LOG_ERROR
,
8807 "Unable to read from print file for job ticket - %s",
8813 if (strncmp(line
, "%!PS-Adobe-", 11) && strncmp(line
, "%PDF-", 5))
8816 * Not a DSC-compliant file, so no job ticket info will be available...
8824 * Read job ticket info from the file...
8830 while (cupsFileGets(fp
, line
, sizeof(line
)))
8833 * Stop at the first non-ticket line...
8836 if (strncmp(line
, "%cupsJobTicket:", 15))
8840 * Add the options to the option array...
8843 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
8847 * Done with the file; see if we have any options...
8852 if (num_options
== 0)
8856 * OK, convert the options to an attribute list, and apply them to
8861 cupsEncodeOptions(ticket
, num_options
, options
);
8864 * See what the user wants to change.
8867 for (attr
= ticket
->attrs
; attr
; attr
= attr
->next
)
8869 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
8872 if (!strcmp(attr
->name
, "job-originating-host-name") ||
8873 !strcmp(attr
->name
, "job-originating-user-name") ||
8874 !strcmp(attr
->name
, "job-media-sheets-completed") ||
8875 !strcmp(attr
->name
, "job-k-octets") ||
8876 !strcmp(attr
->name
, "job-id") ||
8877 !strncmp(attr
->name
, "job-state", 9) ||
8878 !strncmp(attr
->name
, "time-at-", 8))
8879 continue; /* Read-only attrs */
8881 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
,
8882 IPP_TAG_ZERO
)) != NULL
)
8885 * Some other value; first free the old value...
8888 if (con
->request
->attrs
== attr2
)
8890 con
->request
->attrs
= attr2
->next
;
8895 for (prev2
= con
->request
->attrs
; prev2
; prev2
= prev2
->next
)
8896 if (prev2
->next
== attr2
)
8898 prev2
->next
= attr2
->next
;
8903 if (con
->request
->last
== attr2
)
8904 con
->request
->last
= prev2
;
8906 _ippFreeAttr(attr2
);
8910 * Add new option by copying it...
8913 copy_attribute(con
->request
, attr
, 0);
8917 * Then free the attribute list and option array...
8921 cupsFreeOptions(num_options
, options
);
8926 * 'reject_jobs()' - Reject print jobs to a printer.
8930 reject_jobs(cupsd_client_t
*con
, /* I - Client connection */
8931 ipp_attribute_t
*uri
) /* I - Printer or class URI */
8933 http_status_t status
; /* Policy status */
8934 cups_ptype_t dtype
; /* Destination type (printer/class) */
8935 cupsd_printer_t
*printer
; /* Printer data */
8936 ipp_attribute_t
*attr
; /* printer-state-message text */
8939 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "reject_jobs(%p[%d], %s)", con
,
8940 con
->http
.fd
, uri
->values
[0].string
.text
);
8943 * Is the destination valid?
8946 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
8952 send_ipp_status(con
, IPP_NOT_FOUND
,
8953 _("The printer or class was not found."));
8961 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
8963 send_http_error(con
, status
, printer
);
8968 * Reject jobs sent to the printer...
8971 printer
->accepting
= 0;
8973 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
8974 IPP_TAG_TEXT
)) == NULL
)
8975 strcpy(printer
->state_message
, "Rejecting Jobs");
8977 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
8978 sizeof(printer
->state_message
));
8980 cupsdAddPrinterHistory(printer
);
8982 if (dtype
& CUPS_PRINTER_CLASS
)
8984 cupsdMarkDirty(CUPSD_DIRTY_CLASSES
);
8986 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" rejecting jobs (\"%s\").",
8987 printer
->name
, get_username(con
));
8991 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
);
8993 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" rejecting jobs (\"%s\").",
8994 printer
->name
, get_username(con
));
8998 * Everything was ok, so return OK status...
9001 con
->response
->request
.status
.status_code
= IPP_OK
;
9006 * 'release_held_new_jobs()' - Release pending/new jobs on a printer or class.
9010 release_held_new_jobs(
9011 cupsd_client_t
*con
, /* I - Connection */
9012 ipp_attribute_t
*uri
) /* I - Printer URI */
9014 http_status_t status
; /* Policy status */
9015 cups_ptype_t dtype
; /* Destination type (printer/class) */
9016 cupsd_printer_t
*printer
; /* Printer data */
9019 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "release_held_new_jobs(%p[%d], %s)", con
,
9020 con
->http
.fd
, uri
->values
[0].string
.text
);
9023 * Is the destination valid?
9026 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
9032 send_ipp_status(con
, IPP_NOT_FOUND
,
9033 _("The printer or class was not found."));
9041 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
9043 send_http_error(con
, status
, printer
);
9048 * Hold pending/new jobs sent to the printer...
9051 printer
->holding_new_jobs
= 0;
9053 cupsdSetPrinterReasons(printer
, "-hold-new-jobs");
9054 cupsdAddPrinterHistory(printer
);
9056 if (dtype
& CUPS_PRINTER_CLASS
)
9057 cupsdLogMessage(CUPSD_LOG_INFO
,
9058 "Class \"%s\" now printing pending/new jobs (\"%s\").",
9059 printer
->name
, get_username(con
));
9061 cupsdLogMessage(CUPSD_LOG_INFO
,
9062 "Printer \"%s\" now printing pending/new jobs (\"%s\").",
9063 printer
->name
, get_username(con
));
9066 * Everything was ok, so return OK status...
9069 con
->response
->request
.status
.status_code
= IPP_OK
;
9074 * 'release_job()' - Release a held print job.
9078 release_job(cupsd_client_t
*con
, /* I - Client connection */
9079 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
9081 ipp_attribute_t
*attr
; /* Current attribute */
9082 int jobid
; /* Job ID */
9083 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
9084 username
[HTTP_MAX_URI
], /* Username portion of URI */
9085 host
[HTTP_MAX_URI
], /* Host portion of URI */
9086 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
9087 int port
; /* Port portion of URI */
9088 cupsd_job_t
*job
; /* Job information */
9091 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "release_job(%p[%d], %s)", con
,
9092 con
->http
.fd
, uri
->values
[0].string
.text
);
9095 * See if we have a job URI or a printer URI...
9098 if (!strcmp(uri
->name
, "printer-uri"))
9101 * Got a printer URI; see if we also have a job-id attribute...
9104 if ((attr
= ippFindAttribute(con
->request
, "job-id",
9105 IPP_TAG_INTEGER
)) == NULL
)
9107 send_ipp_status(con
, IPP_BAD_REQUEST
,
9108 _("Got a printer-uri attribute but no job-id!"));
9112 jobid
= attr
->values
[0].integer
;
9117 * Got a job URI; parse it to get the job ID...
9120 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
9121 sizeof(scheme
), username
, sizeof(username
), host
,
9122 sizeof(host
), &port
, resource
, sizeof(resource
));
9124 if (strncmp(resource
, "/jobs/", 6))
9130 send_ipp_status(con
, IPP_BAD_REQUEST
,
9131 _("Bad job-uri attribute \"%s\"!"),
9132 uri
->values
[0].string
.text
);
9136 jobid
= atoi(resource
+ 6);
9140 * See if the job exists...
9143 if ((job
= cupsdFindJob(jobid
)) == NULL
)
9146 * Nope - return a "not found" error...
9149 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
9154 * See if job is "held"...
9157 if (job
->state_value
!= IPP_JOB_HELD
)
9160 * Nope - return a "not possible" error...
9163 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Job #%d is not held!"), jobid
);
9168 * See if the job is owned by the requesting user...
9171 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
9173 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
9178 * Reset the job-hold-until value to "no-hold"...
9181 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
9182 IPP_TAG_KEYWORD
)) == NULL
)
9183 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
9187 _cupsStrFree(attr
->values
[0].string
.text
);
9189 attr
->value_tag
= IPP_TAG_KEYWORD
;
9190 attr
->values
[0].string
.text
= _cupsStrAlloc("no-hold");
9192 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, cupsdFindDest(job
->dest
), job
,
9193 "Job job-hold-until value changed by user.");
9197 * Release the job and return...
9200 cupsdReleaseJob(job
);
9202 cupsdAddEvent(CUPSD_EVENT_JOB_STATE
, cupsdFindDest(job
->dest
), job
,
9203 "Job released by user.");
9205 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Released by \"%s\".", username
);
9207 con
->response
->request
.status
.status_code
= IPP_OK
;
9214 * 'renew_subscription()' - Renew an existing subscription...
9219 cupsd_client_t
*con
, /* I - Client connection */
9220 int sub_id
) /* I - Subscription ID */
9222 http_status_t status
; /* Policy status */
9223 cupsd_subscription_t
*sub
; /* Subscription */
9224 ipp_attribute_t
*lease
; /* notify-lease-duration */
9227 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
9228 "renew_subscription(con=%p[%d], sub_id=%d)",
9229 con
, con
->http
.fd
, sub_id
);
9232 * Is the subscription ID valid?
9235 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
9238 * Bad subscription ID...
9241 send_ipp_status(con
, IPP_NOT_FOUND
,
9242 _("notify-subscription-id %d no good!"), sub_id
);
9249 * Job subscriptions cannot be renewed...
9252 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
9253 _("Job subscriptions cannot be renewed!"));
9261 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
9263 con
, sub
->owner
)) != HTTP_OK
)
9265 send_http_error(con
, status
, sub
->dest
);
9270 * Renew the subscription...
9273 lease
= ippFindAttribute(con
->request
, "notify-lease-duration",
9276 sub
->lease
= lease
? lease
->values
[0].integer
: DefaultLeaseDuration
;
9278 if (MaxLeaseDuration
&& (sub
->lease
== 0 || sub
->lease
> MaxLeaseDuration
))
9280 cupsdLogMessage(CUPSD_LOG_INFO
,
9281 "renew_subscription: Limiting notify-lease-duration to "
9284 sub
->lease
= MaxLeaseDuration
;
9287 sub
->expire
= sub
->lease
? time(NULL
) + sub
->lease
: 0;
9289 cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS
);
9291 con
->response
->request
.status
.status_code
= IPP_OK
;
9293 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
9294 "notify-lease-duration", sub
->lease
);
9299 * 'restart_job()' - Restart an old print job.
9303 restart_job(cupsd_client_t
*con
, /* I - Client connection */
9304 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
9306 ipp_attribute_t
*attr
; /* Current attribute */
9307 int jobid
; /* Job ID */
9308 char scheme
[HTTP_MAX_URI
], /* Method portion of URI */
9309 username
[HTTP_MAX_URI
], /* Username portion of URI */
9310 host
[HTTP_MAX_URI
], /* Host portion of URI */
9311 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
9312 int port
; /* Port portion of URI */
9313 cupsd_job_t
*job
; /* Job information */
9316 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "restart_job(%p[%d], %s)", con
,
9317 con
->http
.fd
, uri
->values
[0].string
.text
);
9320 * See if we have a job URI or a printer URI...
9323 if (!strcmp(uri
->name
, "printer-uri"))
9326 * Got a printer URI; see if we also have a job-id attribute...
9329 if ((attr
= ippFindAttribute(con
->request
, "job-id",
9330 IPP_TAG_INTEGER
)) == NULL
)
9332 send_ipp_status(con
, IPP_BAD_REQUEST
,
9333 _("Got a printer-uri attribute but no job-id!"));
9337 jobid
= attr
->values
[0].integer
;
9342 * Got a job URI; parse it to get the job ID...
9345 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
9346 sizeof(scheme
), username
, sizeof(username
), host
,
9347 sizeof(host
), &port
, resource
, sizeof(resource
));
9349 if (strncmp(resource
, "/jobs/", 6))
9355 send_ipp_status(con
, IPP_BAD_REQUEST
,
9356 _("Bad job-uri attribute \"%s\"!"),
9357 uri
->values
[0].string
.text
);
9361 jobid
= atoi(resource
+ 6);
9365 * See if the job exists...
9368 if ((job
= cupsdFindJob(jobid
)) == NULL
)
9371 * Nope - return a "not found" error...
9374 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
9379 * See if job is in any of the "completed" states...
9382 if (job
->state_value
<= IPP_JOB_PROCESSING
)
9385 * Nope - return a "not possible" error...
9388 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Job #%d is not complete!"),
9394 * See if we have retained the job files...
9399 if (!job
->attrs
|| job
->num_files
== 0)
9402 * Nope - return a "not possible" error...
9405 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
9406 _("Job #%d cannot be restarted - no files!"), jobid
);
9411 * See if the job is owned by the requesting user...
9414 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
9416 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
9421 * Restart the job and return...
9424 cupsdRestartJob(job
);
9426 cupsdLogJob(job
, CUPSD_LOG_INFO
, "Restarted by \"%s\".", username
);
9428 con
->response
->request
.status
.status_code
= IPP_OK
;
9433 * 'save_auth_info()' - Save authentication information for a job.
9438 cupsd_client_t
*con
, /* I - Client connection */
9439 cupsd_job_t
*job
, /* I - Job */
9440 ipp_attribute_t
*auth_info
) /* I - auth-info attribute, if any */
9442 int i
; /* Looping var */
9443 char filename
[1024]; /* Job authentication filename */
9444 cups_file_t
*fp
; /* Job authentication file */
9445 char line
[2048]; /* Line for file */
9446 cupsd_printer_t
*dest
; /* Destination printer/class */
9450 * This function saves the in-memory authentication information for
9451 * a job so that it can be used to authenticate with a remote host.
9452 * The information is stored in a file that is readable only by the
9453 * root user. The fields are Base-64 encoded, each on a separate line,
9454 * followed by random number (up to 1024) of newlines to limit the
9455 * amount of information that is exposed.
9457 * Because of the potential for exposing of authentication information,
9458 * this functionality is only enabled when running cupsd as root.
9460 * This caching only works for the Basic and BasicDigest authentication
9461 * types. Digest authentication cannot be cached this way, and in
9462 * the future Kerberos authentication may make all of this obsolete.
9464 * Authentication information is saved whenever an authenticated
9465 * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
9468 * This information is deleted after a job is completed or canceled,
9469 * so reprints may require subsequent re-authentication.
9475 if ((dest
= cupsdFindDest(job
->dest
)) == NULL
)
9479 * Create the authentication file and change permissions...
9482 snprintf(filename
, sizeof(filename
), "%s/a%05d", RequestRoot
, job
->id
);
9483 if ((fp
= cupsFileOpen(filename
, "w")) == NULL
)
9485 cupsdLogMessage(CUPSD_LOG_ERROR
,
9486 "Unable to save authentication info to \"%s\" - %s",
9487 filename
, strerror(errno
));
9491 fchown(cupsFileNumber(fp
), 0, 0);
9492 fchmod(cupsFileNumber(fp
), 0400);
9494 if (auth_info
&& auth_info
->num_values
== dest
->num_auth_info_required
)
9497 * Write 1 to 3 auth values...
9500 cupsdClearString(&job
->auth_username
);
9501 cupsdClearString(&job
->auth_domain
);
9502 cupsdClearString(&job
->auth_password
);
9504 for (i
= 0; i
< auth_info
->num_values
; i
++)
9506 httpEncode64_2(line
, sizeof(line
), auth_info
->values
[i
].string
.text
,
9507 strlen(auth_info
->values
[i
].string
.text
));
9508 cupsFilePrintf(fp
, "%s\n", line
);
9510 if (!strcmp(dest
->auth_info_required
[i
], "username"))
9511 cupsdSetStringf(&job
->auth_username
, "AUTH_USERNAME=%s",
9512 auth_info
->values
[i
].string
.text
);
9513 else if (!strcmp(dest
->auth_info_required
[i
], "domain"))
9514 cupsdSetStringf(&job
->auth_domain
, "AUTH_DOMAIN=%s",
9515 auth_info
->values
[i
].string
.text
);
9516 else if (!strcmp(dest
->auth_info_required
[i
], "password"))
9517 cupsdSetStringf(&job
->auth_password
, "AUTH_PASSWORD=%s",
9518 auth_info
->values
[i
].string
.text
);
9521 else if (con
->username
[0])
9524 * Write the authenticated username...
9527 httpEncode64_2(line
, sizeof(line
), con
->username
, strlen(con
->username
));
9528 cupsFilePrintf(fp
, "%s\n", line
);
9530 cupsdSetStringf(&job
->auth_username
, "AUTH_USERNAME=%s", con
->username
);
9531 cupsdClearString(&job
->auth_domain
);
9534 * Write the authenticated password...
9537 httpEncode64_2(line
, sizeof(line
), con
->password
, strlen(con
->password
));
9538 cupsFilePrintf(fp
, "%s\n", line
);
9540 cupsdSetStringf(&job
->auth_password
, "AUTH_PASSWORD=%s", con
->password
);
9544 * Write a random number of newlines to the end of the file...
9547 for (i
= (rand() % 1024); i
>= 0; i
--)
9548 cupsFilePutChar(fp
, '\n');
9551 * Close the file and return...
9556 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
9557 if (con
->gss_have_creds
)
9558 save_krb5_creds(con
, job
);
9559 else if (job
->ccname
)
9560 cupsdClearString(&(job
->ccname
));
9561 #endif /* HAVE_GSSAPI && HAVE_KRB5_H */
9565 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
9567 * 'save_krb5_creds()' - Save Kerberos credentials for the job.
9571 save_krb5_creds(cupsd_client_t
*con
, /* I - Client connection */
9572 cupsd_job_t
*job
) /* I - Job */
9574 # if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL)
9575 cupsdLogMessage(CUPSD_LOG_INFO
,
9576 "Sorry, your version of Kerberos does not support delegated "
9581 krb5_error_code error
; /* Kerberos error code */
9582 OM_uint32 major_status
, /* Major status code */
9583 minor_status
; /* Minor status code */
9584 krb5_principal principal
; /* Kerberos principal */
9589 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
9593 if (krb5_init_context
== NULL
)
9595 # endif /* __APPLE__ */
9597 if (!KerberosInitialized
)
9600 * Setup a Kerberos context for the scheduler to use...
9603 KerberosInitialized
= 1;
9605 if (krb5_init_context(&KerberosContext
))
9607 KerberosContext
= NULL
;
9609 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to initialize Kerberos context");
9615 * We MUST create a file-based cache because memory-based caches are
9616 * only valid for the current process/address space.
9618 * Due to various bugs/features in different versions of Kerberos, we
9619 * need either the krb5_cc_new_unique() function or Heimdal's version
9620 * of krb5_cc_gen_new() to create a new FILE: credential cache that
9621 * can be passed to the backend. These functions create a temporary
9622 * file (typically in /tmp) containing the cached credentials, which
9623 * are removed when we have successfully printed a job.
9626 # ifdef HAVE_KRB5_CC_NEW_UNIQUE
9627 if ((error
= krb5_cc_new_unique(KerberosContext
, "FILE", NULL
,
9628 &(job
->ccache
))) != 0)
9629 # else /* HAVE_HEIMDAL */
9630 if ((error
= krb5_cc_gen_new(KerberosContext
, &krb5_fcc_ops
,
9631 &(job
->ccache
))) != 0)
9632 # endif /* HAVE_KRB5_CC_NEW_UNIQUE */
9634 cupsdLogMessage(CUPSD_LOG_ERROR
,
9635 "Unable to create new credentials cache (%d/%s)",
9636 error
, strerror(errno
));
9641 if ((error
= krb5_parse_name(KerberosContext
, con
->username
, &principal
)) != 0)
9643 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to parse kerberos username (%d/%s)",
9644 error
, strerror(errno
));
9645 krb5_cc_destroy(KerberosContext
, job
->ccache
);
9650 if ((error
= krb5_cc_initialize(KerberosContext
, job
->ccache
, principal
)))
9652 cupsdLogMessage(CUPSD_LOG_ERROR
,
9653 "Unable to initialize credentials cache (%d/%s)", error
,
9655 krb5_cc_destroy(KerberosContext
, job
->ccache
);
9656 krb5_free_principal(KerberosContext
, principal
);
9661 krb5_free_principal(KerberosContext
, principal
);
9664 * Copy the user's credentials to the new cache file...
9667 major_status
= gss_krb5_copy_ccache(&minor_status
, con
->gss_delegated_cred
,
9670 if (GSS_ERROR(major_status
))
9672 cupsdLogGSSMessage(CUPSD_LOG_ERROR
, major_status
, minor_status
,
9673 "Unable to import client credentials cache");
9674 krb5_cc_destroy(KerberosContext
, job
->ccache
);
9680 * Add the KRB5CCNAME environment variable to the job so that the
9681 * backend can use the credentials when printing.
9684 cupsdSetStringf(&(job
->ccname
), "KRB5CCNAME=FILE:%s",
9685 krb5_cc_get_name(KerberosContext
, job
->ccache
));
9687 cupsdLogJob(job
, CUPSD_LOG_DEBUG2
, "save_krb5_creds: %s", job
->ccname
);
9688 # endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */
9690 #endif /* HAVE_GSSAPI && HAVE_KRB5_H */
9694 * 'send_document()' - Send a file to a printer or class.
9698 send_document(cupsd_client_t
*con
, /* I - Client connection */
9699 ipp_attribute_t
*uri
) /* I - Printer URI */
9701 ipp_attribute_t
*attr
; /* Current attribute */
9702 ipp_attribute_t
*format
; /* Request's document-format attribute */
9703 ipp_attribute_t
*jformat
; /* Job's document-format attribute */
9704 const char *default_format
;/* document-format-default value */
9705 int jobid
; /* Job ID number */
9706 cupsd_job_t
*job
; /* Current job */
9707 char job_uri
[HTTP_MAX_URI
],
9709 scheme
[HTTP_MAX_URI
],
9710 /* Method portion of URI */
9711 username
[HTTP_MAX_URI
],
9712 /* Username portion of URI */
9714 /* Host portion of URI */
9715 resource
[HTTP_MAX_URI
];
9716 /* Resource portion of URI */
9717 int port
; /* Port portion of URI */
9718 mime_type_t
*filetype
; /* Type of file */
9719 char super
[MIME_MAX_SUPER
],
9720 /* Supertype of file */
9721 type
[MIME_MAX_TYPE
],
9722 /* Subtype of file */
9723 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
9724 /* Textual name of mime type */
9725 char filename
[1024]; /* Job filename */
9726 cupsd_printer_t
*printer
; /* Current printer */
9727 struct stat fileinfo
; /* File information */
9728 int kbytes
; /* Size of file */
9729 int compression
; /* Type of compression */
9730 int start_job
; /* Start the job? */
9733 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_document(%p[%d], %s)", con
,
9734 con
->http
.fd
, uri
->values
[0].string
.text
);
9737 * See if we have a job URI or a printer URI...
9740 if (!strcmp(uri
->name
, "printer-uri"))
9743 * Got a printer URI; see if we also have a job-id attribute...
9746 if ((attr
= ippFindAttribute(con
->request
, "job-id",
9747 IPP_TAG_INTEGER
)) == NULL
)
9749 send_ipp_status(con
, IPP_BAD_REQUEST
,
9750 _("Got a printer-uri attribute but no job-id!"));
9754 jobid
= attr
->values
[0].integer
;
9759 * Got a job URI; parse it to get the job ID...
9762 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
9763 sizeof(scheme
), username
, sizeof(username
), host
,
9764 sizeof(host
), &port
, resource
, sizeof(resource
));
9766 if (strncmp(resource
, "/jobs/", 6))
9772 send_ipp_status(con
, IPP_BAD_REQUEST
,
9773 _("Bad job-uri attribute \"%s\"!"),
9774 uri
->values
[0].string
.text
);
9778 jobid
= atoi(resource
+ 6);
9782 * See if the job exists...
9785 if ((job
= cupsdFindJob(jobid
)) == NULL
)
9788 * Nope - return a "not found" error...
9791 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
9795 printer
= cupsdFindDest(job
->dest
);
9798 * See if the job is owned by the requesting user...
9801 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
9803 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
9808 * OK, see if the client is sending the document compressed - CUPS
9809 * only supports "none" and "gzip".
9812 compression
= CUPS_FILE_NONE
;
9814 if ((attr
= ippFindAttribute(con
->request
, "compression",
9815 IPP_TAG_KEYWORD
)) != NULL
)
9817 if (strcmp(attr
->values
[0].string
.text
, "none")
9819 && strcmp(attr
->values
[0].string
.text
, "gzip")
9820 #endif /* HAVE_LIBZ */
9823 send_ipp_status(con
, IPP_ATTRIBUTES
, _("Unsupported compression \"%s\"!"),
9824 attr
->values
[0].string
.text
);
9825 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
9826 "compression", NULL
, attr
->values
[0].string
.text
);
9831 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
9832 compression
= CUPS_FILE_GZIP
;
9833 #endif /* HAVE_LIBZ */
9837 * Do we have a file to print?
9842 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No file!?!"));
9847 * Is it a format we support?
9850 if ((format
= ippFindAttribute(con
->request
, "document-format",
9851 IPP_TAG_MIMETYPE
)) != NULL
)
9854 * Grab format from client...
9857 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]",
9860 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad document-format \"%s\"!"),
9861 format
->values
[0].string
.text
);
9865 else if ((default_format
= cupsGetOption("document-format",
9866 printer
->num_options
,
9867 printer
->options
)) != NULL
)
9870 * Use default document format...
9873 if (sscanf(default_format
, "%15[^/]/%31[^;]", super
, type
) != 2)
9875 send_ipp_status(con
, IPP_BAD_REQUEST
,
9876 _("Could not scan type \"%s\"!"),
9884 * No document format attribute? Auto-type it!
9887 strcpy(super
, "application");
9888 strcpy(type
, "octet-stream");
9891 if (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))
9894 * Auto-type the file...
9897 ipp_attribute_t
*doc_name
; /* document-name attribute */
9900 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Auto-typing file...");
9902 doc_name
= ippFindAttribute(con
->request
, "document-name", IPP_TAG_NAME
);
9903 filetype
= mimeFileType(MimeDatabase
, con
->filename
,
9904 doc_name
? doc_name
->values
[0].string
.text
: NULL
,
9908 filetype
= mimeType(MimeDatabase
, super
, type
);
9910 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Request file type is %s/%s.",
9911 filetype
->super
, filetype
->type
);
9914 filetype
= mimeType(MimeDatabase
, super
, type
);
9919 * Replace the document-format attribute value with the auto-typed or
9923 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
9926 if ((jformat
= ippFindAttribute(job
->attrs
, "document-format",
9927 IPP_TAG_MIMETYPE
)) != NULL
)
9929 _cupsStrFree(jformat
->values
[0].string
.text
);
9931 jformat
->values
[0].string
.text
= _cupsStrAlloc(mimetype
);
9934 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
9935 "document-format", NULL
, mimetype
);
9939 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
9940 _("Unsupported format \'%s/%s\'!"), super
, type
);
9941 cupsdLogMessage(CUPSD_LOG_INFO
,
9942 "Hint: Do you have the raw file printing rules enabled?");
9945 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
9946 "document-format", NULL
, format
->values
[0].string
.text
);
9951 if (printer
->filetypes
&& !cupsArrayFind(printer
->filetypes
, filetype
))
9953 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
9956 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
9957 _("Unsupported format \'%s\'!"), mimetype
);
9959 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
9960 "document-format", NULL
, mimetype
);
9966 * Add the file to the job...
9971 if (add_file(con
, job
, filetype
, compression
))
9974 if (stat(con
->filename
, &fileinfo
))
9977 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
9979 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
9981 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
9982 IPP_TAG_INTEGER
)) != NULL
)
9983 attr
->values
[0].integer
+= kbytes
;
9985 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
9987 rename(con
->filename
, filename
);
9989 cupsdClearString(&con
->filename
);
9991 cupsdLogJob(job
, CUPSD_LOG_INFO
, "File of type %s/%s queued by \"%s\".",
9992 filetype
->super
, filetype
->type
, job
->username
);
9995 * Start the job if this is the last document...
9998 if ((attr
= ippFindAttribute(con
->request
, "last-document",
9999 IPP_TAG_BOOLEAN
)) != NULL
&&
10000 attr
->values
[0].boolean
)
10003 * See if we need to add the ending sheet...
10006 if (cupsdTimeoutJob(job
))
10009 if (job
->state_value
== IPP_JOB_STOPPED
)
10011 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
10012 job
->state_value
= IPP_JOB_PENDING
;
10014 else if (job
->state_value
== IPP_JOB_HELD
)
10016 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
10017 IPP_TAG_KEYWORD
)) == NULL
)
10018 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
10020 if (!attr
|| !strcmp(attr
->values
[0].string
.text
, "no-hold"))
10022 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
10023 job
->state_value
= IPP_JOB_PENDING
;
10028 cupsdMarkDirty(CUPSD_DIRTY_JOBS
);
10034 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
10035 IPP_TAG_KEYWORD
)) == NULL
)
10036 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
10038 if (!attr
|| !strcmp(attr
->values
[0].string
.text
, "no-hold"))
10040 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
10041 job
->state_value
= IPP_JOB_HELD
;
10042 job
->hold_until
= time(NULL
) + MultipleOperationTimeout
;
10045 cupsdMarkDirty(CUPSD_DIRTY_JOBS
);
10052 * Fill in the response info...
10055 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
10058 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
10061 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
10063 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
10065 add_job_state_reasons(con
, job
);
10067 con
->response
->request
.status
.status_code
= IPP_OK
;
10070 * Start the job if necessary...
10079 * 'send_http_error()' - Send a HTTP error back to the IPP client.
10084 cupsd_client_t
*con
, /* I - Client connection */
10085 http_status_t status
, /* I - HTTP status code */
10086 cupsd_printer_t
*printer
) /* I - Printer, if any */
10088 ipp_attribute_t
*uri
; /* Request URI, if any */
10091 if ((uri
= ippFindAttribute(con
->request
, "printer-uri",
10092 IPP_TAG_URI
)) == NULL
)
10093 uri
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
);
10095 cupsdLogMessage(status
== HTTP_FORBIDDEN
? CUPSD_LOG_ERROR
: CUPSD_LOG_DEBUG
,
10096 "Returning HTTP %s for %s (%s) from %s",
10097 httpStatus(status
),
10098 ippOpString(con
->request
->request
.op
.operation_id
),
10099 uri
? uri
->values
[0].string
.text
: "no URI",
10100 con
->http
.hostname
);
10104 int auth_type
; /* Type of authentication required */
10107 auth_type
= CUPSD_AUTH_NONE
;
10109 if (status
== HTTP_UNAUTHORIZED
&&
10110 printer
->num_auth_info_required
> 0 &&
10111 !strcmp(printer
->auth_info_required
[0], "negotiate") &&
10113 (con
->request
->request
.op
.operation_id
== IPP_PRINT_JOB
||
10114 con
->request
->request
.op
.operation_id
== IPP_CREATE_JOB
||
10115 con
->request
->request
.op
.operation_id
== CUPS_AUTHENTICATE_JOB
))
10118 * Creating and authenticating jobs requires Kerberos...
10121 auth_type
= CUPSD_AUTH_NEGOTIATE
;
10126 * Use policy/location-defined authentication requirements...
10129 char resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
10130 cupsd_location_t
*auth
; /* Pointer to authentication element */
10133 if (printer
->type
& CUPS_PRINTER_CLASS
)
10134 snprintf(resource
, sizeof(resource
), "/classes/%s", printer
->name
);
10136 snprintf(resource
, sizeof(resource
), "/printers/%s", printer
->name
);
10138 if ((auth
= cupsdFindBest(resource
, HTTP_POST
)) == NULL
||
10139 auth
->type
== CUPSD_AUTH_NONE
)
10140 auth
= cupsdFindPolicyOp(printer
->op_policy_ptr
,
10142 con
->request
->request
.op
.operation_id
:
10147 if (auth
->type
== CUPSD_AUTH_DEFAULT
)
10148 auth_type
= DefaultAuthType
;
10150 auth_type
= auth
->type
;
10154 cupsdSendError(con
, status
, auth_type
);
10157 cupsdSendError(con
, status
, CUPSD_AUTH_NONE
);
10159 ippDelete(con
->response
);
10160 con
->response
= NULL
;
10167 * 'send_ipp_status()' - Send a status back to the IPP client.
10171 send_ipp_status(cupsd_client_t
*con
, /* I - Client connection */
10172 ipp_status_t status
, /* I - IPP status code */
10173 const char *message
,/* I - Status message */
10174 ...) /* I - Additional args as needed */
10176 va_list ap
; /* Pointer to additional args */
10177 char formatted
[1024]; /* Formatted errror message */
10180 va_start(ap
, message
);
10181 vsnprintf(formatted
, sizeof(formatted
),
10182 _cupsLangString(con
->language
, message
), ap
);
10185 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s %s: %s",
10186 ippOpString(con
->request
->request
.op
.operation_id
),
10187 ippErrorString(status
), formatted
);
10189 con
->response
->request
.status
.status_code
= status
;
10191 if (ippFindAttribute(con
->response
, "attributes-charset",
10192 IPP_TAG_ZERO
) == NULL
)
10193 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
10194 "attributes-charset", NULL
, DefaultCharset
);
10196 if (ippFindAttribute(con
->response
, "attributes-natural-language",
10197 IPP_TAG_ZERO
) == NULL
)
10198 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
10199 "attributes-natural-language", NULL
, DefaultLanguage
);
10201 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
10202 "status-message", NULL
, formatted
);
10207 * 'set_default()' - Set the default destination...
10211 set_default(cupsd_client_t
*con
, /* I - Client connection */
10212 ipp_attribute_t
*uri
) /* I - Printer URI */
10214 http_status_t status
; /* Policy status */
10215 cups_ptype_t dtype
; /* Destination type (printer/class) */
10216 cupsd_printer_t
*printer
, /* Printer */
10217 *oldprinter
; /* Old default printer */
10220 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_default(%p[%d], %s)", con
,
10221 con
->http
.fd
, uri
->values
[0].string
.text
);
10224 * Is the destination valid?
10227 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
10233 send_ipp_status(con
, IPP_NOT_FOUND
,
10234 _("The printer or class was not found."));
10242 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
10244 send_http_error(con
, status
, NULL
);
10249 * Set it as the default...
10252 oldprinter
= DefaultPrinter
;
10253 DefaultPrinter
= printer
;
10256 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE
, oldprinter
, NULL
,
10257 "%s is no longer the default printer.", oldprinter
->name
);
10259 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE
, printer
, NULL
,
10260 "%s is now the default printer.", printer
->name
);
10262 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
| CUPSD_DIRTY_CLASSES
|
10263 CUPSD_DIRTY_REMOTE
| CUPSD_DIRTY_PRINTCAP
);
10265 cupsdLogMessage(CUPSD_LOG_INFO
,
10266 "Default destination set to \"%s\" by \"%s\".",
10267 printer
->name
, get_username(con
));
10270 * Everything was ok, so return OK status...
10273 con
->response
->request
.status
.status_code
= IPP_OK
;
10278 * 'set_job_attrs()' - Set job attributes.
10282 set_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
10283 ipp_attribute_t
*uri
) /* I - Job URI */
10285 ipp_attribute_t
*attr
, /* Current attribute */
10286 *attr2
; /* Job attribute */
10287 int jobid
; /* Job ID */
10288 cupsd_job_t
*job
; /* Current job */
10289 char scheme
[HTTP_MAX_URI
],
10290 /* Method portion of URI */
10291 username
[HTTP_MAX_URI
],
10292 /* Username portion of URI */
10293 host
[HTTP_MAX_URI
],
10294 /* Host portion of URI */
10295 resource
[HTTP_MAX_URI
];
10296 /* Resource portion of URI */
10297 int port
; /* Port portion of URI */
10298 int event
; /* Events? */
10299 int check_jobs
; /* Check jobs? */
10302 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_job_attrs(%p[%d], %s)", con
,
10303 con
->http
.fd
, uri
->values
[0].string
.text
);
10306 * Start with "everything is OK" status...
10309 con
->response
->request
.status
.status_code
= IPP_OK
;
10312 * See if we have a job URI or a printer URI...
10315 if (!strcmp(uri
->name
, "printer-uri"))
10318 * Got a printer URI; see if we also have a job-id attribute...
10321 if ((attr
= ippFindAttribute(con
->request
, "job-id",
10322 IPP_TAG_INTEGER
)) == NULL
)
10324 send_ipp_status(con
, IPP_BAD_REQUEST
,
10325 _("Got a printer-uri attribute but no job-id!"));
10329 jobid
= attr
->values
[0].integer
;
10334 * Got a job URI; parse it to get the job ID...
10337 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
10338 sizeof(scheme
), username
, sizeof(username
), host
,
10339 sizeof(host
), &port
, resource
, sizeof(resource
));
10341 if (strncmp(resource
, "/jobs/", 6))
10347 send_ipp_status(con
, IPP_BAD_REQUEST
,
10348 _("Bad job-uri attribute \"%s\"!"),
10349 uri
->values
[0].string
.text
);
10353 jobid
= atoi(resource
+ 6);
10357 * See if the job exists...
10360 if ((job
= cupsdFindJob(jobid
)) == NULL
)
10363 * Nope - return a "not found" error...
10366 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
10371 * See if the job has been completed...
10374 if (job
->state_value
> IPP_JOB_STOPPED
)
10377 * Return a "not-possible" error...
10380 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10381 _("Job #%d is finished and cannot be altered!"), jobid
);
10386 * See if the job is owned by the requesting user...
10389 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
10391 send_http_error(con
, HTTP_UNAUTHORIZED
, cupsdFindDest(job
->dest
));
10396 * See what the user wants to change.
10404 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
10406 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
10409 if (!strcmp(attr
->name
, "attributes-charset") ||
10410 !strcmp(attr
->name
, "attributes-natural-language") ||
10411 !strcmp(attr
->name
, "document-compression") ||
10412 !strcmp(attr
->name
, "document-format") ||
10413 !strcmp(attr
->name
, "job-detailed-status-messages") ||
10414 !strcmp(attr
->name
, "job-document-access-errors") ||
10415 !strcmp(attr
->name
, "job-id") ||
10416 !strcmp(attr
->name
, "job-impressions-completed") ||
10417 !strcmp(attr
->name
, "job-k-octets") ||
10418 !strcmp(attr
->name
, "job-originating-host-name") ||
10419 !strcmp(attr
->name
, "job-originating-user-name") ||
10420 !strcmp(attr
->name
, "job-printer-up-time") ||
10421 !strcmp(attr
->name
, "job-printer-uri") ||
10422 !strcmp(attr
->name
, "job-sheets") ||
10423 !strcmp(attr
->name
, "job-state-message") ||
10424 !strcmp(attr
->name
, "job-state-reasons") ||
10425 !strcmp(attr
->name
, "job-uri") ||
10426 !strcmp(attr
->name
, "number-of-documents") ||
10427 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
10428 !strcmp(attr
->name
, "output-device-assigned") ||
10429 !strncmp(attr
->name
, "date-time-at-", 13) ||
10430 !strncmp(attr
->name
, "job-k-octets", 12) ||
10431 !strncmp(attr
->name
, "job-media-sheets", 16) ||
10432 !strncmp(attr
->name
, "time-at-", 8))
10438 send_ipp_status(con
, IPP_ATTRIBUTES_NOT_SETTABLE
,
10439 _("%s cannot be changed."), attr
->name
);
10441 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
10442 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
10447 if (!strcmp(attr
->name
, "job-priority"))
10450 * Change the job priority...
10453 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
10455 send_ipp_status(con
, IPP_REQUEST_VALUE
, _("Bad job-priority value!"));
10457 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
10458 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
10460 else if (job
->state_value
>= IPP_JOB_PROCESSING
)
10462 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10463 _("Job is completed and cannot be changed."));
10466 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
10468 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Setting job-priority to %d",
10469 attr
->values
[0].integer
);
10470 cupsdSetJobPriority(job
, attr
->values
[0].integer
);
10473 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
|
10474 CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED
;
10477 else if (!strcmp(attr
->name
, "job-state"))
10480 * Change the job state...
10483 if (attr
->value_tag
!= IPP_TAG_ENUM
)
10485 send_ipp_status(con
, IPP_REQUEST_VALUE
, _("Bad job-state value!"));
10487 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
10488 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
10492 switch (attr
->values
[0].integer
)
10494 case IPP_JOB_PENDING
:
10495 case IPP_JOB_HELD
:
10496 if (job
->state_value
> IPP_JOB_HELD
)
10498 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10499 _("Job state cannot be changed."));
10502 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
10504 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Setting job-state to %d",
10505 attr
->values
[0].integer
);
10506 cupsdSetJobState(job
, attr
->values
[0].integer
,
10508 "Job state changed by \"%s\"", username
);
10513 case IPP_JOB_PROCESSING
:
10514 case IPP_JOB_STOPPED
:
10515 if (job
->state_value
!= attr
->values
[0].integer
)
10517 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10518 _("Job state cannot be changed."));
10523 case IPP_JOB_CANCELED
:
10524 case IPP_JOB_ABORTED
:
10525 case IPP_JOB_COMPLETED
:
10526 if (job
->state_value
> IPP_JOB_PROCESSING
)
10528 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10529 _("Job state cannot be changed."));
10532 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
10534 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Setting job-state to %d",
10535 attr
->values
[0].integer
);
10536 cupsdSetJobState(job
, (ipp_jstate_t
)attr
->values
[0].integer
,
10538 "Job state changed by \"%s\"", username
);
10545 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
10547 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
,
10548 IPP_TAG_ZERO
)) != NULL
)
10551 * Some other value; first free the old value...
10554 if (job
->attrs
->prev
)
10555 job
->attrs
->prev
->next
= attr2
->next
;
10557 job
->attrs
->attrs
= attr2
->next
;
10559 if (job
->attrs
->last
== attr2
)
10560 job
->attrs
->last
= job
->attrs
->prev
;
10562 _ippFreeAttr(attr2
);
10565 * Then copy the attribute...
10568 copy_attribute(job
->attrs
, attr
, 0);
10571 * See if the job-name or job-hold-until is being changed.
10574 if (!strcmp(attr
->name
, "job-hold-until"))
10576 cupsdLogJob(job
, CUPSD_LOG_DEBUG
, "Setting job-hold-until to %s",
10577 attr
->values
[0].string
.text
);
10578 cupsdSetJobHoldUntil(job
, attr
->values
[0].string
.text
, 0);
10580 if (!strcmp(attr
->values
[0].string
.text
, "no-hold"))
10582 cupsdReleaseJob(job
);
10586 cupsdSetJobState(job
, IPP_JOB_HELD
, CUPSD_JOB_DEFAULT
,
10587 "Job held by \"%s\".", username
);
10589 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
| CUPSD_EVENT_JOB_STATE
;
10592 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
10595 * Delete the attribute...
10598 if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
,
10599 IPP_TAG_ZERO
)) != NULL
)
10601 if (job
->attrs
->prev
)
10602 job
->attrs
->prev
->next
= attr2
->next
;
10604 job
->attrs
->attrs
= attr2
->next
;
10606 if (attr2
== job
->attrs
->last
)
10607 job
->attrs
->last
= job
->attrs
->prev
;
10609 _ippFreeAttr(attr2
);
10611 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
;
10617 * Add new option by copying it...
10620 copy_attribute(job
->attrs
, attr
, 0);
10622 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
;
10631 cupsdMarkDirty(CUPSD_DIRTY_JOBS
);
10634 * Send events as needed...
10637 if (event
& CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED
)
10638 cupsdAddEvent(CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED
,
10639 cupsdFindDest(job
->dest
), job
,
10640 "Job priority changed by user.");
10642 if (event
& CUPSD_EVENT_JOB_STATE
)
10643 cupsdAddEvent(CUPSD_EVENT_JOB_STATE
, cupsdFindDest(job
->dest
), job
,
10644 job
->state_value
== IPP_JOB_HELD
?
10645 "Job held by user." : "Job restarted by user.");
10647 if (event
& CUPSD_EVENT_JOB_CONFIG_CHANGED
)
10648 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, cupsdFindDest(job
->dest
), job
,
10649 "Job options changed by user.");
10652 * Start jobs if possible...
10661 * 'set_printer_attrs()' - Set printer attributes.
10665 set_printer_attrs(cupsd_client_t
*con
, /* I - Client connection */
10666 ipp_attribute_t
*uri
) /* I - Printer */
10668 http_status_t status
; /* Policy status */
10669 cups_ptype_t dtype
; /* Destination type (printer/class) */
10670 cupsd_printer_t
*printer
; /* Printer/class */
10671 ipp_attribute_t
*attr
; /* Printer attribute */
10672 int changed
= 0; /* Was anything changed? */
10675 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_printer_attrs(%p[%d], %s)", con
,
10676 con
->http
.fd
, uri
->values
[0].string
.text
);
10679 * Is the destination valid?
10682 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
10688 send_ipp_status(con
, IPP_NOT_FOUND
,
10689 _("The printer or class was not found."));
10697 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
10699 send_http_error(con
, status
, printer
);
10704 * Return a list of attributes that can be set via Set-Printer-Attributes.
10707 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
10708 IPP_TAG_TEXT
)) != NULL
)
10710 cupsdSetString(&printer
->location
, attr
->values
[0].string
.text
);
10714 if ((attr
= ippFindAttribute(con
->request
, "printer-info",
10715 IPP_TAG_TEXT
)) != NULL
)
10717 cupsdSetString(&printer
->info
, attr
->values
[0].string
.text
);
10722 * Update the printer attributes and return...
10727 cupsdSetPrinterAttrs(printer
);
10728 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS
);
10730 cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG
, printer
, NULL
,
10731 "Printer \"%s\" description or location changed by \"%s\".",
10732 printer
->name
, get_username(con
));
10734 cupsdLogMessage(CUPSD_LOG_INFO
,
10735 "Printer \"%s\" description or location changed by \"%s\".",
10736 printer
->name
, get_username(con
));
10739 con
->response
->request
.status
.status_code
= IPP_OK
;
10744 * 'set_printer_defaults()' - Set printer default options from a request.
10748 set_printer_defaults(
10749 cupsd_client_t
*con
, /* I - Client connection */
10750 cupsd_printer_t
*printer
) /* I - Printer */
10752 int i
; /* Looping var */
10753 ipp_attribute_t
*attr
; /* Current attribute */
10754 int namelen
; /* Length of attribute name */
10755 char name
[256], /* New attribute name */
10756 value
[256]; /* String version of integer attrs */
10759 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
10762 * Skip non-printer attributes...
10765 if (attr
->group_tag
!= IPP_TAG_PRINTER
|| !attr
->name
)
10768 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_printer_defaults: %s", attr
->name
);
10770 if (!strcmp(attr
->name
, "job-sheets-default"))
10773 * Only allow keywords and names...
10776 if (attr
->value_tag
!= IPP_TAG_NAME
&& attr
->value_tag
!= IPP_TAG_KEYWORD
)
10780 * Only allow job-sheets-default to be set when running without a
10781 * system high classification level...
10784 if (Classification
)
10787 cupsdSetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
10789 if (attr
->num_values
> 1)
10790 cupsdSetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
10792 cupsdSetString(&printer
->job_sheets
[1], "none");
10794 else if (!strcmp(attr
->name
, "requesting-user-name-allowed"))
10796 cupsdFreePrinterUsers(printer
);
10798 printer
->deny_users
= 0;
10800 if (attr
->value_tag
== IPP_TAG_NAME
&&
10801 (attr
->num_values
> 1 ||
10802 strcmp(attr
->values
[0].string
.text
, "all")))
10804 for (i
= 0; i
< attr
->num_values
; i
++)
10805 cupsdAddPrinterUser(printer
, attr
->values
[i
].string
.text
);
10808 else if (!strcmp(attr
->name
, "requesting-user-name-denied"))
10810 cupsdFreePrinterUsers(printer
);
10812 printer
->deny_users
= 1;
10814 if (attr
->value_tag
== IPP_TAG_NAME
&&
10815 (attr
->num_values
> 1 ||
10816 strcmp(attr
->values
[0].string
.text
, "none")))
10818 for (i
= 0; i
< attr
->num_values
; i
++)
10819 cupsdAddPrinterUser(printer
, attr
->values
[i
].string
.text
);
10822 else if (!strcmp(attr
->name
, "job-quota-period"))
10824 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
10827 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-quota-period to %d...",
10828 attr
->values
[0].integer
);
10829 cupsdFreeQuotas(printer
);
10831 printer
->quota_period
= attr
->values
[0].integer
;
10833 else if (!strcmp(attr
->name
, "job-k-limit"))
10835 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
10838 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-k-limit to %d...",
10839 attr
->values
[0].integer
);
10840 cupsdFreeQuotas(printer
);
10842 printer
->k_limit
= attr
->values
[0].integer
;
10844 else if (!strcmp(attr
->name
, "job-page-limit"))
10846 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
10849 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-page-limit to %d...",
10850 attr
->values
[0].integer
);
10851 cupsdFreeQuotas(printer
);
10853 printer
->page_limit
= attr
->values
[0].integer
;
10855 else if (!strcmp(attr
->name
, "printer-op-policy"))
10857 cupsd_policy_t
*p
; /* Policy */
10860 if (attr
->value_tag
!= IPP_TAG_NAME
)
10863 if ((p
= cupsdFindPolicy(attr
->values
[0].string
.text
)) != NULL
)
10865 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10866 "Setting printer-op-policy to \"%s\"...",
10867 attr
->values
[0].string
.text
);
10868 cupsdSetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
10869 printer
->op_policy_ptr
= p
;
10873 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10874 _("Unknown printer-op-policy \"%s\"."),
10875 attr
->values
[0].string
.text
);
10879 else if (!strcmp(attr
->name
, "printer-error-policy"))
10881 if (attr
->value_tag
!= IPP_TAG_NAME
&& attr
->value_tag
!= IPP_TAG_KEYWORD
)
10884 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
10885 strcmp(attr
->values
[0].string
.text
, "retry-current-job") &&
10886 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
10887 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
10889 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
10890 _("Unknown printer-error-policy \"%s\"."),
10891 attr
->values
[0].string
.text
);
10895 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10896 "Setting printer-error-policy to \"%s\"...",
10897 attr
->values
[0].string
.text
);
10898 cupsdSetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
10902 * Skip any other non-default attributes...
10905 namelen
= strlen(attr
->name
);
10906 if (namelen
< 9 || strcmp(attr
->name
+ namelen
- 8, "-default") ||
10907 namelen
> (sizeof(name
) - 1) || attr
->num_values
!= 1)
10911 * OK, anything else must be a user-defined default...
10914 strlcpy(name
, attr
->name
, sizeof(name
));
10915 name
[namelen
- 8] = '\0'; /* Strip "-default" */
10917 switch (attr
->value_tag
)
10919 case IPP_TAG_DELETEATTR
:
10920 printer
->num_options
= cupsRemoveOption(name
,
10921 printer
->num_options
,
10922 &(printer
->options
));
10923 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10924 "Deleting %s", attr
->name
);
10927 case IPP_TAG_NAME
:
10928 case IPP_TAG_KEYWORD
:
10930 printer
->num_options
= cupsAddOption(name
,
10931 attr
->values
[0].string
.text
,
10932 printer
->num_options
,
10933 &(printer
->options
));
10934 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10935 "Setting %s to \"%s\"...", attr
->name
,
10936 attr
->values
[0].string
.text
);
10939 case IPP_TAG_BOOLEAN
:
10940 printer
->num_options
= cupsAddOption(name
,
10941 attr
->values
[0].boolean
?
10943 printer
->num_options
,
10944 &(printer
->options
));
10945 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10946 "Setting %s to %s...", attr
->name
,
10947 attr
->values
[0].boolean
? "true" : "false");
10950 case IPP_TAG_INTEGER
:
10951 case IPP_TAG_ENUM
:
10952 sprintf(value
, "%d", attr
->values
[0].integer
);
10953 printer
->num_options
= cupsAddOption(name
, value
,
10954 printer
->num_options
,
10955 &(printer
->options
));
10956 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10957 "Setting %s to %s...", attr
->name
, value
);
10960 case IPP_TAG_RANGE
:
10961 sprintf(value
, "%d-%d", attr
->values
[0].range
.lower
,
10962 attr
->values
[0].range
.upper
);
10963 printer
->num_options
= cupsAddOption(name
, value
,
10964 printer
->num_options
,
10965 &(printer
->options
));
10966 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10967 "Setting %s to %s...", attr
->name
, value
);
10970 case IPP_TAG_RESOLUTION
:
10971 sprintf(value
, "%dx%d%s", attr
->values
[0].resolution
.xres
,
10972 attr
->values
[0].resolution
.yres
,
10973 attr
->values
[0].resolution
.units
== IPP_RES_PER_INCH
?
10975 printer
->num_options
= cupsAddOption(name
, value
,
10976 printer
->num_options
,
10977 &(printer
->options
));
10978 cupsdLogMessage(CUPSD_LOG_DEBUG
,
10979 "Setting %s to %s...", attr
->name
, value
);
10983 /* Do nothing for other values */
10991 * 'start_printer()' - Start a printer.
10995 start_printer(cupsd_client_t
*con
, /* I - Client connection */
10996 ipp_attribute_t
*uri
) /* I - Printer URI */
10998 http_status_t status
; /* Policy status */
10999 cups_ptype_t dtype
; /* Destination type (printer/class) */
11000 cupsd_printer_t
*printer
; /* Printer data */
11003 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "start_printer(%p[%d], %s)", con
,
11004 con
->http
.fd
, uri
->values
[0].string
.text
);
11007 * Is the destination valid?
11010 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
11016 send_ipp_status(con
, IPP_NOT_FOUND
,
11017 _("The printer or class was not found."));
11025 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
11027 send_http_error(con
, status
, printer
);
11032 * Start the printer...
11035 printer
->state_message
[0] = '\0';
11037 cupsdStartPrinter(printer
, 1);
11039 if (dtype
& CUPS_PRINTER_CLASS
)
11040 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" started by \"%s\".",
11041 printer
->name
, get_username(con
));
11043 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" started by \"%s\".",
11044 printer
->name
, get_username(con
));
11049 * Everything was ok, so return OK status...
11052 con
->response
->request
.status
.status_code
= IPP_OK
;
11057 * 'stop_printer()' - Stop a printer.
11061 stop_printer(cupsd_client_t
*con
, /* I - Client connection */
11062 ipp_attribute_t
*uri
) /* I - Printer URI */
11064 http_status_t status
; /* Policy status */
11065 cups_ptype_t dtype
; /* Destination type (printer/class) */
11066 cupsd_printer_t
*printer
; /* Printer data */
11067 ipp_attribute_t
*attr
; /* printer-state-message attribute */
11070 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "stop_printer(%p[%d], %s)", con
,
11071 con
->http
.fd
, uri
->values
[0].string
.text
);
11074 * Is the destination valid?
11077 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
11083 send_ipp_status(con
, IPP_NOT_FOUND
,
11084 _("The printer or class was not found."));
11092 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
11094 send_http_error(con
, status
, printer
);
11099 * Stop the printer...
11102 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
11103 IPP_TAG_TEXT
)) == NULL
)
11104 strcpy(printer
->state_message
, "Paused");
11107 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
11108 sizeof(printer
->state_message
));
11111 cupsdStopPrinter(printer
, 1);
11113 if (dtype
& CUPS_PRINTER_CLASS
)
11114 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" stopped by \"%s\".",
11115 printer
->name
, get_username(con
));
11117 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" stopped by \"%s\".",
11118 printer
->name
, get_username(con
));
11121 * Everything was ok, so return OK status...
11124 con
->response
->request
.status
.status_code
= IPP_OK
;
11129 * 'url_encode_attr()' - URL-encode a string attribute.
11133 url_encode_attr(ipp_attribute_t
*attr
, /* I - Attribute */
11134 char *buffer
,/* I - String buffer */
11135 int bufsize
)/* I - Size of buffer */
11137 int i
; /* Looping var */
11138 char *bufptr
, /* Pointer into buffer */
11139 *bufend
; /* End of buffer */
11142 strlcpy(buffer
, attr
->name
, bufsize
);
11143 bufptr
= buffer
+ strlen(buffer
);
11144 bufend
= buffer
+ bufsize
- 1;
11146 for (i
= 0; i
< attr
->num_values
; i
++)
11148 if (bufptr
>= bufend
)
11156 if (bufptr
>= bufend
)
11161 bufptr
= url_encode_string(attr
->values
[i
].string
.text
,
11162 bufptr
, bufend
- bufptr
+ 1);
11164 if (bufptr
>= bufend
)
11175 * 'url_encode_string()' - URL-encode a string.
11178 static char * /* O - End of string */
11179 url_encode_string(const char *s
, /* I - String */
11180 char *buffer
, /* I - String buffer */
11181 int bufsize
) /* I - Size of buffer */
11183 char *bufptr
, /* Pointer into buffer */
11184 *bufend
; /* End of buffer */
11185 static const char *hex
= "0123456789ABCDEF";
11190 bufend
= buffer
+ bufsize
- 1;
11192 while (*s
&& bufptr
< bufend
)
11194 if (*s
== ' ' || *s
== '%')
11196 if (bufptr
>= (bufend
- 2))
11200 *bufptr
++ = hex
[(*s
>> 4) & 15];
11201 *bufptr
++ = hex
[*s
& 15];
11205 else if (*s
== '\'' || *s
== '\\')
11207 if (bufptr
>= (bufend
- 1))
11224 * 'user_allowed()' - See if a user is allowed to print to a queue.
11227 static int /* O - 0 if not allowed, 1 if allowed */
11228 user_allowed(cupsd_printer_t
*p
, /* I - Printer or class */
11229 const char *username
) /* I - Username */
11231 int i
; /* Looping var */
11232 struct passwd
*pw
; /* User password data */
11233 char baseuser
[256], /* Base username */
11234 *baseptr
; /* Pointer to "@" in base username */
11237 if (p
->num_users
== 0)
11240 if (!strcmp(username
, "root"))
11243 if (strchr(username
, '@'))
11246 * Strip @REALM for username check...
11249 strlcpy(baseuser
, username
, sizeof(baseuser
));
11251 if ((baseptr
= strchr(baseuser
, '@')) != NULL
)
11254 username
= baseuser
;
11257 pw
= getpwnam(username
);
11260 for (i
= 0; i
< p
->num_users
; i
++)
11262 if (p
->users
[i
][0] == '@')
11265 * Check group membership...
11268 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
11271 else if (p
->users
[i
][0] == '#')
11277 if (cupsdCheckGroup(username
, pw
, p
->users
[i
]))
11280 else if (!strcasecmp(username
, p
->users
[i
]))
11284 return ((i
< p
->num_users
) != p
->deny_users
);
11289 * 'validate_job()' - Validate printer options and destination.
11293 validate_job(cupsd_client_t
*con
, /* I - Client connection */
11294 ipp_attribute_t
*uri
) /* I - Printer URI */
11296 http_status_t status
; /* Policy status */
11297 ipp_attribute_t
*attr
; /* Current attribute */
11298 ipp_attribute_t
*format
; /* Document-format attribute */
11299 cups_ptype_t dtype
; /* Destination type (printer/class) */
11300 char super
[MIME_MAX_SUPER
],
11301 /* Supertype of file */
11302 type
[MIME_MAX_TYPE
];
11303 /* Subtype of file */
11304 cupsd_printer_t
*printer
; /* Printer */
11307 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "validate_job(%p[%d], %s)", con
,
11308 con
->http
.fd
, uri
->values
[0].string
.text
);
11311 * OK, see if the client is sending the document compressed - CUPS
11312 * doesn't support compression yet...
11315 if ((attr
= ippFindAttribute(con
->request
, "compression",
11316 IPP_TAG_KEYWORD
)) != NULL
&&
11317 !strcmp(attr
->values
[0].string
.text
, "none"))
11319 send_ipp_status(con
, IPP_ATTRIBUTES
,
11320 _("Unsupported compression attribute %s!"),
11321 attr
->values
[0].string
.text
);
11322 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
11323 "compression", NULL
, attr
->values
[0].string
.text
);
11328 * Is it a format we support?
11331 if ((format
= ippFindAttribute(con
->request
, "document-format",
11332 IPP_TAG_MIMETYPE
)) != NULL
)
11334 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]",
11337 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad document-format \"%s\"!"),
11338 format
->values
[0].string
.text
);
11342 if ((strcmp(super
, "application") || strcmp(type
, "octet-stream")) &&
11343 !mimeType(MimeDatabase
, super
, type
))
11345 cupsdLogMessage(CUPSD_LOG_INFO
,
11346 "Hint: Do you have the raw file printing rules enabled?");
11347 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
11348 _("Unsupported format \"%s\"!"),
11349 format
->values
[0].string
.text
);
11350 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
11351 "document-format", NULL
, format
->values
[0].string
.text
);
11357 * Is the destination valid?
11360 if (!cupsdValidateDest(uri
->values
[0].string
.text
, &dtype
, &printer
))
11366 send_ipp_status(con
, IPP_NOT_FOUND
,
11367 _("The printer or class was not found."));
11375 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
11377 send_http_error(con
, status
, printer
);
11382 * Everything was ok, so return OK status...
11385 con
->response
->request
.status
.status_code
= IPP_OK
;
11390 * 'validate_name()' - Make sure the printer name only contains valid chars.
11393 static int /* O - 0 if name is no good, 1 if good */
11394 validate_name(const char *name
) /* I - Name to check */
11396 const char *ptr
; /* Pointer into name */
11400 * Scan the whole name...
11403 for (ptr
= name
; *ptr
; ptr
++)
11404 if ((*ptr
> 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
11408 * All the characters are good; validate the length, too...
11411 return ((ptr
- name
) < 128);
11416 * 'validate_user()' - Validate the user for the request.
11419 static int /* O - 1 if permitted, 0 otherwise */
11420 validate_user(cupsd_job_t
*job
, /* I - Job */
11421 cupsd_client_t
*con
, /* I - Client connection */
11422 const char *owner
, /* I - Owner of job/resource */
11423 char *username
, /* O - Authenticated username */
11424 int userlen
) /* I - Length of username */
11426 cupsd_printer_t
*printer
; /* Printer for job */
11429 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
11430 "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, "
11432 job
->id
, con
? con
->http
.fd
: 0,
11433 owner
? owner
: "(null)", username
, userlen
);
11436 * Validate input...
11439 if (!con
|| !owner
|| !username
|| userlen
<= 0)
11443 * Get the best authenticated username that is available.
11446 strlcpy(username
, get_username(con
), userlen
);
11449 * Check the username against the owner...
11452 printer
= cupsdFindDest(job
->dest
);
11454 return (cupsdCheckPolicy(printer
? printer
->op_policy_ptr
: DefaultPolicyPtr
,
11455 con
, owner
) == HTTP_OK
);
11460 * End of "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $".