2 * "$Id: ipp.c 6032 2006-10-12 19:19:47Z mike $"
4 * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * cupsdProcessIPPRequest() - Process an incoming IPP request...
27 * accept_jobs() - Accept print jobs to a printer.
28 * add_class() - Add a class to the system.
29 * add_file() - Add a file to a job.
30 * add_job() - Add a job to a print queue.
31 * add_job_state_reasons() - Add the "job-state-reasons" attribute based
32 * upon the job and printer state...
33 * add_job_subscriptions() - Add any subcriptions for a job.
34 * add_job_uuid() - Add job-uuid attribute to a job.
35 * add_printer() - Add a printer to the system.
36 * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
37 * based upon the printer state...
38 * add_queued_job_count() - Add the "queued-job-count" attribute for
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 * copy_attribute() - Copy a single attribute.
46 * copy_attrs() - Copy attributes from one request to another.
47 * copy_banner() - Copy a banner file to the requests directory
48 * for the specified job.
49 * copy_file() - Copy a PPD file or interface script...
50 * copy_model() - Copy a PPD model file, substituting default
52 * copy_job_attrs() - Copy job attributes.
53 * copy_printer_attrs() - Copy printer attributes.
54 * copy_subscription_attrs() - Copy subscription attributes.
55 * create_job() - Print a file to a printer or class.
56 * create_requested_array() - Create an array for the requested-attributes.
57 * create_subscription() - Create a notification subscription.
58 * delete_printer() - Remove a printer or class from the system.
59 * get_default() - Get the default destination.
60 * get_devices() - Get the list of available devices on the
62 * get_job_attrs() - Get job attributes.
63 * get_jobs() - Get a list of jobs for the specified printer.
64 * get_notifications() - Get events for a subscription.
65 * get_ppds() - Get the list of PPD files on the local
67 * get_printer_attrs() - Get printer attributes.
68 * get_printers() - Get a list of printers.
69 * get_subscription_attrs() - Get subscription attributes.
70 * get_subscriptions() - Get subscriptions.
71 * get_username() - Get the username associated with a request.
72 * hold_job() - Hold a print job.
73 * move_job() - Move a job to a new destination.
74 * ppd_parse_line() - Parse a PPD default line.
75 * print_job() - Print a file to a printer or class.
76 * read_ps_line() - Read a line from a PS file...
77 * read_ps_job_ticket() - Reads a job ticket embedded in a PS file.
78 * reject_jobs() - Reject print jobs to a printer.
79 * release_job() - Release a held print job.
80 * restart_job() - Restart an old print job.
81 * save_auth_info() - Save authentication information for a job.
82 * send_document() - Send a file to a printer or class.
83 * send_http_error() - Send a HTTP error back to the IPP client.
84 * send_ipp_status() - Send a status back to the IPP client.
85 * set_default() - Set the default destination...
86 * set_job_attrs() - Set job attributes.
87 * set_printer_defaults() - Set printer default options from a request.
88 * start_printer() - Start a printer.
89 * stop_printer() - Stop a printer.
90 * url_encode_attr() - URL-encode a string attribute.
91 * user_allowed() - See if a user is allowed to print to a queue.
92 * validate_job() - Validate printer options and destination.
93 * validate_name() - Make sure the printer name only contains
95 * validate_user() - Validate the user for the request.
99 * Include necessary headers...
106 #endif /* HAVE_LIBPAPER */
113 static void accept_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
114 static void add_class(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
115 static int add_file(cupsd_client_t
*con
, cupsd_job_t
*job
,
116 mime_type_t
*filetype
, int compression
);
117 static cupsd_job_t
*add_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
,
118 cupsd_printer_t
**dprinter
,
119 mime_type_t
*filetype
);
120 static void add_job_state_reasons(cupsd_client_t
*con
, cupsd_job_t
*job
);
121 static void add_job_subscriptions(cupsd_client_t
*con
, cupsd_job_t
*job
);
122 static void add_job_uuid(cupsd_client_t
*con
, cupsd_job_t
*job
);
123 static void add_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
124 static void add_printer_state_reasons(cupsd_client_t
*con
,
126 static void add_queued_job_count(cupsd_client_t
*con
, cupsd_printer_t
*p
);
127 static void apply_printer_defaults(cupsd_printer_t
*printer
,
129 static void authenticate_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
130 static void cancel_all_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
131 static void cancel_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
132 static void cancel_subscription(cupsd_client_t
*con
, int id
);
133 static int check_quotas(cupsd_client_t
*con
, cupsd_printer_t
*p
);
134 static ipp_attribute_t
*copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
136 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, cups_array_t
*ra
,
137 ipp_tag_t group
, int quickcopy
);
138 static int copy_banner(cupsd_client_t
*con
, cupsd_job_t
*job
,
140 static int copy_file(const char *from
, const char *to
);
141 static int copy_model(cupsd_client_t
*con
, const char *from
,
143 static void copy_job_attrs(cupsd_client_t
*con
,
146 static void copy_printer_attrs(cupsd_client_t
*con
,
147 cupsd_printer_t
*printer
,
149 static void copy_subscription_attrs(cupsd_client_t
*con
,
150 cupsd_subscription_t
*sub
,
152 static void create_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
153 static cups_array_t
*create_requested_array(ipp_t
*request
);
154 static void create_subscription(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
155 static void delete_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
156 static void get_default(cupsd_client_t
*con
);
157 static void get_devices(cupsd_client_t
*con
);
158 static void get_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
159 static void get_job_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
160 static void get_notifications(cupsd_client_t
*con
);
161 static void get_ppds(cupsd_client_t
*con
);
162 static void get_printers(cupsd_client_t
*con
, int type
);
163 static void get_printer_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
164 static void get_subscription_attrs(cupsd_client_t
*con
, int sub_id
);
165 static void get_subscriptions(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
166 static const char *get_username(cupsd_client_t
*con
);
167 static void hold_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
168 static void move_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
169 static int ppd_parse_line(const char *line
, char *option
, int olen
,
170 char *choice
, int clen
);
171 static void print_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
172 static void read_ps_job_ticket(cupsd_client_t
*con
);
173 static void reject_jobs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
174 static void release_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
175 static void renew_subscription(cupsd_client_t
*con
, int sub_id
);
176 static void restart_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
177 static void save_auth_info(cupsd_client_t
*con
, cupsd_job_t
*job
);
178 static void send_document(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
179 static void send_http_error(cupsd_client_t
*con
, http_status_t status
);
180 static void send_ipp_status(cupsd_client_t
*con
, ipp_status_t status
,
181 const char *message
, ...)
183 __attribute__ ((__format__ (__printf__
, 3, 4)))
184 # endif /* __GNUC__ */
186 static void set_default(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
187 static void set_job_attrs(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
188 static void set_printer_defaults(cupsd_client_t
*con
,
189 cupsd_printer_t
*printer
);
190 static void start_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
191 static void stop_printer(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
192 static void url_encode_attr(ipp_attribute_t
*attr
, char *buffer
,
194 static int user_allowed(cupsd_printer_t
*p
, const char *username
);
195 static void validate_job(cupsd_client_t
*con
, ipp_attribute_t
*uri
);
196 static int validate_name(const char *name
);
197 static int validate_user(cupsd_job_t
*job
, cupsd_client_t
*con
,
198 const char *owner
, char *username
,
203 * 'cupsdProcessIPPRequest()' - Process an incoming IPP request...
206 int /* O - 1 on success, 0 on failure */
207 cupsdProcessIPPRequest(
208 cupsd_client_t
*con
) /* I - Client connection */
210 ipp_tag_t group
; /* Current group tag */
211 ipp_attribute_t
*attr
; /* Current attribute */
212 ipp_attribute_t
*charset
; /* Character set attribute */
213 ipp_attribute_t
*language
; /* Language attribute */
214 ipp_attribute_t
*uri
; /* Printer URI attribute */
215 ipp_attribute_t
*username
; /* requesting-user-name attr */
216 int sub_id
; /* Subscription ID */
219 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
220 "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x",
221 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
224 * First build an empty response message for this request...
227 con
->response
= ippNew();
229 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
230 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
231 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
234 * Then validate the request header and required attributes...
237 if (con
->request
->request
.any
.version
[0] != 1)
240 * Return an error, since we only support IPP 1.x.
243 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
244 "%04X %s Bad request version number %d.%d",
245 IPP_VERSION_NOT_SUPPORTED
, con
->http
.hostname
,
246 con
->request
->request
.any
.version
[0],
247 con
->request
->request
.any
.version
[1]);
249 send_ipp_status(con
, IPP_VERSION_NOT_SUPPORTED
,
250 _("Bad request version number %d.%d!"),
251 con
->request
->request
.any
.version
[0],
252 con
->request
->request
.any
.version
[1]);
254 else if (!con
->request
->attrs
)
256 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
257 "%04X %s No attributes in request",
258 IPP_BAD_REQUEST
, con
->http
.hostname
);
260 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No attributes in request!"));
265 * Make sure that the attributes are provided in the correct order and
266 * don't repeat groups...
269 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
272 if (attr
->group_tag
< group
&& attr
->group_tag
!= IPP_TAG_ZERO
)
275 * Out of order; return an error...
278 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
279 "%04X %s Attribute groups are out of order",
280 IPP_BAD_REQUEST
, con
->http
.hostname
);
282 send_ipp_status(con
, IPP_BAD_REQUEST
,
283 _("Attribute groups are out of order (%x < %x)!"),
284 attr
->group_tag
, group
);
288 group
= attr
->group_tag
;
293 * Then make sure that the first three attributes are:
296 * attributes-natural-language
297 * printer-uri/job-uri
300 attr
= con
->request
->attrs
;
301 if (attr
&& !strcmp(attr
->name
, "attributes-charset") &&
302 (attr
->value_tag
& IPP_TAG_MASK
) == IPP_TAG_CHARSET
)
310 if (attr
&& !strcmp(attr
->name
, "attributes-natural-language") &&
311 (attr
->value_tag
& IPP_TAG_MASK
) == IPP_TAG_LANGUAGE
)
316 if ((attr
= ippFindAttribute(con
->request
, "printer-uri",
317 IPP_TAG_URI
)) != NULL
)
319 else if ((attr
= ippFindAttribute(con
->request
, "job-uri",
320 IPP_TAG_URI
)) != NULL
)
326 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
327 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
329 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
330 "attributes-charset", NULL
, DefaultCharset
);
333 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
334 "attributes-natural-language", NULL
,
335 language
->values
[0].string
.text
);
337 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
338 "attributes-natural-language", NULL
, DefaultLanguage
);
340 if (!charset
|| !language
||
342 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
343 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
344 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
345 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
346 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
349 * Return an error, since attributes-charset,
350 * attributes-natural-language, and printer-uri/job-uri are required
351 * for all operations.
356 cupsdLogMessage(CUPSD_LOG_ERROR
,
357 "Missing attributes-charset attribute!");
359 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
360 "%04X %s Missing attributes-charset attribute",
361 IPP_BAD_REQUEST
, con
->http
.hostname
);
366 cupsdLogMessage(CUPSD_LOG_ERROR
,
367 "Missing attributes-natural-language attribute!");
369 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
370 "%04X %s Missing attributes-natural-language attribute",
371 IPP_BAD_REQUEST
, con
->http
.hostname
);
376 cupsdLogMessage(CUPSD_LOG_ERROR
,
377 "Missing printer-uri or job-uri attribute!");
379 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
380 "%04X %s Missing printer-uri or job-uri attribute",
381 IPP_BAD_REQUEST
, con
->http
.hostname
);
384 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Request attributes follow...");
386 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
387 cupsdLogMessage(CUPSD_LOG_DEBUG
,
388 "attr \"%s\": group_tag = %x, value_tag = %x",
389 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
392 cupsdLogMessage(CUPSD_LOG_DEBUG
, "End of attributes...");
394 send_ipp_status(con
, IPP_BAD_REQUEST
,
395 _("Missing required attributes!"));
400 * OK, all the checks pass so far; make sure requesting-user-name is
401 * not "root" from a remote host...
404 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name",
405 IPP_TAG_NAME
)) != NULL
)
408 * Check for root user...
411 if (!strcmp(username
->values
[0].string
.text
, "root") &&
412 strcasecmp(con
->http
.hostname
, "localhost") &&
413 strcmp(con
->username
, "root"))
416 * Remote unauthenticated user masquerading as local root...
419 _cupsStrFree(username
->values
[0].string
.text
);
420 username
->values
[0].string
.text
= _cupsStrAlloc(RemoteRoot
);
424 if ((attr
= ippFindAttribute(con
->request
, "notify-subscription-id",
425 IPP_TAG_INTEGER
)) != NULL
)
426 sub_id
= attr
->values
[0].integer
;
431 * Then try processing the operation...
435 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s %s",
436 ippOpString(con
->request
->request
.op
.operation_id
),
437 uri
->values
[0].string
.text
);
439 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s",
440 ippOpString(con
->request
->request
.op
.operation_id
));
442 switch (con
->request
->request
.op
.operation_id
)
448 case IPP_VALIDATE_JOB
:
449 validate_job(con
, uri
);
452 case IPP_CREATE_JOB
:
453 create_job(con
, uri
);
456 case IPP_SEND_DOCUMENT
:
457 send_document(con
, uri
);
460 case IPP_CANCEL_JOB
:
461 cancel_job(con
, uri
);
464 case IPP_GET_JOB_ATTRIBUTES
:
465 get_job_attrs(con
, uri
);
472 case IPP_GET_PRINTER_ATTRIBUTES
:
473 get_printer_attrs(con
, uri
);
480 case IPP_RELEASE_JOB
:
481 release_job(con
, uri
);
484 case IPP_RESTART_JOB
:
485 restart_job(con
, uri
);
488 case IPP_PAUSE_PRINTER
:
489 stop_printer(con
, uri
);
492 case IPP_RESUME_PRINTER
:
493 start_printer(con
, uri
);
496 case IPP_PURGE_JOBS
:
497 cancel_all_jobs(con
, uri
);
500 case IPP_SET_JOB_ATTRIBUTES
:
501 set_job_attrs(con
, uri
);
504 case CUPS_GET_DEFAULT
:
508 case CUPS_GET_PRINTERS
:
509 get_printers(con
, 0);
512 case CUPS_GET_CLASSES
:
513 get_printers(con
, CUPS_PRINTER_CLASS
);
516 case CUPS_ADD_PRINTER
:
517 add_printer(con
, uri
);
520 case CUPS_DELETE_PRINTER
:
521 delete_printer(con
, uri
);
524 case CUPS_ADD_CLASS
:
528 case CUPS_DELETE_CLASS
:
529 delete_printer(con
, uri
);
532 case CUPS_ACCEPT_JOBS
:
533 case IPP_ENABLE_PRINTER
:
534 accept_jobs(con
, uri
);
537 case CUPS_REJECT_JOBS
:
538 case IPP_DISABLE_PRINTER
:
539 reject_jobs(con
, uri
);
542 case CUPS_SET_DEFAULT
:
543 set_default(con
, uri
);
546 case CUPS_GET_DEVICES
:
558 case CUPS_AUTHENTICATE_JOB
:
559 authenticate_job(con
, uri
);
562 case IPP_CREATE_PRINTER_SUBSCRIPTION
:
563 case IPP_CREATE_JOB_SUBSCRIPTION
:
564 create_subscription(con
, uri
);
567 case IPP_GET_SUBSCRIPTION_ATTRIBUTES
:
568 get_subscription_attrs(con
, sub_id
);
571 case IPP_GET_SUBSCRIPTIONS
:
572 get_subscriptions(con
, uri
);
575 case IPP_RENEW_SUBSCRIPTION
:
576 renew_subscription(con
, sub_id
);
579 case IPP_CANCEL_SUBSCRIPTION
:
580 cancel_subscription(con
, sub_id
);
583 case IPP_GET_NOTIFICATIONS
:
584 get_notifications(con
);
588 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
589 "%04X %s Operation %04X (%s) not supported",
590 IPP_OPERATION_NOT_SUPPORTED
, con
->http
.hostname
,
591 con
->request
->request
.op
.operation_id
,
592 ippOpString(con
->request
->request
.op
.operation_id
));
594 send_ipp_status(con
, IPP_OPERATION_NOT_SUPPORTED
,
595 _("%s not supported!"),
596 ippOpString(con
->request
->request
.op
.operation_id
));
606 * Sending data from the scheduler...
609 cupsdLogMessage(CUPSD_LOG_DEBUG
,
610 "cupsdProcessIPPRequest: %d status_code=%x (%s)",
611 con
->http
.fd
, con
->response
->request
.status
.status_code
,
612 ippErrorString(con
->response
->request
.status
.status_code
));
614 if (cupsdSendHeader(con
, HTTP_OK
, "application/ipp"))
616 #ifdef CUPSD_USE_CHUNKING
618 * Because older versions of CUPS (1.1.17 and older) and some IPP
619 * clients do not implement chunking properly, we cannot use
620 * chunking by default. This may become the default in future
621 * CUPS releases, or we might add a configuration directive for
625 if (con
->http
.version
== HTTP_1_1
)
627 if (httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n") < 0)
630 if (cupsdFlushHeader(con
) < 0)
633 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
636 #endif /* CUPSD_USE_CHUNKING */
638 size_t length
; /* Length of response */
641 length
= ippLength(con
->response
);
643 if (httpPrintf(HTTP(con
), "Content-Length: " CUPS_LLFMT
"\r\n\r\n",
644 CUPS_LLCAST length
) < 0)
647 if (cupsdFlushHeader(con
) < 0)
650 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
651 con
->http
.data_remaining
= length
;
654 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
655 "cupsdProcessIPPRequest: Adding fd %d to OutputSet...",
658 FD_SET(con
->http
.fd
, OutputSet
);
661 * Tell the caller the response header was sent successfully...
669 * Tell the caller the response header could not be sent...
678 * Sending data from a subprocess like cups-deviced; tell the caller
679 * everything is A-OK so far...
688 * 'accept_jobs()' - Accept print jobs to a printer.
692 accept_jobs(cupsd_client_t
*con
, /* I - Client connection */
693 ipp_attribute_t
*uri
) /* I - Printer or class URI */
695 http_status_t status
; /* Policy status */
696 cups_ptype_t dtype
; /* Destination type (printer or class) */
697 char method
[HTTP_MAX_URI
], /* Method portion of URI */
698 username
[HTTP_MAX_URI
], /* Username portion of URI */
699 host
[HTTP_MAX_URI
], /* Host portion of URI */
700 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
701 int port
; /* Port portion of URI */
702 const char *name
; /* Printer name */
703 cupsd_printer_t
*printer
; /* Printer data */
706 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "accept_jobs(%p[%d], %s)", con
,
707 con
->http
.fd
, uri
->values
[0].string
.text
);
710 * Is the destination valid?
713 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
714 sizeof(method
), username
, sizeof(username
), host
,
715 sizeof(host
), &port
, resource
, sizeof(resource
));
717 if ((name
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
723 send_ipp_status(con
, IPP_NOT_FOUND
,
724 _("The printer or class was not found."));
732 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
734 send_http_error(con
, status
);
739 * Accept jobs sent to the printer...
742 printer
->accepting
= 1;
743 printer
->state_message
[0] = '\0';
745 cupsdAddPrinterHistory(printer
);
747 if (dtype
& CUPS_PRINTER_CLASS
)
748 cupsdSaveAllClasses();
750 cupsdSaveAllPrinters();
752 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" now accepting jobs (\"%s\").", name
,
756 * Everything was ok, so return OK status...
759 con
->response
->request
.status
.status_code
= IPP_OK
;
764 * 'add_class()' - Add a class to the system.
768 add_class(cupsd_client_t
*con
, /* I - Client connection */
769 ipp_attribute_t
*uri
) /* I - URI of class */
771 http_status_t status
; /* Policy status */
772 int i
; /* Looping var */
773 char method
[HTTP_MAX_URI
], /* Method portion of URI */
774 username
[HTTP_MAX_URI
], /* Username portion of URI */
775 host
[HTTP_MAX_URI
], /* Host portion of URI */
776 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
777 int port
; /* Port portion of URI */
778 cupsd_printer_t
*pclass
, /* Class */
779 *member
; /* Member printer/class */
780 cups_ptype_t dtype
; /* Destination type */
781 ipp_attribute_t
*attr
; /* Printer attribute */
782 int modify
; /* Non-zero if we just modified */
783 char newname
[IPP_MAX_NAME
]; /* New class name */
784 int need_restart_job
; /* Need to restart job? */
787 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_class(%p[%d], %s)", con
,
788 con
->http
.fd
, uri
->values
[0].string
.text
);
791 * Do we have a valid URI?
794 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
795 sizeof(method
), username
, sizeof(username
), host
,
796 sizeof(host
), &port
, resource
, sizeof(resource
));
799 if (strncmp(resource
, "/classes/", 9) || strlen(resource
) == 9)
802 * No, return an error...
805 send_ipp_status(con
, IPP_BAD_REQUEST
,
806 _("The printer-uri must be of the form "
807 "\"ipp://HOSTNAME/classes/CLASSNAME\"."));
812 * Do we have a valid printer name?
815 if (!validate_name(resource
+ 9))
818 * No, return an error...
821 send_ipp_status(con
, IPP_BAD_REQUEST
,
822 _("The printer-uri \"%s\" contains invalid characters."),
823 uri
->values
[0].string
.text
);
831 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
833 send_http_error(con
, status
);
838 * See if the class already exists; if not, create a new class...
841 if ((pclass
= cupsdFindClass(resource
+ 9)) == NULL
)
844 * Class doesn't exist; see if we have a printer of the same name...
847 if ((pclass
= cupsdFindPrinter(resource
+ 9)) != NULL
&&
848 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
851 * Yes, return an error...
854 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
855 _("A printer named \"%s\" already exists!"),
861 * No, add the pclass...
864 pclass
= cupsdAddClass(resource
+ 9);
867 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
870 * Rename the implicit class to "AnyClass" or remove it...
873 if (ImplicitAnyClasses
)
875 snprintf(newname
, sizeof(newname
), "Any%s", resource
+ 9);
876 cupsdRenamePrinter(pclass
, newname
);
879 cupsdDeletePrinter(pclass
, 1);
882 * Add the class as a new local class...
885 pclass
= cupsdAddClass(resource
+ 9);
888 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
891 * Rename the remote class to "Class"...
894 snprintf(newname
, sizeof(newname
), "%s@%s", resource
+ 9, pclass
->hostname
);
895 cupsdRenamePrinter(pclass
, newname
);
898 * Add the class as a new local class...
901 pclass
= cupsdAddClass(resource
+ 9);
908 * Look for attributes and copy them over as needed...
911 need_restart_job
= 0;
913 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
914 IPP_TAG_TEXT
)) != NULL
)
915 cupsdSetString(&pclass
->location
, attr
->values
[0].string
.text
);
917 if ((attr
= ippFindAttribute(con
->request
, "printer-info",
918 IPP_TAG_TEXT
)) != NULL
)
919 cupsdSetString(&pclass
->info
, attr
->values
[0].string
.text
);
921 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs",
922 IPP_TAG_BOOLEAN
)) != NULL
)
924 cupsdLogMessage(CUPSD_LOG_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
925 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
927 pclass
->accepting
= attr
->values
[0].boolean
;
928 cupsdAddPrinterHistory(pclass
);
931 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared",
932 IPP_TAG_BOOLEAN
)) != NULL
)
934 if (pclass
->shared
&& !attr
->values
[0].boolean
)
935 cupsdSendBrowseDelete(pclass
);
937 cupsdLogMessage(CUPSD_LOG_INFO
,
938 "Setting %s printer-is-shared to %d (was %d.)",
939 pclass
->name
, attr
->values
[0].boolean
, pclass
->shared
);
941 pclass
->shared
= attr
->values
[0].boolean
;
944 if ((attr
= ippFindAttribute(con
->request
, "printer-state",
945 IPP_TAG_ENUM
)) != NULL
)
947 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
948 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
950 send_ipp_status(con
, IPP_BAD_REQUEST
,
951 _("Attempt to set %s printer-state to bad value %d!"),
952 pclass
->name
, attr
->values
[0].integer
);
956 cupsdLogMessage(CUPSD_LOG_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
957 attr
->values
[0].integer
, pclass
->state
);
959 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
960 cupsdStopPrinter(pclass
, 0);
963 cupsdSetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
964 need_restart_job
= 1;
967 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
968 IPP_TAG_TEXT
)) != NULL
)
970 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
971 sizeof(pclass
->state_message
));
972 cupsdAddPrinterHistory(pclass
);
974 if ((attr
= ippFindAttribute(con
->request
, "member-uris",
975 IPP_TAG_URI
)) != NULL
)
978 * Clear the printer array as needed...
981 need_restart_job
= 1;
983 if (pclass
->num_printers
> 0)
985 free(pclass
->printers
);
986 pclass
->num_printers
= 0;
990 * Add each printer or class that is listed...
993 for (i
= 0; i
< attr
->num_values
; i
++)
996 * Search for the printer or class URI...
999 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[i
].string
.text
, method
,
1000 sizeof(method
), username
, sizeof(username
), host
,
1001 sizeof(host
), &port
, resource
, sizeof(resource
));
1003 if (!cupsdValidateDest(host
, resource
, &dtype
, &member
))
1009 send_ipp_status(con
, IPP_NOT_FOUND
,
1010 _("The printer or class was not found."));
1015 * Add it to the class...
1018 cupsdAddPrinterToClass(pclass
, member
);
1022 set_printer_defaults(con
, pclass
);
1025 * Update the printer class attributes and return...
1028 cupsdSetPrinterAttrs(pclass
);
1029 cupsdSaveAllClasses();
1031 if (need_restart_job
&& pclass
->job
)
1036 * Stop the current job and then restart it below...
1039 job
= (cupsd_job_t
*)pclass
->job
;
1041 cupsdStopJob(job
, 1);
1043 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1044 job
->state_value
= IPP_JOB_PENDING
;
1047 if (need_restart_job
)
1050 cupsdWritePrintcap();
1054 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1055 "Class \"%s\" modified by \"%s\".", pclass
->name
,
1058 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" modified by \"%s\".",
1059 pclass
->name
, get_username(con
));
1063 cupsdAddPrinterHistory(pclass
);
1065 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1066 "New class \"%s\" added by \"%s\".", pclass
->name
,
1069 cupsdLogMessage(CUPSD_LOG_INFO
, "New class \"%s\" added by \"%s\".",
1070 pclass
->name
, get_username(con
));
1073 con
->response
->request
.status
.status_code
= IPP_OK
;
1078 * 'add_file()' - Add a file to a job.
1081 static int /* O - 0 on success, -1 on error */
1082 add_file(cupsd_client_t
*con
, /* I - Connection to client */
1083 cupsd_job_t
*job
, /* I - Job to add to */
1084 mime_type_t
*filetype
, /* I - Type of file */
1085 int compression
) /* I - Compression */
1087 mime_type_t
**filetypes
; /* New filetypes array... */
1088 int *compressions
; /* New compressions array... */
1091 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
1092 "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)",
1093 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1097 * Add the file to the job...
1100 if (job
->num_files
== 0)
1102 compressions
= (int *)malloc(sizeof(int));
1103 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1107 compressions
= (int *)realloc(job
->compressions
,
1108 (job
->num_files
+ 1) * sizeof(int));
1109 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1110 (job
->num_files
+ 1) *
1111 sizeof(mime_type_t
*));
1114 if (!compressions
|| !filetypes
)
1116 cupsdCancelJob(job
, 1, IPP_JOB_ABORTED
);
1118 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
1119 _("Unable to allocate memory for file types!"));
1123 job
->compressions
= compressions
;
1124 job
->compressions
[job
->num_files
] = compression
;
1125 job
->filetypes
= filetypes
;
1126 job
->filetypes
[job
->num_files
] = filetype
;
1135 * 'add_job()' - Add a job to a print queue.
1138 static cupsd_job_t
* /* O - Job object */
1139 add_job(cupsd_client_t
*con
, /* I - Client connection */
1140 ipp_attribute_t
*uri
, /* I - printer-uri */
1141 cupsd_printer_t
**dprinter
, /* I - Destination printer */
1142 mime_type_t
*filetype
) /* I - First print file type, if any */
1144 http_status_t status
; /* Policy status */
1145 ipp_attribute_t
*attr
; /* Current attribute */
1146 const char *dest
; /* Destination */
1147 cups_ptype_t dtype
; /* Destination type (printer or class) */
1148 const char *val
; /* Default option value */
1149 int priority
; /* Job priority */
1150 char *title
; /* Job name/title */
1151 cupsd_job_t
*job
; /* Current job */
1152 char job_uri
[HTTP_MAX_URI
], /* Job URI */
1153 method
[HTTP_MAX_URI
], /* Method portion of URI */
1154 username
[HTTP_MAX_URI
], /* Username portion of URI */
1155 host
[HTTP_MAX_URI
], /* Host portion of URI */
1156 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1157 int port
; /* Port portion of URI */
1158 cupsd_printer_t
*printer
; /* Printer data */
1159 int kbytes
; /* Size of print file */
1160 int i
; /* Looping var */
1161 int lowerpagerange
; /* Page range bound */
1164 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_job(%p[%d], %s)", con
,
1165 con
->http
.fd
, uri
->values
[0].string
.text
);
1168 * Is the destination valid?
1171 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
1172 sizeof(method
), username
, sizeof(username
), host
,
1173 sizeof(host
), &port
, resource
, sizeof(resource
));
1175 if ((dest
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
1181 send_ipp_status(con
, IPP_NOT_FOUND
,
1182 _("The printer or class was not found."));
1187 *dprinter
= printer
;
1190 * Check remote printing to non-shared printer...
1193 if (!printer
->shared
&&
1194 strcasecmp(con
->http
.hostname
, "localhost") &&
1195 strcasecmp(con
->http
.hostname
, ServerName
))
1197 send_ipp_status(con
, IPP_NOT_AUTHORIZED
,
1198 _("The printer or class is not shared!"));
1206 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
1208 send_http_error(con
, status
);
1211 else if ((printer
->type
& CUPS_PRINTER_AUTHENTICATED
) && !con
->username
[0])
1213 send_http_error(con
, HTTP_UNAUTHORIZED
);
1218 * See if the printer is accepting jobs...
1221 if (!printer
->accepting
)
1223 send_ipp_status(con
, IPP_NOT_ACCEPTING
,
1224 _("Destination \"%s\" is not accepting jobs."),
1230 * Validate job template attributes; for now just document-format,
1231 * copies, and page-ranges...
1234 if (filetype
&& printer
->filetypes
&&
1235 !cupsArrayFind(printer
->filetypes
, filetype
))
1237 char mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
1238 /* MIME media type string */
1241 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
1244 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
1245 _("Unsupported format \'%s\'!"), mimetype
);
1247 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
1248 "document-format", NULL
, mimetype
);
1253 if ((attr
= ippFindAttribute(con
->request
, "copies",
1254 IPP_TAG_INTEGER
)) != NULL
)
1256 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
1258 send_ipp_status(con
, IPP_ATTRIBUTES
, _("Bad copies value %d."),
1259 attr
->values
[0].integer
);
1260 ippAddInteger(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_INTEGER
,
1261 "copies", attr
->values
[0].integer
);
1266 if ((attr
= ippFindAttribute(con
->request
, "page-ranges",
1267 IPP_TAG_RANGE
)) != NULL
)
1269 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
1271 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
1272 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
1274 send_ipp_status(con
, IPP_BAD_REQUEST
,
1275 _("Bad page-ranges values %d-%d."),
1276 attr
->values
[i
].range
.lower
,
1277 attr
->values
[i
].range
.upper
);
1281 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
1286 * Make sure we aren't over our limit...
1289 if (MaxJobs
&& cupsArrayCount(Jobs
) >= MaxJobs
)
1292 if (cupsArrayCount(Jobs
) >= MaxJobs
&& MaxJobs
)
1294 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
1295 _("Too many active jobs."));
1299 if (!check_quotas(con
, printer
))
1301 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Quota limit reached."));
1306 * Create the job and set things up...
1309 if ((attr
= ippFindAttribute(con
->request
, "job-priority",
1310 IPP_TAG_INTEGER
)) != NULL
)
1311 priority
= attr
->values
[0].integer
;
1314 if ((val
= cupsGetOption("job-priority", printer
->num_options
,
1315 printer
->options
)) != NULL
)
1316 priority
= atoi(val
);
1320 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
1324 if ((attr
= ippFindAttribute(con
->request
, "job-name",
1325 IPP_TAG_NAME
)) != NULL
)
1326 title
= attr
->values
[0].string
.text
;
1328 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
1329 title
= "Untitled");
1331 if ((job
= cupsdAddJob(priority
, printer
->name
)) == NULL
)
1333 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
1334 _("Unable to add job for destination \"%s\"!"), dest
);
1339 job
->attrs
= con
->request
;
1340 con
->request
= ippNewRequest(job
->attrs
->request
.op
.operation_id
);
1342 add_job_uuid(con
, job
);
1343 apply_printer_defaults(printer
, job
);
1345 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
1347 if (con
->username
[0])
1349 cupsdSetString(&job
->username
, con
->username
);
1352 cupsdSetString(&attr
->values
[0].string
.text
, con
->username
);
1354 save_auth_info(con
, job
);
1358 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1359 "add_job: requesting-user-name=\"%s\"",
1360 attr
->values
[0].string
.text
);
1362 cupsdSetString(&job
->username
, attr
->values
[0].string
.text
);
1365 cupsdSetString(&job
->username
, "anonymous");
1368 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
1369 "job-originating-user-name", NULL
, job
->username
);
1372 attr
->group_tag
= IPP_TAG_JOB
;
1373 _cupsStrFree(attr
->name
);
1374 attr
->name
= _cupsStrAlloc("job-originating-user-name");
1377 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
1378 IPP_TAG_ZERO
)) != NULL
)
1381 * Request contains a job-originating-host-name attribute; validate it...
1384 if (attr
->value_tag
!= IPP_TAG_NAME
||
1385 attr
->num_values
!= 1 ||
1386 strcmp(con
->http
.hostname
, "localhost"))
1389 * Can't override the value if we aren't connected via localhost.
1390 * Also, we can only have 1 value and it must be a name value.
1393 switch (attr
->value_tag
)
1395 case IPP_TAG_STRING
:
1396 case IPP_TAG_TEXTLANG
:
1397 case IPP_TAG_NAMELANG
:
1400 case IPP_TAG_KEYWORD
:
1402 case IPP_TAG_URISCHEME
:
1403 case IPP_TAG_CHARSET
:
1404 case IPP_TAG_LANGUAGE
:
1405 case IPP_TAG_MIMETYPE
:
1407 * Free old strings...
1410 for (i
= 0; i
< attr
->num_values
; i
++)
1412 _cupsStrFree(attr
->values
[i
].string
.text
);
1413 attr
->values
[i
].string
.text
= NULL
;
1414 if (attr
->values
[i
].string
.charset
)
1416 _cupsStrFree(attr
->values
[i
].string
.charset
);
1417 attr
->values
[i
].string
.charset
= NULL
;
1426 * Use the default connection hostname instead...
1429 attr
->value_tag
= IPP_TAG_NAME
;
1430 attr
->num_values
= 1;
1431 attr
->values
[0].string
.text
= _cupsStrAlloc(con
->http
.hostname
);
1434 attr
->group_tag
= IPP_TAG_JOB
;
1439 * No job-originating-host-name attribute, so use the hostname from
1443 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
1444 "job-originating-host-name", NULL
, con
->http
.hostname
);
1447 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
1449 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1450 "time-at-processing", 0);
1451 attr
->value_tag
= IPP_TAG_NOVALUE
;
1452 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1453 "time-at-completed", 0);
1454 attr
->value_tag
= IPP_TAG_NOVALUE
;
1457 * Add remaining job attributes...
1460 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
1461 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
1462 "job-state", IPP_JOB_STOPPED
);
1463 job
->state_value
= (ipp_jstate_t
)job
->state
->values
[0].integer
;
1464 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1465 "job-media-sheets-completed", 0);
1466 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
1468 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
1471 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
1472 IPP_TAG_INTEGER
)) != NULL
)
1473 attr
->values
[0].integer
= 0;
1475 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
1478 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
1479 IPP_TAG_KEYWORD
)) == NULL
)
1480 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
1483 if ((val
= cupsGetOption("job-hold-until", printer
->num_options
,
1484 printer
->options
)) == NULL
)
1487 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1488 "job-hold-until", NULL
, val
);
1490 if (attr
&& strcmp(attr
->values
[0].string
.text
, "no-hold") &&
1491 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1494 * Hold job until specified time...
1497 cupsdSetJobHoldUntil(job
, attr
->values
[0].string
.text
);
1499 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
1500 job
->state_value
= IPP_JOB_HELD
;
1502 else if (job
->attrs
->request
.op
.operation_id
== IPP_CREATE_JOB
)
1504 job
->hold_until
= time(NULL
) + 60;
1505 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
1506 job
->state_value
= IPP_JOB_HELD
;
1510 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1511 job
->state_value
= IPP_JOB_PENDING
;
1514 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
1518 * Add job sheets options...
1521 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets",
1522 IPP_TAG_ZERO
)) == NULL
)
1524 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1525 "Adding default job-sheets values \"%s,%s\"...",
1526 printer
->job_sheets
[0], printer
->job_sheets
[1]);
1528 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
1530 attr
->values
[0].string
.text
= _cupsStrAlloc(printer
->job_sheets
[0]);
1531 attr
->values
[1].string
.text
= _cupsStrAlloc(printer
->job_sheets
[1]);
1534 job
->job_sheets
= attr
;
1537 * Enforce classification level if set...
1542 cupsdLogMessage(CUPSD_LOG_INFO
,
1543 "Classification=\"%s\", ClassifyOverride=%d",
1544 Classification
? Classification
: "(null)",
1547 if (ClassifyOverride
)
1549 if (!strcmp(attr
->values
[0].string
.text
, "none") &&
1550 (attr
->num_values
== 1 ||
1551 !strcmp(attr
->values
[1].string
.text
, "none")))
1554 * Force the leading banner to have the classification on it...
1557 cupsdSetString(&attr
->values
[0].string
.text
, Classification
);
1559 cupsdLogMessage(CUPSD_LOG_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
1560 "job-sheets=\"%s,none\", "
1561 "job-originating-user-name=\"%s\"",
1562 job
->id
, Classification
, job
->username
);
1564 else if (attr
->num_values
== 2 &&
1565 strcmp(attr
->values
[0].string
.text
,
1566 attr
->values
[1].string
.text
) &&
1567 strcmp(attr
->values
[0].string
.text
, "none") &&
1568 strcmp(attr
->values
[1].string
.text
, "none"))
1571 * Can't put two different security markings on the same document!
1574 cupsdSetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
1576 cupsdLogMessage(CUPSD_LOG_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
1577 "job-sheets=\"%s,%s\", "
1578 "job-originating-user-name=\"%s\"",
1579 job
->id
, attr
->values
[0].string
.text
,
1580 attr
->values
[1].string
.text
, job
->username
);
1582 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
1583 strcmp(attr
->values
[0].string
.text
, "none") &&
1584 (attr
->num_values
== 1 ||
1585 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
1586 strcmp(attr
->values
[1].string
.text
, "none"))))
1588 if (attr
->num_values
== 1)
1589 cupsdLogMessage(CUPSD_LOG_NOTICE
,
1590 "[Job %d] CLASSIFICATION OVERRIDDEN "
1591 "job-sheets=\"%s\", "
1592 "job-originating-user-name=\"%s\"",
1593 job
->id
, attr
->values
[0].string
.text
, job
->username
);
1595 cupsdLogMessage(CUPSD_LOG_NOTICE
,
1596 "[Job %d] CLASSIFICATION OVERRIDDEN "
1597 "job-sheets=\"%s,%s\",fffff "
1598 "job-originating-user-name=\"%s\"",
1599 job
->id
, attr
->values
[0].string
.text
,
1600 attr
->values
[1].string
.text
, job
->username
);
1603 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
1604 (attr
->num_values
== 1 ||
1605 strcmp(attr
->values
[1].string
.text
, Classification
)))
1608 * Force the banner to have the classification on it...
1611 if (attr
->num_values
> 1 &&
1612 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
1614 cupsdSetString(&(attr
->values
[0].string
.text
), Classification
);
1615 cupsdSetString(&(attr
->values
[1].string
.text
), Classification
);
1619 if (attr
->num_values
== 1 ||
1620 strcmp(attr
->values
[0].string
.text
, "none"))
1621 cupsdSetString(&(attr
->values
[0].string
.text
), Classification
);
1623 if (attr
->num_values
> 1 &&
1624 strcmp(attr
->values
[1].string
.text
, "none"))
1625 cupsdSetString(&(attr
->values
[1].string
.text
), Classification
);
1628 if (attr
->num_values
> 1)
1629 cupsdLogMessage(CUPSD_LOG_NOTICE
,
1630 "[Job %d] CLASSIFICATION FORCED "
1631 "job-sheets=\"%s,%s\", "
1632 "job-originating-user-name=\"%s\"",
1633 job
->id
, attr
->values
[0].string
.text
,
1634 attr
->values
[1].string
.text
, job
->username
);
1636 cupsdLogMessage(CUPSD_LOG_NOTICE
,
1637 "[Job %d] CLASSIFICATION FORCED "
1638 "job-sheets=\"%s\", "
1639 "job-originating-user-name=\"%s\"",
1640 job
->id
, Classification
, job
->username
);
1645 * See if we need to add the starting sheet...
1648 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
1650 cupsdLogMessage(CUPSD_LOG_INFO
,
1651 "Adding start banner page \"%s\" to job %d.",
1652 attr
->values
[0].string
.text
, job
->id
);
1654 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
1656 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
1659 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets",
1660 IPP_TAG_ZERO
)) != NULL
)
1664 * Fill in the response info...
1667 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
1668 LocalPort
, job
->id
);
1670 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
1673 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
1675 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
1677 add_job_state_reasons(con
, job
);
1679 con
->response
->request
.status
.status_code
= IPP_OK
;
1682 * Add any job subscriptions...
1685 add_job_subscriptions(con
, job
);
1688 * Set all but the first two attributes to the job attributes group...
1691 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
1692 attr
->group_tag
= IPP_TAG_JOB
;
1695 * Fire the "job created" event...
1698 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
1701 * Return the new job...
1709 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1710 * upon the job and printer state...
1714 add_job_state_reasons(
1715 cupsd_client_t
*con
, /* I - Client connection */
1716 cupsd_job_t
*job
) /* I - Job info */
1718 cupsd_printer_t
*dest
; /* Destination printer */
1721 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_job_state_reasons(%p[%d], %d)",
1722 con
, con
->http
.fd
, job
? job
->id
: 0);
1724 switch (job
? job
->state_value
: IPP_JOB_CANCELED
)
1726 case IPP_JOB_PENDING
:
1727 dest
= cupsdFindDest(job
->dest
);
1729 if (dest
&& dest
->state
== IPP_PRINTER_STOPPED
)
1730 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1731 "job-state-reasons", NULL
, "printer-stopped");
1733 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1734 "job-state-reasons", NULL
, "none");
1738 if (ippFindAttribute(job
->attrs
, "job-hold-until",
1739 IPP_TAG_KEYWORD
) != NULL
||
1740 ippFindAttribute(job
->attrs
, "job-hold-until",
1741 IPP_TAG_NAME
) != NULL
)
1742 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1743 "job-state-reasons", NULL
, "job-hold-until-specified");
1745 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1746 "job-state-reasons", NULL
, "job-incoming");
1749 case IPP_JOB_PROCESSING
:
1750 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1751 "job-state-reasons", NULL
, "job-printing");
1754 case IPP_JOB_STOPPED
:
1755 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1756 "job-state-reasons", NULL
, "job-stopped");
1759 case IPP_JOB_CANCELED
:
1760 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1761 "job-state-reasons", NULL
, "job-canceled-by-user");
1764 case IPP_JOB_ABORTED
:
1765 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1766 "job-state-reasons", NULL
, "aborted-by-system");
1769 case IPP_JOB_COMPLETED
:
1770 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1771 "job-state-reasons", NULL
, "job-completed-successfully");
1778 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1782 add_job_subscriptions(
1783 cupsd_client_t
*con
, /* I - Client connection */
1784 cupsd_job_t
*job
) /* I - Newly created job */
1786 int i
; /* Looping var */
1787 ipp_attribute_t
*prev
, /* Previous attribute */
1788 *next
, /* Next attribute */
1789 *attr
; /* Current attribute */
1790 cupsd_subscription_t
*sub
; /* Subscription object */
1791 const char *recipient
, /* notify-recipient-uri */
1792 *pullmethod
; /* notify-pull-method */
1793 ipp_attribute_t
*user_data
; /* notify-user-data */
1794 int interval
; /* notify-time-interval */
1795 unsigned mask
; /* notify-events */
1799 * Find the first subscription group attribute; return if we have
1803 for (attr
= job
->attrs
->attrs
, prev
= NULL
;
1805 prev
= attr
, attr
= attr
->next
)
1806 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1813 * Process the subscription attributes in the request...
1822 mask
= CUPSD_EVENT_NONE
;
1824 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1826 if (!strcmp(attr
->name
, "notify-recipient") &&
1827 attr
->value_tag
== IPP_TAG_URI
)
1828 recipient
= attr
->values
[0].string
.text
;
1829 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1830 attr
->value_tag
== IPP_TAG_KEYWORD
)
1831 pullmethod
= attr
->values
[0].string
.text
;
1832 else if (!strcmp(attr
->name
, "notify-charset") &&
1833 attr
->value_tag
== IPP_TAG_CHARSET
&&
1834 strcmp(attr
->values
[0].string
.text
, "us-ascii") &&
1835 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1837 send_ipp_status(con
, IPP_CHARSET
,
1838 _("Character set \"%s\" not supported!"),
1839 attr
->values
[0].string
.text
);
1842 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1843 (attr
->value_tag
!= IPP_TAG_LANGUAGE
||
1844 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
)))
1846 send_ipp_status(con
, IPP_CHARSET
,
1847 _("Language \"%s\" not supported!"),
1848 attr
->values
[0].string
.text
);
1851 else if (!strcmp(attr
->name
, "notify-user-data") &&
1852 attr
->value_tag
== IPP_TAG_STRING
)
1854 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1856 send_ipp_status(con
, IPP_REQUEST_VALUE
,
1857 _("The notify-user-data value is too large "
1858 "(%d > 63 octets)!"),
1859 attr
->values
[0].unknown
.length
);
1865 else if (!strcmp(attr
->name
, "notify-events") &&
1866 attr
->value_tag
== IPP_TAG_KEYWORD
)
1868 for (i
= 0; i
< attr
->num_values
; i
++)
1869 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1871 else if (!strcmp(attr
->name
, "notify-lease-duration"))
1873 send_ipp_status(con
, IPP_BAD_REQUEST
,
1874 _("The notify-lease-duration attribute cannot be "
1875 "used with job subscriptions."));
1878 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1879 attr
->value_tag
== IPP_TAG_INTEGER
)
1880 interval
= attr
->values
[0].integer
;
1885 if (!recipient
&& !pullmethod
)
1888 if (mask
== CUPSD_EVENT_NONE
)
1889 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1891 sub
= cupsdAddSubscription(mask
, cupsdFindDest(job
->dest
), job
, recipient
,
1894 sub
->interval
= interval
;
1896 cupsdSetString(&sub
->owner
, job
->username
);
1900 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1901 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1902 sub
->user_data_len
);
1905 ippAddSeparator(con
->response
);
1906 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
1907 "notify-subscription-id", sub
->id
);
1913 cupsdSaveAllSubscriptions();
1916 * Remove all of the subscription attributes from the job request...
1919 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1923 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1924 attr
->group_tag
== IPP_TAG_ZERO
)
1927 * Free and remove this attribute...
1935 job
->attrs
->attrs
= next
;
1941 job
->attrs
->last
= prev
;
1942 job
->attrs
->current
= prev
;
1947 * 'add_job_uuid()' - Add job-uuid attribute to a job.
1949 * See RFC 4122 for the definition of UUIDs and the format.
1953 add_job_uuid(cupsd_client_t
*con
, /* I - Client connection */
1954 cupsd_job_t
*job
) /* I - Job */
1956 char uuid
[1024]; /* job-uuid string */
1957 _cups_md5_state_t md5state
; /* MD5 state */
1958 unsigned char md5sum
[16]; /* MD5 digest/sum */
1962 * First see if the job already has a job-uuid attribute; if so, return...
1965 if (ippFindAttribute(job
->attrs
, "job-uuid", IPP_TAG_URI
))
1969 * No job-uuid attribute, so build a version 3 UUID with the local job
1970 * ID at the end; see RFC 4122 for details. Start with the MD5 sum of
1971 * the ServerName, server name and port that the client connected to,
1972 * and local job ID...
1975 snprintf(uuid
, sizeof(uuid
), "%s:%s:%d:%d", ServerName
, con
->servername
,
1976 con
->serverport
, job
->id
);
1978 _cupsMD5Init(&md5state
);
1979 _cupsMD5Append(&md5state
, (unsigned char *)uuid
, strlen(uuid
));
1980 _cupsMD5Finish(&md5state
, md5sum
);
1983 * Format the UUID URI using the MD5 sum and job ID.
1986 snprintf(uuid
, sizeof(uuid
),
1987 "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
1988 "%02x%02x%02x%02x%02x%02x",
1989 md5sum
[0], md5sum
[1], md5sum
[2], md5sum
[3], md5sum
[4], md5sum
[5],
1990 (md5sum
[6] & 15) | 0x30, md5sum
[7], (md5sum
[8] & 0x3f) | 0x40,
1991 md5sum
[9], md5sum
[10], md5sum
[11], md5sum
[12], md5sum
[13],
1992 md5sum
[14], md5sum
[15]);
1994 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uuid", NULL
, uuid
);
1999 * 'add_printer()' - Add a printer to the system.
2003 add_printer(cupsd_client_t
*con
, /* I - Client connection */
2004 ipp_attribute_t
*uri
) /* I - URI of printer */
2006 http_status_t status
; /* Policy status */
2007 int i
; /* Looping var */
2008 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2009 username
[HTTP_MAX_URI
], /* Username portion of URI */
2010 host
[HTTP_MAX_URI
], /* Host portion of URI */
2011 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2012 int port
; /* Port portion of URI */
2013 cupsd_printer_t
*printer
; /* Printer/class */
2014 ipp_attribute_t
*attr
; /* Printer attribute */
2015 cups_file_t
*fp
; /* Script/PPD file */
2016 char line
[1024]; /* Line from file... */
2017 char srcfile
[1024], /* Source Script/PPD file */
2018 dstfile
[1024]; /* Destination Script/PPD file */
2019 int modify
; /* Non-zero if we are modifying */
2020 char newname
[IPP_MAX_NAME
]; /* New printer name */
2021 int need_restart_job
; /* Need to restart job? */
2024 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_printer(%p[%d], %s)", con
,
2025 con
->http
.fd
, uri
->values
[0].string
.text
);
2028 * Do we have a valid URI?
2031 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
2032 sizeof(method
), username
, sizeof(username
), host
,
2033 sizeof(host
), &port
, resource
, sizeof(resource
));
2035 if (strncmp(resource
, "/printers/", 10) || strlen(resource
) == 10)
2038 * No, return an error...
2041 send_ipp_status(con
, IPP_BAD_REQUEST
,
2042 _("The printer-uri must be of the form "
2043 "\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
2048 * Do we have a valid printer name?
2051 if (!validate_name(resource
+ 10))
2054 * No, return an error...
2057 send_ipp_status(con
, IPP_BAD_REQUEST
,
2058 _("The printer-uri \"%s\" contains invalid characters."),
2059 uri
->values
[0].string
.text
);
2067 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
2069 send_http_error(con
, status
);
2074 * See if the printer already exists; if not, create a new printer...
2077 if ((printer
= cupsdFindPrinter(resource
+ 10)) == NULL
)
2080 * Printer doesn't exist; see if we have a class of the same name...
2083 if ((printer
= cupsdFindClass(resource
+ 10)) != NULL
&&
2084 !(printer
->type
& CUPS_PRINTER_REMOTE
))
2087 * Yes, return an error...
2090 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2091 _("A class named \"%s\" already exists!"),
2097 * No, add the printer...
2100 printer
= cupsdAddPrinter(resource
+ 10);
2103 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
2106 * Rename the implicit printer to "AnyPrinter" or delete it...
2109 if (ImplicitAnyClasses
)
2111 snprintf(newname
, sizeof(newname
), "Any%s", resource
+ 10);
2112 cupsdRenamePrinter(printer
, newname
);
2115 cupsdDeletePrinter(printer
, 1);
2118 * Add the printer as a new local printer...
2121 printer
= cupsdAddPrinter(resource
+ 10);
2124 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
2127 * Rename the remote printer to "Printer@server"...
2130 snprintf(newname
, sizeof(newname
), "%s@%s", resource
+ 10,
2132 cupsdRenamePrinter(printer
, newname
);
2135 * Add the printer as a new local printer...
2138 printer
= cupsdAddPrinter(resource
+ 10);
2145 * Look for attributes and copy them over as needed...
2148 need_restart_job
= 0;
2150 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
2151 IPP_TAG_TEXT
)) != NULL
)
2152 cupsdSetString(&printer
->location
, attr
->values
[0].string
.text
);
2154 if ((attr
= ippFindAttribute(con
->request
, "printer-info",
2155 IPP_TAG_TEXT
)) != NULL
)
2156 cupsdSetString(&printer
->info
, attr
->values
[0].string
.text
);
2158 if ((attr
= ippFindAttribute(con
->request
, "device-uri",
2159 IPP_TAG_URI
)) != NULL
)
2162 * Do we have a valid device URI?
2165 need_restart_job
= 1;
2167 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
, method
,
2168 sizeof(method
), username
, sizeof(username
), host
,
2169 sizeof(host
), &port
, resource
, sizeof(resource
));
2171 if (!strcmp(method
, "file"))
2174 * See if the administrator has enabled file devices...
2177 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
2180 * File devices are disabled and the URL is not file:/dev/null...
2183 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2184 _("File device URIs have been disabled! "
2185 "To enable, see the FileDevice directive in "
2186 "\"%s/cupsd.conf\"."),
2194 * See if the backend exists and is executable...
2197 snprintf(srcfile
, sizeof(srcfile
), "%s/backend/%s", ServerBin
, method
);
2198 if (access(srcfile
, X_OK
))
2201 * Could not find device in list!
2204 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Bad device-uri \"%s\"!"),
2205 attr
->values
[0].string
.text
);
2210 cupsdLogMessage(CUPSD_LOG_INFO
,
2211 "Setting %s device-uri to \"%s\" (was \"%s\".)",
2213 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
,
2215 cupsdSanitizeURI(printer
->device_uri
, resource
,
2218 cupsdSetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
2221 if ((attr
= ippFindAttribute(con
->request
, "port-monitor",
2222 IPP_TAG_KEYWORD
)) != NULL
)
2224 ipp_attribute_t
*supported
; /* port-monitor-supported attribute */
2227 need_restart_job
= 1;
2229 supported
= ippFindAttribute(printer
->attrs
, "port-monitor-supported",
2231 for (i
= 0; i
< supported
->num_values
; i
++)
2232 if (!strcmp(supported
->values
[i
].string
.text
,
2233 attr
->values
[0].string
.text
))
2236 if (i
>= supported
->num_values
)
2238 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Bad port-monitor \"%s\"!"),
2239 attr
->values
[0].string
.text
);
2243 cupsdLogMessage(CUPSD_LOG_INFO
,
2244 "Setting %s port-monitor to \"%s\" (was \"%s\".)",
2245 printer
->name
, attr
->values
[0].string
.text
,
2246 printer
->port_monitor
);
2248 if (strcmp(attr
->values
[0].string
.text
, "none"))
2249 cupsdSetString(&printer
->port_monitor
, attr
->values
[0].string
.text
);
2251 cupsdClearString(&printer
->port_monitor
);
2254 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs",
2255 IPP_TAG_BOOLEAN
)) != NULL
)
2257 cupsdLogMessage(CUPSD_LOG_INFO
,
2258 "Setting %s printer-is-accepting-jobs to %d (was %d.)",
2259 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
2261 printer
->accepting
= attr
->values
[0].boolean
;
2262 cupsdAddPrinterHistory(printer
);
2265 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared",
2266 IPP_TAG_BOOLEAN
)) != NULL
)
2268 if (printer
->shared
&& !attr
->values
[0].boolean
)
2269 cupsdSendBrowseDelete(printer
);
2271 cupsdLogMessage(CUPSD_LOG_INFO
,
2272 "Setting %s printer-is-shared to %d (was %d.)",
2273 printer
->name
, attr
->values
[0].boolean
, printer
->shared
);
2275 printer
->shared
= attr
->values
[0].boolean
;
2278 if ((attr
= ippFindAttribute(con
->request
, "printer-state",
2279 IPP_TAG_ENUM
)) != NULL
)
2281 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
2282 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
2284 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad printer-state value %d!"),
2285 attr
->values
[0].integer
);
2289 cupsdLogMessage(CUPSD_LOG_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
2290 attr
->values
[0].integer
, printer
->state
);
2292 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
2293 cupsdStopPrinter(printer
, 0);
2296 need_restart_job
= 1;
2297 cupsdSetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
2300 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
2301 IPP_TAG_TEXT
)) != NULL
)
2303 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
2304 sizeof(printer
->state_message
));
2305 cupsdAddPrinterHistory(printer
);
2308 set_printer_defaults(con
, printer
);
2311 * See if we have all required attributes...
2314 if (!printer
->device_uri
)
2315 cupsdSetString(&printer
->device_uri
, "file:///dev/null");
2318 * See if we have an interface script or PPD file attached to the request...
2323 need_restart_job
= 1;
2325 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
2327 if ((fp
= cupsFileOpen(srcfile
, "rb")))
2330 * Yes; get the first line from it...
2334 cupsFileGets(fp
, line
, sizeof(line
));
2338 * Then see what kind of file it is...
2341 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2344 if (!strncmp(line
, "*PPD-Adobe", 10))
2347 * The new file is a PPD file, so remove any old interface script
2348 * that might be lying around...
2356 * This must be an interface script, so move the file over to the
2357 * interfaces directory and make it executable...
2360 if (copy_file(srcfile
, dstfile
))
2362 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
2363 _("Unable to copy interface script - %s!"),
2369 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2370 "Copied interface script successfully!");
2371 chmod(dstfile
, 0755);
2375 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2378 if (!strncmp(line
, "*PPD-Adobe", 10))
2381 * The new file is a PPD file, so move the file over to the
2382 * ppd directory and make it readable by all...
2385 if (copy_file(srcfile
, dstfile
))
2387 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
2388 _("Unable to copy PPD file - %s!"),
2394 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2395 "Copied PPD file successfully!");
2396 chmod(dstfile
, 0644);
2402 * This must be an interface script, so remove any old PPD file that
2403 * may be lying around...
2410 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name",
2411 IPP_TAG_NAME
)) != NULL
)
2413 need_restart_job
= 1;
2415 if (!strcmp(attr
->values
[0].string
.text
, "raw"))
2418 * Raw driver, remove any existing PPD or interface script files.
2421 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2425 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2435 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
2439 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
2442 if (copy_model(con
, attr
->values
[0].string
.text
, dstfile
))
2444 send_ipp_status(con
, IPP_INTERNAL_ERROR
, _("Unable to copy PPD file!"));
2449 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2450 "Copied PPD file successfully!");
2451 chmod(dstfile
, 0644);
2457 * Update the printer attributes and return...
2460 cupsdSetPrinterAttrs(printer
);
2461 cupsdSaveAllPrinters();
2463 if (need_restart_job
&& printer
->job
)
2468 * Stop the current job and then restart it below...
2471 job
= (cupsd_job_t
*)printer
->job
;
2473 cupsdStopJob(job
, 1);
2475 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
2476 job
->state_value
= IPP_JOB_PENDING
;
2479 if (need_restart_job
)
2482 cupsdWritePrintcap();
2486 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
2487 "Printer \"%s\" modified by \"%s\".", printer
->name
,
2490 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" modified by \"%s\".",
2491 printer
->name
, get_username(con
));
2495 cupsdAddPrinterHistory(printer
);
2497 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
2498 "New printer \"%s\" added by \"%s\".", printer
->name
,
2501 cupsdLogMessage(CUPSD_LOG_INFO
, "New printer \"%s\" added by \"%s\".",
2502 printer
->name
, get_username(con
));
2505 con
->response
->request
.status
.status_code
= IPP_OK
;
2510 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
2511 * based upon the printer state...
2515 add_printer_state_reasons(
2516 cupsd_client_t
*con
, /* I - Client connection */
2517 cupsd_printer_t
*p
) /* I - Printer info */
2519 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
2520 "add_printer_state_reasons(%p[%d], %p[%s])",
2521 con
, con
->http
.fd
, p
, p
->name
);
2523 if (p
->num_reasons
== 0)
2524 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
2525 "printer-state-reasons", NULL
,
2526 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
2528 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
2529 "printer-state-reasons", p
->num_reasons
, NULL
,
2530 (const char * const *)p
->reasons
);
2535 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
2536 * the specified printer or class.
2540 add_queued_job_count(
2541 cupsd_client_t
*con
, /* I - Client connection */
2542 cupsd_printer_t
*p
) /* I - Printer or class */
2544 int count
; /* Number of jobs on destination */
2547 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])",
2548 con
, con
->http
.fd
, p
, p
->name
);
2550 count
= cupsdGetPrinterJobCount(p
->name
);
2552 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
2553 "queued-job-count", count
);
2558 * 'apply_printer_defaults()' - Apply printer default options to a job.
2562 apply_printer_defaults(
2563 cupsd_printer_t
*printer
, /* I - Printer */
2564 cupsd_job_t
*job
) /* I - Job */
2566 int i
, /* Looping var */
2567 num_options
; /* Number of default options */
2568 cups_option_t
*options
, /* Default options */
2569 *option
; /* Current option */
2573 * Collect all of the default options and add the missing ones to the
2577 for (i
= printer
->num_options
, num_options
= 0, option
= printer
->options
;
2580 if (!ippFindAttribute(job
->attrs
, option
->name
, IPP_TAG_ZERO
))
2582 num_options
= cupsAddOption(option
->name
, option
->value
, num_options
,
2587 * Encode these options as attributes in the job object...
2590 cupsEncodeOptions2(job
->attrs
, num_options
, options
, IPP_TAG_JOB
);
2591 cupsFreeOptions(num_options
, options
);
2596 * 'authenticate_job()' - Set job authentication info.
2600 authenticate_job(cupsd_client_t
*con
, /* I - Client connection */
2601 ipp_attribute_t
*uri
) /* I - Job URI */
2603 ipp_attribute_t
*attr
; /* Job-id attribute */
2604 int jobid
; /* Job ID */
2605 cupsd_job_t
*job
; /* Current job */
2606 char method
[HTTP_MAX_URI
],
2607 /* Method portion of URI */
2608 username
[HTTP_MAX_URI
],
2609 /* Username portion of URI */
2611 /* Host portion of URI */
2612 resource
[HTTP_MAX_URI
];
2613 /* Resource portion of URI */
2614 int port
; /* Port portion of URI */
2617 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "authenticate_job(%p[%d], %s)",
2618 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
2621 * Start with "everything is OK" status...
2624 con
->response
->request
.status
.status_code
= IPP_OK
;
2627 * See if we have a job URI or a printer URI...
2630 if (!strcmp(uri
->name
, "printer-uri"))
2633 * Got a printer URI; see if we also have a job-id attribute...
2636 if ((attr
= ippFindAttribute(con
->request
, "job-id",
2637 IPP_TAG_INTEGER
)) == NULL
)
2639 send_ipp_status(con
, IPP_BAD_REQUEST
,
2640 _("Got a printer-uri attribute but no job-id!"));
2644 jobid
= attr
->values
[0].integer
;
2649 * Got a job URI; parse it to get the job ID...
2652 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
2653 sizeof(method
), username
, sizeof(username
), host
,
2654 sizeof(host
), &port
, resource
, sizeof(resource
));
2656 if (strncmp(resource
, "/jobs/", 6))
2662 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad job-uri attribute \"%s\"!"),
2663 uri
->values
[0].string
.text
);
2667 jobid
= atoi(resource
+ 6);
2671 * See if the job exists...
2674 if ((job
= cupsdFindJob(jobid
)) == NULL
)
2677 * Nope - return a "not found" error...
2680 send_ipp_status(con
, IPP_NOT_FOUND
,
2681 _("Job #%d does not exist!"), jobid
);
2686 * See if the job has been completed...
2689 if (job
->state_value
!= IPP_JOB_HELD
)
2692 * Return a "not-possible" error...
2695 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
2696 _("Job #%d is not held for authentication!"),
2702 * See if we have already authenticated...
2705 if (!con
->username
[0])
2707 send_ipp_status(con
, IPP_NOT_AUTHORIZED
,
2708 _("No authentication information provided!"));
2713 * See if the job is owned by the requesting user...
2716 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2718 send_http_error(con
, HTTP_UNAUTHORIZED
);
2723 * Save the authentication information for this job...
2726 save_auth_info(con
, job
);
2729 * Reset the job-hold-until value to "no-hold"...
2732 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
2733 IPP_TAG_KEYWORD
)) == NULL
)
2734 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
2738 attr
->value_tag
= IPP_TAG_KEYWORD
;
2739 cupsdSetString(&(attr
->values
[0].string
.text
), "no-hold");
2743 * Release the job and return...
2746 cupsdReleaseJob(job
);
2748 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d was authenticated by \"%s\".", jobid
,
2754 * 'cancel_all_jobs()' - Cancel all print jobs.
2758 cancel_all_jobs(cupsd_client_t
*con
, /* I - Client connection */
2759 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2761 http_status_t status
; /* Policy status */
2762 const char *dest
; /* Destination */
2763 cups_ptype_t dtype
; /* Destination type */
2764 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2765 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
2766 host
[HTTP_MAX_URI
], /* Host portion of URI */
2767 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2768 int port
; /* Port portion of URI */
2769 ipp_attribute_t
*attr
; /* Attribute in request */
2770 const char *username
; /* Username */
2771 int purge
; /* Purge? */
2772 cupsd_printer_t
*printer
; /* Printer */
2775 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cancel_all_jobs(%p[%d], %s)", con
,
2776 con
->http
.fd
, uri
->values
[0].string
.text
);
2779 * See if we have a printer URI...
2782 if (strcmp(uri
->name
, "printer-uri"))
2784 send_ipp_status(con
, IPP_BAD_REQUEST
,
2785 _("The printer-uri attribute is required!"));
2790 * Get the username (if any) for the jobs we want to cancel (only if
2791 * "my-jobs" is specified...
2794 if ((attr
= ippFindAttribute(con
->request
, "my-jobs",
2795 IPP_TAG_BOOLEAN
)) != NULL
&&
2796 attr
->values
[0].boolean
)
2798 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
2799 IPP_TAG_NAME
)) != NULL
)
2800 username
= attr
->values
[0].string
.text
;
2803 send_ipp_status(con
, IPP_BAD_REQUEST
,
2804 _("Missing requesting-user-name attribute!"));
2812 * Look for the "purge-jobs" attribute...
2815 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs",
2816 IPP_TAG_BOOLEAN
)) != NULL
)
2817 purge
= attr
->values
[0].boolean
;
2822 * And if the destination is valid...
2825 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
2826 sizeof(method
), userpass
, sizeof(userpass
), host
,
2827 sizeof(host
), &port
, resource
, sizeof(resource
));
2829 if ((dest
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2835 if ((!strncmp(resource
, "/printers/", 10) && resource
[10]) ||
2836 (!strncmp(resource
, "/classes/", 9) && resource
[9]))
2838 send_ipp_status(con
, IPP_NOT_FOUND
,
2839 _("The printer or class was not found."));
2842 else if (strcmp(resource
, "/printers/"))
2844 send_ipp_status(con
, IPP_NOT_FOUND
,
2845 _("The printer-uri \"%s\" is not valid."),
2846 uri
->values
[0].string
.text
);
2854 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
2856 send_http_error(con
, status
);
2861 * Cancel all jobs on all printers...
2864 cupsdCancelJobs(NULL
, username
, purge
);
2866 cupsdLogMessage(CUPSD_LOG_INFO
, "All jobs were %s by \"%s\".",
2867 purge
? "purged" : "canceled", get_username(con
));
2875 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
2877 send_http_error(con
, status
);
2882 * Cancel all of the jobs on the named printer...
2885 cupsdCancelJobs(dest
, username
, purge
);
2887 cupsdLogMessage(CUPSD_LOG_INFO
, "All jobs on \"%s\" were %s by \"%s\".",
2888 dest
, purge
? "purged" : "canceled", get_username(con
));
2891 con
->response
->request
.status
.status_code
= IPP_OK
;
2896 * 'cancel_job()' - Cancel a print job.
2900 cancel_job(cupsd_client_t
*con
, /* I - Client connection */
2901 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2903 ipp_attribute_t
*attr
; /* Current attribute */
2904 int jobid
; /* Job ID */
2905 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2906 username
[HTTP_MAX_URI
], /* Username portion of URI */
2907 host
[HTTP_MAX_URI
], /* Host portion of URI */
2908 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2909 int port
; /* Port portion of URI */
2910 cupsd_job_t
*job
; /* Job information */
2911 const char *dest
; /* Destination */
2912 cups_ptype_t dtype
; /* Destination type (printer or class) */
2913 cupsd_printer_t
*printer
; /* Printer data */
2916 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cancel_job(%p[%d], %s)", con
,
2917 con
->http
.fd
, uri
->values
[0].string
.text
);
2920 * See if we have a job URI or a printer URI...
2923 if (!strcmp(uri
->name
, "printer-uri"))
2926 * Got a printer URI; see if we also have a job-id attribute...
2929 if ((attr
= ippFindAttribute(con
->request
, "job-id",
2930 IPP_TAG_INTEGER
)) == NULL
)
2932 send_ipp_status(con
, IPP_BAD_REQUEST
,
2933 _("Got a printer-uri attribute but no job-id!"));
2937 if ((jobid
= attr
->values
[0].integer
) == 0)
2940 * Find the current job on the specified printer...
2943 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
2944 sizeof(method
), username
, sizeof(username
), host
,
2945 sizeof(host
), &port
, resource
, sizeof(resource
));
2947 if ((dest
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2953 send_ipp_status(con
, IPP_NOT_FOUND
,
2954 _("The printer or class was not found."));
2959 * See if the printer is currently printing a job...
2963 jobid
= ((cupsd_job_t
*)printer
->job
)->id
;
2967 * No, see if there are any pending jobs...
2970 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
2972 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
2973 if (job
->state_value
<= IPP_JOB_PROCESSING
&&
2974 !strcasecmp(job
->dest
, dest
))
2981 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("No active jobs on %s!"),
2991 * Got a job URI; parse it to get the job ID...
2994 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
2995 sizeof(method
), username
, sizeof(username
), host
,
2996 sizeof(host
), &port
, resource
, sizeof(resource
));
2998 if (strncmp(resource
, "/jobs/", 6))
3004 send_ipp_status(con
, IPP_BAD_REQUEST
,
3005 _("Bad job-uri attribute \"%s\"!"),
3006 uri
->values
[0].string
.text
);
3010 jobid
= atoi(resource
+ 6);
3014 * See if the job exists...
3017 if ((job
= cupsdFindJob(jobid
)) == NULL
)
3020 * Nope - return a "not found" error...
3023 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
3028 * See if the job is owned by the requesting user...
3031 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
3033 send_http_error(con
, HTTP_UNAUTHORIZED
);
3038 * See if the job is already completed, canceled, or aborted; if so,
3039 * we can't cancel...
3042 if (job
->state_value
>= IPP_JOB_CANCELED
)
3044 switch (job
->state_value
)
3046 case IPP_JOB_CANCELED
:
3047 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
3048 _("Job #%d is already canceled - can\'t cancel."),
3052 case IPP_JOB_ABORTED
:
3053 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
3054 _("Job #%d is already aborted - can\'t cancel."),
3059 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
3060 _("Job #%d is already completed - can\'t cancel."),
3069 * Cancel the job and return...
3072 cupsdCancelJob(job
, 0, IPP_JOB_CANCELED
);
3075 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d was canceled by \"%s\".", jobid
,
3078 con
->response
->request
.status
.status_code
= IPP_OK
;
3083 * 'cancel_subscription()' - Cancel a subscription.
3087 cancel_subscription(
3088 cupsd_client_t
*con
, /* I - Client connection */
3089 int sub_id
) /* I - Subscription ID */
3091 http_status_t status
; /* Policy status */
3092 cupsd_subscription_t
*sub
; /* Subscription */
3095 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3096 "cancel_subscription(con=%p[%d], sub_id=%d)",
3097 con
, con
->http
.fd
, sub_id
);
3100 * Is the subscription ID valid?
3103 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
3106 * Bad subscription ID...
3109 send_ipp_status(con
, IPP_NOT_FOUND
,
3110 _("notify-subscription-id %d no good!"), sub_id
);
3118 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
3120 con
, sub
->owner
)) != HTTP_OK
)
3122 send_http_error(con
, status
);
3127 * Cancel the subscription...
3130 cupsdDeleteSubscription(sub
, 1);
3132 con
->response
->request
.status
.status_code
= IPP_OK
;
3137 * 'check_quotas()' - Check quotas for a printer and user.
3140 static int /* O - 1 if OK, 0 if not */
3141 check_quotas(cupsd_client_t
*con
, /* I - Client connection */
3142 cupsd_printer_t
*p
) /* I - Printer or class */
3144 int i
; /* Looping var */
3145 char username
[33]; /* Username */
3146 cupsd_quota_t
*q
; /* Quota data */
3147 struct passwd
*pw
; /* User password data */
3150 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "check_quotas(%p[%d], %p[%s])",
3151 con
, con
->http
.fd
, p
, p
->name
);
3161 * Figure out who is printing...
3164 strlcpy(username
, get_username(con
), sizeof(username
));
3167 * Check global active job limits for printers and users...
3170 if (MaxJobsPerPrinter
)
3173 * Check if there are too many pending jobs on this printer...
3176 if (cupsdGetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
3178 cupsdLogMessage(CUPSD_LOG_INFO
, "Too many jobs for printer \"%s\"...",
3187 * Check if there are too many pending jobs for this user...
3190 if (cupsdGetUserJobCount(username
) >= MaxJobsPerUser
)
3192 cupsdLogMessage(CUPSD_LOG_INFO
, "Too many jobs for user \"%s\"...",
3199 * Check against users...
3202 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
3207 pw
= getpwnam(username
);
3210 for (i
= 0; i
< p
->num_users
; i
++)
3211 if (p
->users
[i
][0] == '@')
3214 * Check group membership...
3217 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
3220 else if (!strcasecmp(username
, p
->users
[i
]))
3223 if ((i
< p
->num_users
) == p
->deny_users
)
3225 cupsdLogMessage(CUPSD_LOG_INFO
,
3226 "Denying user \"%s\" access to printer \"%s\"...",
3236 if (p
->k_limit
|| p
->page_limit
)
3238 if ((q
= cupsdUpdateQuota(p
, username
, 0, 0)) == NULL
)
3240 cupsdLogMessage(CUPSD_LOG_ERROR
,
3241 "Unable to allocate quota data for user \"%s\"!",
3246 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
3247 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
3249 cupsdLogMessage(CUPSD_LOG_INFO
, "User \"%s\" is over the quota limit...",
3256 * If we have gotten this far, we're done!
3264 * 'copy_attribute()' - Copy a single attribute.
3267 static ipp_attribute_t
* /* O - New attribute */
3269 ipp_t
*to
, /* O - Destination request/response */
3270 ipp_attribute_t
*attr
, /* I - Attribute to copy */
3271 int quickcopy
) /* I - Do a quick copy? */
3273 int i
; /* Looping var */
3274 ipp_attribute_t
*toattr
; /* Destination attribute */
3277 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3278 "copy_attribute(%p, %p[%s,%x,%x])", to
, attr
,
3279 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
3282 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
3285 toattr
= ippAddSeparator(to
);
3288 case IPP_TAG_INTEGER
:
3290 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
3291 attr
->name
, attr
->num_values
, NULL
);
3293 for (i
= 0; i
< attr
->num_values
; i
++)
3294 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
3297 case IPP_TAG_BOOLEAN
:
3298 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
3299 attr
->num_values
, NULL
);
3301 for (i
= 0; i
< attr
->num_values
; i
++)
3302 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
3305 case IPP_TAG_STRING
:
3308 case IPP_TAG_KEYWORD
:
3310 case IPP_TAG_URISCHEME
:
3311 case IPP_TAG_CHARSET
:
3312 case IPP_TAG_LANGUAGE
:
3313 case IPP_TAG_MIMETYPE
:
3314 toattr
= ippAddStrings(to
, attr
->group_tag
,
3315 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
3316 attr
->name
, attr
->num_values
, NULL
, NULL
);
3320 for (i
= 0; i
< attr
->num_values
; i
++)
3321 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
3325 for (i
= 0; i
< attr
->num_values
; i
++)
3326 toattr
->values
[i
].string
.text
= _cupsStrAlloc(attr
->values
[i
].string
.text
);
3331 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
3332 attr
->values
[0].date
);
3335 case IPP_TAG_RESOLUTION
:
3336 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
3337 attr
->num_values
, IPP_RES_PER_INCH
,
3340 for (i
= 0; i
< attr
->num_values
; i
++)
3342 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
3343 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
3344 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
3348 case IPP_TAG_RANGE
:
3349 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
3350 attr
->num_values
, NULL
, NULL
);
3352 for (i
= 0; i
< attr
->num_values
; i
++)
3354 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
3355 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
3359 case IPP_TAG_TEXTLANG
:
3360 case IPP_TAG_NAMELANG
:
3361 toattr
= ippAddStrings(to
, attr
->group_tag
,
3362 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
3363 attr
->name
, attr
->num_values
, NULL
, NULL
);
3367 for (i
= 0; i
< attr
->num_values
; i
++)
3369 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
3370 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
3375 for (i
= 0; i
< attr
->num_values
; i
++)
3378 toattr
->values
[i
].string
.charset
=
3379 _cupsStrAlloc(attr
->values
[i
].string
.charset
);
3381 toattr
->values
[i
].string
.charset
=
3382 toattr
->values
[0].string
.charset
;
3384 toattr
->values
[i
].string
.text
= _cupsStrAlloc(attr
->values
[i
].string
.text
);
3389 case IPP_TAG_BEGIN_COLLECTION
:
3390 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
3391 attr
->num_values
, NULL
);
3393 for (i
= 0; i
< attr
->num_values
; i
++)
3395 toattr
->values
[i
].collection
= ippNew();
3396 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
3397 NULL
, IPP_TAG_ZERO
, 0);
3402 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
3403 attr
->name
, attr
->num_values
, NULL
);
3405 for (i
= 0; i
< attr
->num_values
; i
++)
3407 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
3409 if (toattr
->values
[i
].unknown
.length
> 0)
3411 if ((toattr
->values
[i
].unknown
.data
=
3412 malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
3413 toattr
->values
[i
].unknown
.length
= 0;
3415 memcpy(toattr
->values
[i
].unknown
.data
,
3416 attr
->values
[i
].unknown
.data
,
3417 toattr
->values
[i
].unknown
.length
);
3420 break; /* anti-compiler-warning-code */
3428 * 'copy_attrs()' - Copy attributes from one request to another.
3432 copy_attrs(ipp_t
*to
, /* I - Destination request */
3433 ipp_t
*from
, /* I - Source request */
3434 cups_array_t
*ra
, /* I - Requested attributes */
3435 ipp_tag_t group
, /* I - Group to copy */
3436 int quickcopy
) /* I - Do a quick copy? */
3438 ipp_attribute_t
*fromattr
; /* Source attribute */
3441 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3442 "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
3443 to
, from
, ra
, group
, quickcopy
);
3448 for (fromattr
= from
->attrs
; fromattr
; fromattr
= fromattr
->next
)
3451 * Filter attributes as needed...
3454 if ((group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
3455 fromattr
->group_tag
!= IPP_TAG_ZERO
) || !fromattr
->name
)
3458 if (!ra
|| cupsArrayFind(ra
, fromattr
->name
))
3459 copy_attribute(to
, fromattr
, quickcopy
);
3465 * 'copy_banner()' - Copy a banner file to the requests directory for the
3469 static int /* O - Size of banner file in kbytes */
3470 copy_banner(cupsd_client_t
*con
, /* I - Client connection */
3471 cupsd_job_t
*job
, /* I - Job information */
3472 const char *name
) /* I - Name of banner */
3474 int i
; /* Looping var */
3475 int kbytes
; /* Size of banner file in kbytes */
3476 char filename
[1024]; /* Job filename */
3477 cupsd_banner_t
*banner
; /* Pointer to banner */
3478 cups_file_t
*in
; /* Input file */
3479 cups_file_t
*out
; /* Output file */
3480 int ch
; /* Character from file */
3481 char attrname
[255], /* Name of attribute */
3482 *s
; /* Pointer into name */
3483 ipp_attribute_t
*attr
; /* Attribute */
3486 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
3487 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
3490 * Find the banner; return if not found or "none"...
3493 if (!name
|| !strcmp(name
, "none") ||
3494 (banner
= cupsdFindBanner(name
)) == NULL
)
3498 * Open the banner and job files...
3501 if (add_file(con
, job
, banner
->filetype
, 0))
3504 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
3506 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
3508 cupsdLogMessage(CUPSD_LOG_ERROR
,
3509 "copy_banner: Unable to create banner job file %s - %s",
3510 filename
, strerror(errno
));
3515 fchmod(cupsFileNumber(out
), 0640);
3516 fchown(cupsFileNumber(out
), RunUser
, Group
);
3519 * Try the localized banner file under the subdirectory...
3522 strlcpy(attrname
, job
->attrs
->attrs
->next
->values
[0].string
.text
,
3524 if (strlen(attrname
) > 2 && attrname
[2] == '-')
3527 * Convert ll-cc to ll_CC...
3531 attrname
[3] = toupper(attrname
[3] & 255);
3532 attrname
[4] = toupper(attrname
[4] & 255);
3535 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
3538 if (access(filename
, 0) && strlen(attrname
) > 2)
3541 * Wasn't able to find "ll_CC" locale file; try the non-national
3542 * localization banner directory.
3547 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
3551 if (access(filename
, 0))
3554 * Use the non-localized banner file.
3557 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
3560 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
3564 cupsdLogMessage(CUPSD_LOG_ERROR
,
3565 "copy_banner: Unable to open banner template file %s - %s",
3566 filename
, strerror(errno
));
3572 * Parse the file to the end...
3575 while ((ch
= cupsFileGetChar(in
)) != EOF
)
3579 * Get an attribute name...
3582 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
3583 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
3585 else if (s
< (attrname
+ sizeof(attrname
) - 1))
3595 * Ignore { followed by stuff that is not an attribute name...
3598 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
3603 * See if it is defined...
3606 if (attrname
[0] == '?')
3611 if (!strcmp(s
, "printer-name"))
3613 cupsFilePuts(out
, job
->dest
);
3616 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
3619 * See if we have a leading question mark...
3622 if (attrname
[0] != '?')
3625 * Nope, write to file as-is; probably a PostScript procedure...
3628 cupsFilePrintf(out
, "{%s}", attrname
);
3635 * Output value(s)...
3638 for (i
= 0; i
< attr
->num_values
; i
++)
3641 cupsFilePutChar(out
, ',');
3643 switch (attr
->value_tag
)
3645 case IPP_TAG_INTEGER
:
3647 if (!strncmp(s
, "time-at-", 8))
3648 cupsFilePuts(out
, cupsdGetDateTime(attr
->values
[i
].integer
));
3650 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
3653 case IPP_TAG_BOOLEAN
:
3654 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
3657 case IPP_TAG_NOVALUE
:
3658 cupsFilePuts(out
, "novalue");
3661 case IPP_TAG_RANGE
:
3662 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
3663 attr
->values
[i
].range
.upper
);
3666 case IPP_TAG_RESOLUTION
:
3667 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
3668 attr
->values
[i
].resolution
.yres
,
3669 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3674 case IPP_TAG_STRING
:
3677 case IPP_TAG_KEYWORD
:
3678 case IPP_TAG_CHARSET
:
3679 case IPP_TAG_LANGUAGE
:
3680 if (!strcasecmp(banner
->filetype
->type
, "postscript"))
3683 * Need to quote strings for PS banners...
3688 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
3690 if (*p
== '(' || *p
== ')' || *p
== '\\')
3692 cupsFilePutChar(out
, '\\');
3693 cupsFilePutChar(out
, *p
);
3695 else if (*p
< 32 || *p
> 126)
3696 cupsFilePrintf(out
, "\\%03o", *p
& 255);
3698 cupsFilePutChar(out
, *p
);
3702 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
3706 break; /* anti-compiler-warning-code */
3710 else if (ch
== '\\') /* Quoted char */
3712 ch
= cupsFileGetChar(in
);
3714 if (ch
!= '{') /* Only do special handling for \{ */
3715 cupsFilePutChar(out
, '\\');
3717 cupsFilePutChar(out
, ch
);
3720 cupsFilePutChar(out
, ch
);
3724 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
3726 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
3727 IPP_TAG_INTEGER
)) != NULL
)
3728 attr
->values
[0].integer
+= kbytes
;
3737 * 'copy_file()' - Copy a PPD file or interface script...
3740 static int /* O - 0 = success, -1 = error */
3741 copy_file(const char *from
, /* I - Source file */
3742 const char *to
) /* I - Destination file */
3744 cups_file_t
*src
, /* Source file */
3745 *dst
; /* Destination file */
3746 int bytes
; /* Bytes to read/write */
3747 char buffer
[2048]; /* Copy buffer */
3750 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "copy_file(\"%s\", \"%s\")", from
, to
);
3753 * Open the source and destination file for a copy...
3756 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3759 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3766 * Copy the source file to the destination...
3769 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
3770 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
3778 * Close both files and return...
3783 return (cupsFileClose(dst
));
3788 * 'copy_model()' - Copy a PPD model file, substituting default values
3792 static int /* O - 0 = success, -1 = error */
3793 copy_model(cupsd_client_t
*con
, /* I - Client connection */
3794 const char *from
, /* I - Source file */
3795 const char *to
) /* I - Destination file */
3797 fd_set
*input
; /* select() input set */
3798 struct timeval timeout
; /* select() timeout */
3799 int maxfd
; /* Maximum file descriptor for select() */
3800 char tempfile
[1024]; /* Temporary PPD file */
3801 int tempfd
; /* Temporary PPD file descriptor */
3802 int temppid
; /* Process ID of cups-driverd */
3803 int temppipe
[2]; /* Temporary pipes */
3804 char *argv
[4], /* Command-line arguments */
3805 *envp
[MAX_ENV
]; /* Environment */
3806 cups_file_t
*src
, /* Source file */
3807 *dst
; /* Destination file */
3808 ppd_file_t
*ppd
; /* PPD file */
3809 int bytes
, /* Bytes from pipe */
3810 total
; /* Total bytes from pipe */
3811 char buffer
[2048]; /* Copy buffer */
3812 int i
; /* Looping var */
3813 char option
[PPD_MAX_NAME
], /* Option name */
3814 choice
[PPD_MAX_NAME
]; /* Choice name */
3815 int num_defaults
; /* Number of default options */
3816 cups_option_t
*defaults
; /* Default options */
3817 char cups_protocol
[PPD_MAX_LINE
];
3818 /* cupsProtocol attribute */
3819 int have_letter
, /* Have Letter size */
3820 have_a4
; /* Have A4 size */
3821 #ifdef HAVE_LIBPAPER
3822 char *paper_result
; /* Paper size name from libpaper */
3823 char system_paper
[64]; /* Paper size name buffer */
3824 #endif /* HAVE_LIBPAPER */
3827 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3828 "copy_model(con=%p, from=\"%s\", to=\"%s\")",
3832 * Run cups-driverd to get the PPD file...
3835 argv
[0] = "cups-driverd";
3837 argv
[2] = (char *)from
;
3840 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
3842 snprintf(buffer
, sizeof(buffer
), "%s/daemon/cups-driverd", ServerBin
);
3843 snprintf(tempfile
, sizeof(tempfile
), "%s/%d.ppd", TempDir
, con
->http
.fd
);
3844 tempfd
= open(tempfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
3848 cupsdOpenPipe(temppipe
);
3850 if ((input
= calloc(1, SetSize
)) == NULL
)
3855 cupsdLogMessage(CUPSD_LOG_ERROR
,
3856 "copy_model: Unable to allocate %d bytes for select()...",
3861 cupsdLogMessage(CUPSD_LOG_DEBUG
,
3862 "copy_model: Running \"cups-driverd cat %s\"...", from
);
3864 if (!cupsdStartProcess(buffer
, argv
, envp
, -1, temppipe
[1], CGIPipes
[1],
3876 * Wait up to 30 seconds for the PPD file to be copied...
3881 if (temppipe
[0] > CGIPipes
[0])
3882 maxfd
= temppipe
[0] + 1;
3884 maxfd
= CGIPipes
[0] + 1;
3889 * See if we have data ready...
3894 FD_SET(temppipe
[0], input
);
3895 FD_SET(CGIPipes
[0], input
);
3897 timeout
.tv_sec
= 30;
3898 timeout
.tv_usec
= 0;
3900 if ((i
= select(maxfd
, input
, NULL
, NULL
, &timeout
)) < 0)
3910 * We have timed out...
3916 if (FD_ISSET(temppipe
[0], input
))
3919 * Read the PPD file from the pipe, and write it to the PPD file.
3922 if ((bytes
= read(temppipe
[0], buffer
, sizeof(buffer
))) > 0)
3924 if (write(tempfd
, buffer
, bytes
) < bytes
)
3933 if (FD_ISSET(CGIPipes
[0], input
))
3945 * No data from cups-deviced...
3948 cupsdLogMessage(CUPSD_LOG_ERROR
, "copy_model: empty PPD file!");
3954 * Read the source file and see what page sizes are supported...
3957 if ((ppd
= ppdOpenFile(tempfile
)) == NULL
)
3963 have_letter
= ppdPageSize(ppd
, "Letter") != NULL
;
3964 have_a4
= ppdPageSize(ppd
, "A4") != NULL
;
3967 * Open the destination (if possible) and set the default options...
3972 cups_protocol
[0] = '\0';
3974 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
3977 * Read all of the default lines from the old PPD...
3980 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)))
3981 if (!strncmp(buffer
, "*Default", 8))
3984 * Add the default option...
3987 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3988 choice
, sizeof(choice
)))
3990 ppd_option_t
*ppdo
; /* PPD option */
3994 * Only add the default if the default hasn't already been
3995 * set and the choice exists in the new PPD...
3998 if (!cupsGetOption(option
, num_defaults
, defaults
) &&
3999 (ppdo
= ppdFindOption(ppd
, option
)) != NULL
&&
4000 ppdFindChoice(ppdo
, choice
))
4001 num_defaults
= cupsAddOption(option
, choice
, num_defaults
,
4005 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
4006 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
4010 #ifdef HAVE_LIBPAPER
4011 else if ((paper_result
= systempapername()) != NULL
)
4014 * Set the default media sizes from the systemwide default...
4017 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
4018 system_paper
[0] = toupper(system_paper
[0] & 255);
4020 if ((!strcmp(system_paper
, "Letter") && have_letter
) ||
4021 (!strcmp(system_paper
, "A4") && have_a4
))
4023 num_defaults
= ppd_add_default("PageSize", system_paper
,
4024 num_defaults
, &defaults
);
4025 num_defaults
= ppd_add_default("PageRegion", system_paper
,
4026 num_defaults
, &defaults
);
4027 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
4028 num_defaults
, &defaults
);
4029 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
4030 num_defaults
, &defaults
);
4033 #endif /* HAVE_LIBPAPER */
4037 * Add the default media sizes...
4039 * Note: These values are generally not valid for large-format devices
4040 * like plotters, however it is probably safe to say that those
4041 * users will configure the media size after initially adding
4042 * the device anyways...
4045 if (!DefaultLanguage
||
4046 !strcasecmp(DefaultLanguage
, "C") ||
4047 !strcasecmp(DefaultLanguage
, "POSIX") ||
4048 !strcasecmp(DefaultLanguage
, "en") ||
4049 !strncasecmp(DefaultLanguage
, "en.", 3) ||
4050 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
4051 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
4052 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
4055 * These are the only locales that will default to "letter" size...
4060 num_defaults
= cupsAddOption("PageSize", "Letter", num_defaults
,
4062 num_defaults
= cupsAddOption("PageRegion", "Letter", num_defaults
,
4064 num_defaults
= cupsAddOption("PaperDimension", "Letter", num_defaults
,
4066 num_defaults
= cupsAddOption("ImageableArea", "Letter", num_defaults
,
4073 * The rest default to "a4" size...
4076 num_defaults
= cupsAddOption("PageSize", "A4", num_defaults
,
4078 num_defaults
= cupsAddOption("PageRegion", "A4", num_defaults
,
4080 num_defaults
= cupsAddOption("PaperDimension", "A4", num_defaults
,
4082 num_defaults
= cupsAddOption("ImageableArea", "A4", num_defaults
,
4090 * Open the source file for a copy...
4093 if ((src
= cupsFileOpen(tempfile
, "rb")) == NULL
)
4095 cupsFreeOptions(num_defaults
, defaults
);
4101 * Open the destination file for a copy...
4104 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
4106 cupsFreeOptions(num_defaults
, defaults
);
4113 * Copy the source file to the destination...
4116 while (cupsFileGets(src
, buffer
, sizeof(buffer
)))
4118 if (!strncmp(buffer
, "*Default", 8))
4121 * Check for an previous default option choice...
4124 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
4125 choice
, sizeof(choice
)))
4127 const char *val
; /* Default option value */
4130 if ((val
= cupsGetOption(option
, num_defaults
, defaults
)) != NULL
)
4133 * Substitute the previous choice...
4136 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
, val
);
4141 cupsFilePrintf(dst
, "%s\n", buffer
);
4144 if (cups_protocol
[0])
4145 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
4147 cupsFreeOptions(num_defaults
, defaults
);
4150 * Close both files and return...
4157 return (cupsFileClose(dst
));
4162 * 'copy_job_attrs()' - Copy job attributes.
4166 copy_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
4167 cupsd_job_t
*job
, /* I - Job */
4168 cups_array_t
*ra
) /* I - Requested attributes array */
4170 char job_uri
[HTTP_MAX_URI
]; /* Job URI */
4174 * Send the requested attributes for each job...
4177 httpAssembleURIf(HTTP_URI_CODING_ALL
, job_uri
, sizeof(job_uri
), "ipp", NULL
,
4178 con
->servername
, con
->serverport
, "/jobs/%d",
4181 if (!ra
|| cupsArrayFind(ra
, "job-more-info"))
4182 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4183 "job-more-info", NULL
, job_uri
);
4185 if (job
->state_value
> IPP_JOB_PROCESSING
&&
4186 (!ra
|| cupsArrayFind(ra
, "job-preserved")))
4187 ippAddBoolean(con
->response
, IPP_TAG_JOB
, "job-preserved",
4188 job
->num_files
> 0);
4190 if (!ra
|| cupsArrayFind(ra
, "job-printer-up-time"))
4191 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4192 "job-printer-up-time", time(NULL
));
4194 if (!ra
|| cupsArrayFind(ra
, "job-state-reasons"))
4195 add_job_state_reasons(con
, job
);
4197 if (!ra
|| cupsArrayFind(ra
, "job-uri"))
4198 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4199 "job-uri", NULL
, job_uri
);
4201 copy_attrs(con
->response
, job
->attrs
, ra
, IPP_TAG_JOB
, 0);
4206 * 'copy_printer_attrs()' - Copy printer attributes.
4211 cupsd_client_t
*con
, /* I - Client connection */
4212 cupsd_printer_t
*printer
, /* I - Printer */
4213 cups_array_t
*ra
) /* I - Requested attributes array */
4215 char printer_uri
[HTTP_MAX_URI
];
4217 time_t curtime
; /* Current time */
4218 int i
; /* Looping var */
4219 ipp_attribute_t
*history
; /* History collection */
4223 * Copy the printer attributes to the response using requested-attributes
4224 * and document-format attributes that may be provided by the client.
4227 curtime
= time(NULL
);
4230 if ((!ra
|| cupsArrayFind(ra
, "com.apple.print.recoverable-message")) &&
4231 printer
->recoverable
)
4232 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4233 "com.apple.print.recoverable-message", NULL
,
4234 printer
->recoverable
);
4235 #endif /* __APPLE__ */
4237 if (!ra
|| cupsArrayFind(ra
, "printer-current-time"))
4238 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4239 ippTimeToDate(curtime
));
4241 if (!ra
|| cupsArrayFind(ra
, "printer-error-policy"))
4242 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4243 "printer-error-policy", NULL
, printer
->error_policy
);
4245 if (!ra
|| cupsArrayFind(ra
, "printer-is-accepting-jobs"))
4246 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4247 printer
->accepting
);
4249 if (!ra
|| cupsArrayFind(ra
, "printer-is-shared"))
4250 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
4253 if (!ra
|| cupsArrayFind(ra
, "printer-op-policy"))
4254 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4255 "printer-op-policy", NULL
, printer
->op_policy
);
4257 if (!ra
|| cupsArrayFind(ra
, "printer-state"))
4258 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4261 if (!ra
|| cupsArrayFind(ra
, "printer-state-change-time"))
4262 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4263 "printer-state-change-time", printer
->state_time
);
4265 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 &&
4266 cupsArrayFind(ra
, "printer-state-history"))
4269 * Printer history is only sent if specifically requested, so that
4270 * older CUPS/IPP clients won't barf on the collection attributes.
4273 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4274 "printer-state-history",
4275 printer
->num_history
, NULL
);
4277 for (i
= 0; i
< printer
->num_history
; i
++)
4278 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4279 NULL
, IPP_TAG_ZERO
, 0);
4282 if (!ra
|| cupsArrayFind(ra
, "printer-state-message"))
4283 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4284 "printer-state-message", NULL
, printer
->state_message
);
4286 if (!ra
|| cupsArrayFind(ra
, "printer-state-reasons"))
4287 add_printer_state_reasons(con
, printer
);
4289 if (!ra
|| cupsArrayFind(ra
, "printer-type"))
4291 int type
; /* printer-type value */
4295 * Add the CUPS-specific printer-type attribute...
4298 type
= printer
->type
;
4300 if (printer
== DefaultPrinter
)
4301 type
|= CUPS_PRINTER_DEFAULT
;
4303 if (!printer
->accepting
)
4304 type
|= CUPS_PRINTER_REJECTING
;
4306 if (!printer
->shared
)
4307 type
|= CUPS_PRINTER_NOT_SHARED
;
4309 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-type",
4313 if (!ra
|| cupsArrayFind(ra
, "printer-up-time"))
4314 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4315 "printer-up-time", curtime
);
4317 if ((!ra
|| cupsArrayFind(ra
, "printer-uri-supported")) &&
4318 !ippFindAttribute(printer
->attrs
, "printer-uri-supported",
4321 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
),
4322 "ipp", NULL
, con
->servername
, con
->serverport
,
4323 (printer
->type
& CUPS_PRINTER_CLASS
) ?
4324 "/classes/%s" : "/printers/%s", printer
->name
);
4325 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
4326 "printer-uri-supported", NULL
, printer_uri
);
4327 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "printer-uri-supported=\"%s\"",
4331 if (!ra
|| cupsArrayFind(ra
, "queued-job-count"))
4332 add_queued_job_count(con
, printer
);
4334 copy_attrs(con
->response
, printer
->attrs
, ra
, IPP_TAG_ZERO
, 0);
4335 copy_attrs(con
->response
, CommonData
, ra
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4340 * 'copy_subscription_attrs()' - Copy subscription attributes.
4344 copy_subscription_attrs(
4345 cupsd_client_t
*con
, /* I - Client connection */
4346 cupsd_subscription_t
*sub
, /* I - Subscription */
4347 cups_array_t
*ra
) /* I - Requested attributes array */
4349 ipp_attribute_t
*attr
; /* Current attribute */
4350 char printer_uri
[HTTP_MAX_URI
];
4352 int count
; /* Number of events */
4353 unsigned mask
; /* Current event mask */
4354 const char *name
; /* Current event name */
4358 * Copy the subscription attributes to the response using the
4359 * requested-attributes attribute that may be provided by the client.
4362 if (!ra
|| cupsArrayFind(ra
, "notify-events"))
4364 if ((name
= cupsdEventName((cupsd_eventmask_t
)sub
->mask
)) != NULL
)
4367 * Simple event list...
4370 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
,
4371 (ipp_tag_t
)(IPP_TAG_KEYWORD
| IPP_TAG_COPY
),
4372 "notify-events", NULL
, name
);
4377 * Complex event list...
4380 for (mask
= 1, count
= 0; mask
< CUPSD_EVENT_ALL
; mask
<<= 1)
4381 if (sub
->mask
& mask
)
4384 attr
= ippAddStrings(con
->response
, IPP_TAG_SUBSCRIPTION
,
4385 (ipp_tag_t
)(IPP_TAG_KEYWORD
| IPP_TAG_COPY
),
4386 "notify-events", count
, NULL
, NULL
);
4388 for (mask
= 1, count
= 0; mask
< CUPSD_EVENT_ALL
; mask
<<= 1)
4389 if (sub
->mask
& mask
)
4391 attr
->values
[count
].string
.text
=
4392 (char *)cupsdEventName((cupsd_eventmask_t
)mask
);
4399 if (sub
->job
&& (!ra
|| cupsArrayFind(ra
, "notify-job-id")))
4400 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
4401 "notify-job-id", sub
->job
->id
);
4403 if (!sub
->job
&& (!ra
|| cupsArrayFind(ra
, "notify-lease-duration")))
4404 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
4405 "notify-lease-duration", sub
->lease
);
4407 if (sub
->dest
&& (!ra
|| cupsArrayFind(ra
, "notify-printer-uri")))
4409 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
),
4410 "ipp", NULL
, con
->servername
, con
->serverport
,
4411 "/printers/%s", sub
->dest
->name
);
4412 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
4413 "notify-printer-uri", NULL
, printer_uri
);
4416 if (sub
->recipient
&& (!ra
|| cupsArrayFind(ra
, "notify-recipient-uri")))
4417 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
4418 "notify-recipient-uri", NULL
, sub
->recipient
);
4419 else if (!ra
|| cupsArrayFind(ra
, "notify-pull-method"))
4420 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
,
4421 "notify-pull-method", NULL
, "ippget");
4423 if (!ra
|| cupsArrayFind(ra
, "notify-subscriber-user-name"))
4424 ippAddString(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_NAME
,
4425 "notify-subscriber-user-name", NULL
, sub
->owner
);
4427 if (!ra
|| cupsArrayFind(ra
, "notify-subscription-id"))
4428 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
4429 "notify-subscription-id", sub
->id
);
4431 if (!ra
|| cupsArrayFind(ra
, "notify-time-interval"))
4432 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
4433 "notify-time-interval", sub
->interval
);
4435 if (sub
->user_data_len
> 0 && (!ra
|| cupsArrayFind(ra
, "notify-user-data")))
4436 ippAddOctetString(con
->response
, IPP_TAG_SUBSCRIPTION
, "notify-user-data",
4437 sub
->user_data
, sub
->user_data_len
);
4442 * 'create_job()' - Print a file to a printer or class.
4446 create_job(cupsd_client_t
*con
, /* I - Client connection */
4447 ipp_attribute_t
*uri
) /* I - Printer URI */
4449 cupsd_job_t
*job
; /* New job */
4452 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "create_job(%p[%d], %s)", con
,
4453 con
->http
.fd
, uri
->values
[0].string
.text
);
4456 * Create the job object...
4459 if ((job
= add_job(con
, uri
, NULL
, NULL
)) == NULL
)
4463 * Save and log the job...
4468 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d created on \"%s\" by \"%s\".",
4469 job
->id
, job
->dest
, job
->username
);
4474 * 'create_requested_array()' - Create an array for the requested-attributes.
4477 static cups_array_t
* /* O - Array of attributes or NULL */
4478 create_requested_array(ipp_t
*request
) /* I - IPP request */
4480 int i
; /* Looping var */
4481 ipp_attribute_t
*requested
; /* requested-attributes attribute */
4482 cups_array_t
*ra
; /* Requested attributes array */
4483 char *value
; /* Current value */
4487 * Get the requested-attributes attribute, and return NULL if we don't
4491 if ((requested
= ippFindAttribute(request
, "requested-attributes",
4492 IPP_TAG_KEYWORD
)) == NULL
)
4496 * If the attribute contains a single "all" keyword, return NULL...
4499 if (requested
->num_values
== 1 &&
4500 !strcmp(requested
->values
[0].string
.text
, "all"))
4504 * Create an array using "strcmp" as the comparison function...
4507 ra
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
4509 for (i
= 0; i
< requested
->num_values
; i
++)
4511 value
= requested
->values
[i
].string
.text
;
4513 if (!strcmp(value
, "job-template"))
4515 cupsArrayAdd(ra
, "copies");
4516 cupsArrayAdd(ra
, "copies-default");
4517 cupsArrayAdd(ra
, "copies-supported");
4518 cupsArrayAdd(ra
, "finishings");
4519 cupsArrayAdd(ra
, "finishings-default");
4520 cupsArrayAdd(ra
, "finishings-supported");
4521 cupsArrayAdd(ra
, "job-hold-until");
4522 cupsArrayAdd(ra
, "job-hold-until-default");
4523 cupsArrayAdd(ra
, "job-hold-until-supported");
4524 cupsArrayAdd(ra
, "job-priority");
4525 cupsArrayAdd(ra
, "job-priority-default");
4526 cupsArrayAdd(ra
, "job-priority-supported");
4527 cupsArrayAdd(ra
, "job-sheets");
4528 cupsArrayAdd(ra
, "job-sheets-default");
4529 cupsArrayAdd(ra
, "job-sheets-supported");
4530 cupsArrayAdd(ra
, "media");
4531 cupsArrayAdd(ra
, "media-default");
4532 cupsArrayAdd(ra
, "media-supported");
4533 cupsArrayAdd(ra
, "multiple-document-handling");
4534 cupsArrayAdd(ra
, "multiple-document-handling-default");
4535 cupsArrayAdd(ra
, "multiple-document-handling-supported");
4536 cupsArrayAdd(ra
, "number-up");
4537 cupsArrayAdd(ra
, "number-up-default");
4538 cupsArrayAdd(ra
, "number-up-supported");
4539 cupsArrayAdd(ra
, "orientation-requested");
4540 cupsArrayAdd(ra
, "orientation-requested-default");
4541 cupsArrayAdd(ra
, "orientation-requested-supported");
4542 cupsArrayAdd(ra
, "page-ranges");
4543 cupsArrayAdd(ra
, "page-ranges-supported");
4544 cupsArrayAdd(ra
, "printer-resolution");
4545 cupsArrayAdd(ra
, "printer-resolution-default");
4546 cupsArrayAdd(ra
, "printer-resolution-supported");
4547 cupsArrayAdd(ra
, "print-quality");
4548 cupsArrayAdd(ra
, "print-quality-default");
4549 cupsArrayAdd(ra
, "print-quality-supported");
4550 cupsArrayAdd(ra
, "sides");
4551 cupsArrayAdd(ra
, "sides-default");
4552 cupsArrayAdd(ra
, "sides-supported");
4554 else if (!strcmp(value
, "job-description"))
4556 cupsArrayAdd(ra
, "date-time-at-completed");
4557 cupsArrayAdd(ra
, "date-time-at-creation");
4558 cupsArrayAdd(ra
, "date-time-at-processing");
4559 cupsArrayAdd(ra
, "job-detailed-status-message");
4560 cupsArrayAdd(ra
, "job-document-access-errors");
4561 cupsArrayAdd(ra
, "job-id");
4562 cupsArrayAdd(ra
, "job-impressions");
4563 cupsArrayAdd(ra
, "job-impressions-completed");
4564 cupsArrayAdd(ra
, "job-k-octets");
4565 cupsArrayAdd(ra
, "job-k-octets-processed");
4566 cupsArrayAdd(ra
, "job-media-sheets");
4567 cupsArrayAdd(ra
, "job-media-sheets-completed");
4568 cupsArrayAdd(ra
, "job-message-from-operator");
4569 cupsArrayAdd(ra
, "job-more-info");
4570 cupsArrayAdd(ra
, "job-name");
4571 cupsArrayAdd(ra
, "job-originating-user-name");
4572 cupsArrayAdd(ra
, "job-printer-up-time");
4573 cupsArrayAdd(ra
, "job-printer-uri");
4574 cupsArrayAdd(ra
, "job-state");
4575 cupsArrayAdd(ra
, "job-state-message");
4576 cupsArrayAdd(ra
, "job-state-reasons");
4577 cupsArrayAdd(ra
, "job-uri");
4578 cupsArrayAdd(ra
, "number-of-documents");
4579 cupsArrayAdd(ra
, "number-of-intervening-jobs");
4580 cupsArrayAdd(ra
, "output-device-assigned");
4581 cupsArrayAdd(ra
, "time-at-completed");
4582 cupsArrayAdd(ra
, "time-at-creation");
4583 cupsArrayAdd(ra
, "time-at-processing");
4585 else if (!strcmp(value
, "printer-description"))
4587 cupsArrayAdd(ra
, "charset-configured");
4588 cupsArrayAdd(ra
, "charset-supported");
4589 cupsArrayAdd(ra
, "color-supported");
4590 cupsArrayAdd(ra
, "compression-supported");
4591 cupsArrayAdd(ra
, "document-format-default");
4592 cupsArrayAdd(ra
, "document-format-supported");
4593 cupsArrayAdd(ra
, "generated-natural-language-supported");
4594 cupsArrayAdd(ra
, "ipp-versions-supported");
4595 cupsArrayAdd(ra
, "job-impressions-supported");
4596 cupsArrayAdd(ra
, "job-k-octets-supported");
4597 cupsArrayAdd(ra
, "job-media-sheets-supported");
4598 cupsArrayAdd(ra
, "multiple-document-jobs-supported");
4599 cupsArrayAdd(ra
, "multiple-operation-time-out");
4600 cupsArrayAdd(ra
, "natural-language-configured");
4601 cupsArrayAdd(ra
, "notify-attributes-supported");
4602 cupsArrayAdd(ra
, "notify-lease-duration-default");
4603 cupsArrayAdd(ra
, "notify-lease-duration-supported");
4604 cupsArrayAdd(ra
, "notify-max-events-supported");
4605 cupsArrayAdd(ra
, "notify-events-default");
4606 cupsArrayAdd(ra
, "notify-events-supported");
4607 cupsArrayAdd(ra
, "notify-pull-method-supported");
4608 cupsArrayAdd(ra
, "notify-schemes-supported");
4609 cupsArrayAdd(ra
, "operations-supported");
4610 cupsArrayAdd(ra
, "pages-per-minute");
4611 cupsArrayAdd(ra
, "pages-per-minute-color");
4612 cupsArrayAdd(ra
, "pdl-override-supported");
4613 cupsArrayAdd(ra
, "printer-current-time");
4614 cupsArrayAdd(ra
, "printer-driver-installer");
4615 cupsArrayAdd(ra
, "printer-info");
4616 cupsArrayAdd(ra
, "printer-is-accepting-jobs");
4617 cupsArrayAdd(ra
, "printer-location");
4618 cupsArrayAdd(ra
, "printer-make-and-model");
4619 cupsArrayAdd(ra
, "printer-message-from-operator");
4620 cupsArrayAdd(ra
, "printer-more-info");
4621 cupsArrayAdd(ra
, "printer-more-info-manufacturer");
4622 cupsArrayAdd(ra
, "printer-name");
4623 cupsArrayAdd(ra
, "printer-state");
4624 cupsArrayAdd(ra
, "printer-state-message");
4625 cupsArrayAdd(ra
, "printer-state-reasons");
4626 cupsArrayAdd(ra
, "printer-up-time");
4627 cupsArrayAdd(ra
, "printer-uri-supported");
4628 cupsArrayAdd(ra
, "queued-job-count");
4629 cupsArrayAdd(ra
, "reference-uri-schemes-supported");
4630 cupsArrayAdd(ra
, "uri-authentication-supported");
4631 cupsArrayAdd(ra
, "uri-security-supported");
4633 else if (!strcmp(value
, "subscription-template"))
4635 cupsArrayAdd(ra
, "notify-attributes");
4636 cupsArrayAdd(ra
, "notify-charset");
4637 cupsArrayAdd(ra
, "notify-events");
4638 cupsArrayAdd(ra
, "notify-lease-duration");
4639 cupsArrayAdd(ra
, "notify-natural-language");
4640 cupsArrayAdd(ra
, "notify-pull-method");
4641 cupsArrayAdd(ra
, "notify-recipient-uri");
4642 cupsArrayAdd(ra
, "notify-time-interval");
4643 cupsArrayAdd(ra
, "notify-user-data");
4646 cupsArrayAdd(ra
, value
);
4654 * 'create_subscription()' - Create a notification subscription.
4658 create_subscription(
4659 cupsd_client_t
*con
, /* I - Client connection */
4660 ipp_attribute_t
*uri
) /* I - Printer URI */
4662 http_status_t status
; /* Policy status */
4663 int i
; /* Looping var */
4664 ipp_attribute_t
*attr
; /* Current attribute */
4665 cups_ptype_t dtype
; /* Destination type (printer or class) */
4666 char scheme
[HTTP_MAX_URI
],
4667 /* Scheme portion of URI */
4668 userpass
[HTTP_MAX_URI
],
4669 /* Username portion of URI */
4671 /* Host portion of URI */
4672 resource
[HTTP_MAX_URI
];
4673 /* Resource portion of URI */
4674 int port
; /* Port portion of URI */
4675 cupsd_printer_t
*printer
; /* Printer/class */
4676 cupsd_job_t
*job
; /* Job */
4677 int jobid
; /* Job ID */
4678 cupsd_subscription_t
*sub
; /* Subscription object */
4679 const char *username
, /* requesting-user-name or authenticated username */
4680 *recipient
, /* notify-recipient-uri */
4681 *pullmethod
; /* notify-pull-method */
4682 ipp_attribute_t
*user_data
; /* notify-user-data */
4683 int interval
, /* notify-time-interval */
4684 lease
; /* notify-lease-duration */
4685 unsigned mask
; /* notify-events */
4689 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
4691 if (attr
->group_tag
!= IPP_TAG_ZERO
)
4692 cupsdLogMessage(CUPSD_LOG_DEBUG
, "g%04x v%04x %s", attr
->group_tag
,
4693 attr
->value_tag
, attr
->name
);
4695 cupsdLogMessage(CUPSD_LOG_DEBUG
, "----SEP----");
4700 * Is the destination valid?
4703 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4704 "cupsdCreateSubscription(con=%p(%d), uri=\"%s\")",
4705 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
4707 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, scheme
,
4708 sizeof(scheme
), userpass
, sizeof(userpass
), host
,
4709 sizeof(host
), &port
, resource
, sizeof(resource
));
4711 if (!strcmp(resource
, "/"))
4713 dtype
= (cups_ptype_t
)0;
4716 else if (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10)
4718 dtype
= (cups_ptype_t
)0;
4721 else if (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9)
4723 dtype
= CUPS_PRINTER_CLASS
;
4726 else if (!cupsdValidateDest(host
, resource
, &dtype
, &printer
))
4732 send_ipp_status(con
, IPP_NOT_FOUND
,
4733 _("The printer or class was not found."));
4743 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
4745 send_http_error(con
, status
);
4749 else if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
4751 send_http_error(con
, status
);
4756 * Get the user that is requesting the subscription...
4759 username
= get_username(con
);
4762 * Find the first subscription group attribute; return if we have
4766 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
4767 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
4772 send_ipp_status(con
, IPP_BAD_REQUEST
,
4773 _("No subscription attributes in request!"));
4778 * Process the subscription attributes in the request...
4781 con
->response
->request
.status
.status_code
= IPP_BAD_REQUEST
;
4789 lease
= DefaultLeaseDuration
;
4791 mask
= CUPSD_EVENT_NONE
;
4793 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
4795 if (!strcmp(attr
->name
, "notify-recipient") &&
4796 attr
->value_tag
== IPP_TAG_URI
)
4799 * Validate the recipient scheme against the ServerBin/notifier
4803 char notifier
[1024]; /* Notifier filename */
4806 recipient
= attr
->values
[0].string
.text
;
4808 if (httpSeparateURI(HTTP_URI_CODING_ALL
, recipient
,
4809 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
4810 host
, sizeof(host
), &port
,
4811 resource
, sizeof(resource
)) < HTTP_URI_OK
)
4813 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4814 _("Bad notify-recipient URI \"%s\"!"), recipient
);
4815 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
4816 "notify-status-code", IPP_URI_SCHEME
);
4820 snprintf(notifier
, sizeof(notifier
), "%s/notifier/%s", ServerBin
,
4822 if (access(notifier
, X_OK
))
4824 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4825 _("notify-recipient URI \"%s\" uses unknown scheme!"),
4827 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
4828 "notify-status-code", IPP_URI_SCHEME
);
4832 else if (!strcmp(attr
->name
, "notify-pull-method") &&
4833 attr
->value_tag
== IPP_TAG_KEYWORD
)
4835 pullmethod
= attr
->values
[0].string
.text
;
4837 if (strcmp(pullmethod
, "ippget"))
4839 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
4840 _("Bad notify-pull-method \"%s\"!"), pullmethod
);
4841 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_ENUM
,
4842 "notify-status-code", IPP_ATTRIBUTES
);
4846 else if (!strcmp(attr
->name
, "notify-charset") &&
4847 attr
->value_tag
== IPP_TAG_CHARSET
&&
4848 strcmp(attr
->values
[0].string
.text
, "us-ascii") &&
4849 strcmp(attr
->values
[0].string
.text
, "utf-8"))
4851 send_ipp_status(con
, IPP_CHARSET
,
4852 _("Character set \"%s\" not supported!"),
4853 attr
->values
[0].string
.text
);
4856 else if (!strcmp(attr
->name
, "notify-natural-language") &&
4857 (attr
->value_tag
!= IPP_TAG_LANGUAGE
||
4858 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
)))
4860 send_ipp_status(con
, IPP_CHARSET
,
4861 _("Language \"%s\" not supported!"),
4862 attr
->values
[0].string
.text
);
4865 else if (!strcmp(attr
->name
, "notify-user-data") &&
4866 attr
->value_tag
== IPP_TAG_STRING
)
4868 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
4870 send_ipp_status(con
, IPP_REQUEST_VALUE
,
4871 _("The notify-user-data value is too large "
4872 "(%d > 63 octets)!"),
4873 attr
->values
[0].unknown
.length
);
4879 else if (!strcmp(attr
->name
, "notify-events") &&
4880 attr
->value_tag
== IPP_TAG_KEYWORD
)
4882 for (i
= 0; i
< attr
->num_values
; i
++)
4883 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
4885 else if (!strcmp(attr
->name
, "notify-lease-duration") &&
4886 attr
->value_tag
== IPP_TAG_INTEGER
)
4887 lease
= attr
->values
[0].integer
;
4888 else if (!strcmp(attr
->name
, "notify-time-interval") &&
4889 attr
->value_tag
== IPP_TAG_INTEGER
)
4890 interval
= attr
->values
[0].integer
;
4891 else if (!strcmp(attr
->name
, "notify-job-id") &&
4892 attr
->value_tag
== IPP_TAG_INTEGER
)
4893 jobid
= attr
->values
[0].integer
;
4899 cupsdLogMessage(CUPSD_LOG_DEBUG
, "recipient=\"%s\"", recipient
);
4901 cupsdLogMessage(CUPSD_LOG_DEBUG
, "pullmethod=\"%s\"", pullmethod
);
4902 cupsdLogMessage(CUPSD_LOG_DEBUG
, "notify-lease-duration=%d", lease
);
4903 cupsdLogMessage(CUPSD_LOG_DEBUG
, "notify-time-interval=%d", interval
);
4905 if (!recipient
&& !pullmethod
)
4908 if (mask
== CUPSD_EVENT_NONE
)
4911 mask
= CUPSD_EVENT_JOB_COMPLETED
;
4913 mask
= CUPSD_EVENT_PRINTER_STATE_CHANGED
;
4916 send_ipp_status(con
, IPP_BAD_REQUEST
,
4917 _("notify-events not specified!"));
4922 if (MaxLeaseDuration
&& (lease
== 0 || lease
> MaxLeaseDuration
))
4924 cupsdLogMessage(CUPSD_LOG_INFO
,
4925 "create_subscription: Limiting notify-lease-duration to "
4928 lease
= MaxLeaseDuration
;
4933 if ((job
= cupsdFindJob(jobid
)) == NULL
)
4935 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job %d not found!"), jobid
);
4942 sub
= cupsdAddSubscription(mask
, printer
, job
, recipient
, 0);
4945 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added subscription %d for job %d",
4948 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4949 "Added subscription %d for printer \"%s\"",
4950 sub
->id
, printer
->name
);
4952 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added subscription %d for server",
4955 sub
->interval
= interval
;
4957 sub
->expire
= lease
? time(NULL
) + lease
: 0;
4959 cupsdSetString(&sub
->owner
, username
);
4963 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
4964 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
4965 sub
->user_data_len
);
4968 ippAddSeparator(con
->response
);
4969 ippAddInteger(con
->response
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
4970 "notify-subscription-id", sub
->id
);
4972 con
->response
->request
.status
.status_code
= IPP_OK
;
4978 cupsdSaveAllSubscriptions();
4984 * 'delete_printer()' - Remove a printer or class from the system.
4988 delete_printer(cupsd_client_t
*con
, /* I - Client connection */
4989 ipp_attribute_t
*uri
) /* I - URI of printer or class */
4991 http_status_t status
; /* Policy status */
4992 const char *dest
; /* Destination */
4993 cups_ptype_t dtype
; /* Destination type (printer or class) */
4994 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4995 username
[HTTP_MAX_URI
], /* Username portion of URI */
4996 host
[HTTP_MAX_URI
], /* Host portion of URI */
4997 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4998 int port
; /* Port portion of URI */
4999 cupsd_printer_t
*printer
; /* Printer/class */
5000 char filename
[1024]; /* Script/PPD filename */
5003 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "delete_printer(%p[%d], %s)", con
,
5004 con
->http
.fd
, uri
->values
[0].string
.text
);
5007 * Do we have a valid URI?
5010 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
5011 sizeof(method
), username
, sizeof(username
), host
,
5012 sizeof(host
), &port
, resource
, sizeof(resource
));
5014 if ((dest
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5020 send_ipp_status(con
, IPP_NOT_FOUND
,
5021 _("The printer or class was not found."));
5029 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5031 send_http_error(con
, status
);
5036 * Remove old jobs...
5039 cupsdCancelJobs(dest
, NULL
, 1);
5042 * Remove old subscriptions and send a "deleted printer" event...
5045 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
5046 "%s \"%s\" deleted by \"%s\".",
5047 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
5048 dest
, get_username(con
));
5050 cupsdExpireSubscriptions(printer
, NULL
);
5053 * Remove any old PPD or script files...
5056 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
5059 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
5062 if (dtype
& CUPS_PRINTER_CLASS
)
5064 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" deleted by \"%s\".", dest
,
5067 cupsdDeletePrinter(printer
, 0);
5068 cupsdSaveAllClasses();
5072 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" deleted by \"%s\".", dest
,
5075 cupsdDeletePrinter(printer
, 0);
5076 cupsdSaveAllPrinters();
5079 cupsdWritePrintcap();
5082 * Return with no errors...
5085 con
->response
->request
.status
.status_code
= IPP_OK
;
5090 * 'get_default()' - Get the default destination.
5094 get_default(cupsd_client_t
*con
) /* I - Client connection */
5096 http_status_t status
; /* Policy status */
5097 cups_array_t
*ra
; /* Requested attributes array */
5100 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_default(%p[%d])", con
, con
->http
.fd
);
5106 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5108 send_http_error(con
, status
);
5114 ra
= create_requested_array(con
->request
);
5116 copy_printer_attrs(con
, DefaultPrinter
, ra
);
5118 cupsArrayDelete(ra
);
5120 con
->response
->request
.status
.status_code
= IPP_OK
;
5123 send_ipp_status(con
, IPP_NOT_FOUND
, _("No default printer"));
5128 * 'get_devices()' - Get the list of available devices on the local system.
5132 get_devices(cupsd_client_t
*con
) /* I - Client connection */
5134 http_status_t status
; /* Policy status */
5135 ipp_attribute_t
*limit
, /* Limit attribute */
5136 *requested
; /* requested-attributes attribute */
5137 char command
[1024], /* cups-deviced command */
5138 options
[1024], /* Options to pass to command */
5140 /* String for requested attributes */
5143 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_devices(%p[%d])", con
, con
->http
.fd
);
5149 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5151 send_http_error(con
, status
);
5156 * Run cups-deviced command with the given options...
5159 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
5160 requested
= ippFindAttribute(con
->request
, "requested-attributes",
5164 url_encode_attr(requested
, requested_str
, sizeof(requested_str
));
5166 strlcpy(requested_str
, "requested-attributes=all", sizeof(requested_str
));
5168 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
5169 snprintf(options
, sizeof(options
),
5171 con
->request
->request
.op
.request_id
,
5172 limit
? limit
->values
[0].integer
: 0, (int)User
,
5175 if (cupsdSendCommand(con
, command
, options
, 1))
5178 * Command started successfully, don't send an IPP response here...
5181 ippDelete(con
->response
);
5182 con
->response
= NULL
;
5187 * Command failed, return "internal error" so the user knows something
5191 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
5192 _("cups-deviced failed to execute."));
5198 * 'get_job_attrs()' - Get job attributes.
5202 get_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
5203 ipp_attribute_t
*uri
) /* I - Job URI */
5205 http_status_t status
; /* Policy status */
5206 ipp_attribute_t
*attr
; /* Current attribute */
5207 int jobid
; /* Job ID */
5208 cupsd_job_t
*job
; /* Current job */
5209 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5210 username
[HTTP_MAX_URI
], /* Username portion of URI */
5211 host
[HTTP_MAX_URI
], /* Host portion of URI */
5212 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5213 int port
; /* Port portion of URI */
5214 cups_array_t
*ra
; /* Requested attributes array */
5217 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_job_attrs(%p[%d], %s)", con
,
5218 con
->http
.fd
, uri
->values
[0].string
.text
);
5221 * See if we have a job URI or a printer URI...
5224 if (!strcmp(uri
->name
, "printer-uri"))
5227 * Got a printer URI; see if we also have a job-id attribute...
5230 if ((attr
= ippFindAttribute(con
->request
, "job-id",
5231 IPP_TAG_INTEGER
)) == NULL
)
5233 send_ipp_status(con
, IPP_BAD_REQUEST
,
5234 _("Got a printer-uri attribute but no job-id!"));
5238 jobid
= attr
->values
[0].integer
;
5243 * Got a job URI; parse it to get the job ID...
5246 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
5247 sizeof(method
), username
, sizeof(username
), host
,
5248 sizeof(host
), &port
, resource
, sizeof(resource
));
5250 if (strncmp(resource
, "/jobs/", 6))
5256 send_ipp_status(con
, IPP_BAD_REQUEST
,
5257 _("Bad job-uri attribute \"%s\"!"),
5258 uri
->values
[0].string
.text
);
5262 jobid
= atoi(resource
+ 6);
5266 * See if the job exists...
5269 if ((job
= cupsdFindJob(jobid
)) == NULL
)
5272 * Nope - return a "not found" error...
5275 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
5283 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5285 send_http_error(con
, status
);
5290 * Copy attributes...
5295 ra
= create_requested_array(con
->request
);
5296 copy_job_attrs(con
, job
, ra
);
5297 cupsArrayDelete(ra
);
5299 con
->response
->request
.status
.status_code
= IPP_OK
;
5304 * 'get_jobs()' - Get a list of jobs for the specified printer.
5308 get_jobs(cupsd_client_t
*con
, /* I - Client connection */
5309 ipp_attribute_t
*uri
) /* I - Printer URI */
5311 http_status_t status
; /* Policy status */
5312 ipp_attribute_t
*attr
; /* Current attribute */
5313 const char *dest
; /* Destination */
5314 cups_ptype_t dtype
; /* Destination type (printer or class) */
5315 cups_ptype_t dmask
; /* Destination type mask */
5316 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5317 username
[HTTP_MAX_URI
], /* Username portion of URI */
5318 host
[HTTP_MAX_URI
], /* Host portion of URI */
5319 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5320 int port
; /* Port portion of URI */
5321 int completed
; /* Completed jobs? */
5322 int first_job_id
; /* First job ID */
5323 int limit
; /* Maximum number of jobs to return */
5324 int count
; /* Number of jobs that match */
5325 cupsd_job_t
*job
; /* Current job pointer */
5326 cupsd_printer_t
*printer
; /* Printer */
5327 cups_array_t
*list
; /* Which job list... */
5328 cups_array_t
*ra
; /* Requested attributes array */
5331 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs(%p[%d], %s)", con
, con
->http
.fd
,
5332 uri
->values
[0].string
.text
);
5335 * Is the destination valid?
5338 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
5339 sizeof(method
), username
, sizeof(username
), host
,
5340 sizeof(host
), &port
, resource
, sizeof(resource
));
5342 if (!strcmp(resource
, "/") ||
5343 (!strncmp(resource
, "/jobs", 5) && strlen(resource
) <= 6))
5346 dtype
= (cups_ptype_t
)0;
5347 dmask
= (cups_ptype_t
)0;
5350 else if (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10)
5353 dtype
= (cups_ptype_t
)0;
5354 dmask
= CUPS_PRINTER_CLASS
;
5357 else if (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9)
5360 dtype
= CUPS_PRINTER_CLASS
;
5361 dmask
= CUPS_PRINTER_CLASS
;
5364 else if ((dest
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5370 send_ipp_status(con
, IPP_NOT_FOUND
,
5371 _("The printer or class was not found."));
5375 dmask
= CUPS_PRINTER_CLASS
;
5383 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
5385 send_http_error(con
, status
);
5389 else if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5391 send_http_error(con
, status
);
5396 * See if the "which-jobs" attribute have been specified...
5399 if ((attr
= ippFindAttribute(con
->request
, "which-jobs",
5400 IPP_TAG_KEYWORD
)) != NULL
&&
5401 !strcmp(attr
->values
[0].string
.text
, "completed"))
5406 else if (attr
&& !strcmp(attr
->values
[0].string
.text
, "all"))
5418 * See if they want to limit the number of jobs reported...
5421 if ((attr
= ippFindAttribute(con
->request
, "limit",
5422 IPP_TAG_INTEGER
)) != NULL
)
5423 limit
= attr
->values
[0].integer
;
5427 if ((attr
= ippFindAttribute(con
->request
, "first-job-id",
5428 IPP_TAG_INTEGER
)) != NULL
)
5429 first_job_id
= attr
->values
[0].integer
;
5434 * See if we only want to see jobs for a specific user...
5437 if ((attr
= ippFindAttribute(con
->request
, "my-jobs",
5438 IPP_TAG_BOOLEAN
)) != NULL
&&
5439 attr
->values
[0].boolean
)
5440 strlcpy(username
, get_username(con
), sizeof(username
));
5444 ra
= create_requested_array(con
->request
);
5447 * OK, build a list of jobs for this printer...
5450 for (count
= 0, job
= (cupsd_job_t
*)cupsArrayFirst(list
);
5451 count
< limit
&& job
;
5452 job
= (cupsd_job_t
*)cupsArrayNext(list
))
5455 * Filter out jobs that don't match...
5458 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
5460 if ((dest
&& strcmp(job
->dest
, dest
)) &&
5461 (!job
->printer
|| !dest
|| strcmp(job
->printer
->name
, dest
)))
5463 if ((job
->dtype
& dmask
) != dtype
&&
5464 (!job
->printer
|| (job
->printer
->type
& dmask
) != dtype
))
5466 if (username
[0] && strcasecmp(username
, job
->username
))
5469 if (completed
&& job
->state_value
<= IPP_JOB_STOPPED
)
5472 if (job
->id
< first_job_id
)
5481 ippAddSeparator(con
->response
);
5485 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_jobs: count = %d", count
);
5487 copy_job_attrs(con
, job
, ra
);
5490 cupsArrayDelete(ra
);
5492 con
->response
->request
.status
.status_code
= IPP_OK
;
5497 * 'get_notifications()' - Get events for a subscription.
5501 get_notifications(cupsd_client_t
*con
) /* I - Client connection */
5503 int i
, j
; /* Looping vars */
5504 http_status_t status
; /* Policy status */
5505 cupsd_subscription_t
*sub
; /* Subscription */
5506 ipp_attribute_t
*ids
, /* notify-subscription-ids */
5507 *sequences
; /* notify-sequence-numbers */
5508 int min_seq
; /* Minimum sequence number */
5509 int interval
; /* Poll interval */
5512 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_subscription_attrs(con=%p[%d])",
5516 * Get subscription attributes...
5519 ids
= ippFindAttribute(con
->request
, "notify-subscription-ids",
5521 sequences
= ippFindAttribute(con
->request
, "notify-sequence-numbers",
5526 send_ipp_status(con
, IPP_BAD_REQUEST
,
5527 _("Missing notify-subscription-ids attribute!"));
5532 * Are the subscription IDs valid?
5535 for (i
= 0, interval
= 60; i
< ids
->num_values
; i
++)
5537 if ((sub
= cupsdFindSubscription(ids
->values
[i
].integer
)) == NULL
)
5540 * Bad subscription ID...
5543 send_ipp_status(con
, IPP_NOT_FOUND
,
5544 _("notify-subscription-id %d no good!"),
5545 ids
->values
[i
].integer
);
5553 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
5555 con
, sub
->owner
)) != HTTP_OK
)
5557 send_http_error(con
, status
);
5562 * Check the subscription type and update the interval accordingly.
5565 if (sub
->job
&& sub
->job
->state_value
== IPP_JOB_PROCESSING
&&
5568 else if (sub
->job
&& sub
->job
->state_value
>= IPP_JOB_STOPPED
)
5570 else if (sub
->dest
&& sub
->dest
->state
== IPP_PRINTER_PROCESSING
&&
5576 * Tell the client to poll again in N seconds...
5580 ippAddInteger(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
5581 "notify-get-interval", interval
);
5583 ippAddInteger(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
5584 "printer-up-time", time(NULL
));
5587 * Copy the subscription event attributes to the response.
5590 con
->response
->request
.status
.status_code
=
5591 interval
? IPP_OK
: IPP_OK_EVENTS_COMPLETE
;
5593 for (i
= 0; i
< ids
->num_values
; i
++)
5596 * Get the subscription and sequence number...
5599 sub
= cupsdFindSubscription(ids
->values
[i
].integer
);
5601 if (sequences
&& i
< sequences
->num_values
)
5602 min_seq
= sequences
->values
[i
].integer
;
5607 * If we don't have any new events, nothing to do here...
5610 if (min_seq
> (sub
->first_event_id
+ sub
->num_events
))
5614 * Otherwise copy all of the new events...
5617 if (sub
->first_event_id
> min_seq
)
5620 j
= min_seq
- sub
->first_event_id
;
5622 for (; j
< sub
->num_events
; j
++)
5624 ippAddSeparator(con
->response
);
5626 copy_attrs(con
->response
, sub
->events
[j
]->attrs
, NULL
,
5627 IPP_TAG_EVENT_NOTIFICATION
, 0);
5634 * 'get_ppds()' - Get the list of PPD files on the local system.
5638 get_ppds(cupsd_client_t
*con
) /* I - Client connection */
5640 http_status_t status
; /* Policy status */
5641 ipp_attribute_t
*limit
, /* Limit attribute */
5642 *make
, /* ppd-make attribute */
5643 *requested
; /* requested-attributes attribute */
5644 char command
[1024], /* cups-deviced command */
5645 options
[1024], /* Options to pass to command */
5647 /* String for requested attributes */
5648 make_str
[256]; /* Escaped ppd-make string */
5651 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_ppds(%p[%d])", con
, con
->http
.fd
);
5657 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5659 send_http_error(con
, status
);
5664 * Run cups-driverd command with the given options...
5667 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
5668 make
= ippFindAttribute(con
->request
, "ppd-make", IPP_TAG_TEXT
);
5669 requested
= ippFindAttribute(con
->request
, "requested-attributes",
5673 url_encode_attr(requested
, requested_str
, sizeof(requested_str
));
5675 strlcpy(requested_str
, "requested-attributes=all", sizeof(requested_str
));
5678 url_encode_attr(make
, make_str
, sizeof(make_str
));
5682 snprintf(command
, sizeof(command
), "%s/daemon/cups-driverd", ServerBin
);
5683 snprintf(options
, sizeof(options
), "list+%d+%d+%s%s%s",
5684 con
->request
->request
.op
.request_id
,
5685 limit
? limit
->values
[0].integer
: 0,
5686 requested_str
, make
? "%20" : "", make_str
);
5688 if (cupsdSendCommand(con
, command
, options
, 0))
5691 * Command started successfully, don't send an IPP response here...
5694 ippDelete(con
->response
);
5695 con
->response
= NULL
;
5700 * Command failed, return "internal error" so the user knows something
5704 send_ipp_status(con
, IPP_INTERNAL_ERROR
,
5705 _("cups-driverd failed to execute."));
5711 * 'get_printer_attrs()' - Get printer attributes.
5715 get_printer_attrs(cupsd_client_t
*con
, /* I - Client connection */
5716 ipp_attribute_t
*uri
) /* I - Printer URI */
5718 http_status_t status
; /* Policy status */
5719 cups_ptype_t dtype
; /* Destination type (printer or class) */
5720 char method
[HTTP_MAX_URI
],
5721 /* Method portion of URI */
5722 username
[HTTP_MAX_URI
],
5723 /* Username portion of URI */
5725 /* Host portion of URI */
5726 resource
[HTTP_MAX_URI
];
5727 /* Resource portion of URI */
5728 int port
; /* Port portion of URI */
5729 cupsd_printer_t
*printer
; /* Printer/class */
5730 cups_array_t
*ra
; /* Requested attributes array */
5733 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_printer_attrs(%p[%d], %s)", con
,
5734 con
->http
.fd
, uri
->values
[0].string
.text
);
5737 * Is the destination valid?
5740 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
5741 sizeof(method
), username
, sizeof(username
), host
,
5742 sizeof(host
), &port
, resource
, sizeof(resource
));
5744 if (!cupsdValidateDest(host
, resource
, &dtype
, &printer
))
5750 send_ipp_status(con
, IPP_NOT_FOUND
,
5751 _("The printer or class was not found."));
5759 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
5761 send_http_error(con
, status
);
5766 * Send the attributes...
5769 ra
= create_requested_array(con
->request
);
5771 copy_printer_attrs(con
, printer
, ra
);
5773 cupsArrayDelete(ra
);
5775 con
->response
->request
.status
.status_code
= IPP_OK
;
5780 * 'get_printers()' - Get a list of printers or classes.
5784 get_printers(cupsd_client_t
*con
, /* I - Client connection */
5785 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
5787 http_status_t status
; /* Policy status */
5788 ipp_attribute_t
*attr
; /* Current attribute */
5789 int limit
; /* Maximum number of printers to return */
5790 int count
; /* Number of printers that match */
5791 cupsd_printer_t
*printer
; /* Current printer pointer */
5792 int printer_type
, /* printer-type attribute */
5793 printer_mask
; /* printer-type-mask attribute */
5794 char *location
; /* Location string */
5795 const char *username
; /* Current user */
5796 char *first_printer_name
; /* first-printer-name attribute */
5797 cups_array_t
*ra
; /* Requested attributes array */
5800 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "get_printers(%p[%d], %x)", con
,
5801 con
->http
.fd
, type
);
5807 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
5809 send_http_error(con
, status
);
5814 * Check for printers...
5817 if (!Printers
|| !cupsArrayCount(Printers
))
5819 send_ipp_status(con
, IPP_NOT_FOUND
, _("No destinations added."));
5824 * See if they want to limit the number of printers reported...
5827 if ((attr
= ippFindAttribute(con
->request
, "limit",
5828 IPP_TAG_INTEGER
)) != NULL
)
5829 limit
= attr
->values
[0].integer
;
5833 if ((attr
= ippFindAttribute(con
->request
, "first-printer-name",
5834 IPP_TAG_NAME
)) != NULL
)
5835 first_printer_name
= attr
->values
[0].string
.text
;
5837 first_printer_name
= NULL
;
5840 * Support filtering...
5843 if ((attr
= ippFindAttribute(con
->request
, "printer-type",
5844 IPP_TAG_ENUM
)) != NULL
)
5845 printer_type
= attr
->values
[0].integer
;
5849 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask",
5850 IPP_TAG_ENUM
)) != NULL
)
5851 printer_mask
= attr
->values
[0].integer
;
5855 if ((attr
= ippFindAttribute(con
->request
, "printer-location",
5856 IPP_TAG_TEXT
)) != NULL
)
5857 location
= attr
->values
[0].string
.text
;
5861 if (con
->username
[0])
5862 username
= con
->username
;
5863 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
5864 IPP_TAG_NAME
)) != NULL
)
5865 username
= attr
->values
[0].string
.text
;
5869 ra
= create_requested_array(con
->request
);
5872 * OK, build a list of printers for this printer...
5875 if (first_printer_name
)
5877 if ((printer
= cupsdFindDest(first_printer_name
)) == NULL
)
5878 printer
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
5881 printer
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
5884 count
< limit
&& printer
;
5885 printer
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
5887 if ((!type
|| (printer
->type
& CUPS_PRINTER_CLASS
) == type
) &&
5888 (printer
->type
& printer_mask
) == printer_type
&&
5889 (!location
|| !printer
->location
||
5890 !strcasecmp(printer
->location
, location
)))
5893 * If HideImplicitMembers is enabled, see if this printer or class
5894 * is a member of an implicit class...
5897 if (ImplicitClasses
&& HideImplicitMembers
&&
5898 printer
->in_implicit_class
)
5902 * If a username is specified, see if it is allowed or denied
5906 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
5910 * Add the group separator as needed...
5914 ippAddSeparator(con
->response
);
5919 * Send the attributes...
5922 copy_printer_attrs(con
, printer
, ra
);
5926 cupsArrayDelete(ra
);
5928 con
->response
->request
.status
.status_code
= IPP_OK
;
5933 * 'get_subscription_attrs()' - Get subscription attributes.
5937 get_subscription_attrs(
5938 cupsd_client_t
*con
, /* I - Client connection */
5939 int sub_id
) /* I - Subscription ID */
5941 http_status_t status
; /* Policy status */
5942 cupsd_subscription_t
*sub
; /* Subscription */
5943 cups_array_t
*ra
; /* Requested attributes array */
5946 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
5947 "get_subscription_attrs(con=%p[%d], sub_id=%d)",
5948 con
, con
->http
.fd
, sub_id
);
5951 * Is the subscription ID valid?
5954 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
5957 * Bad subscription ID...
5960 send_ipp_status(con
, IPP_NOT_FOUND
,
5961 _("notify-subscription-id %d no good!"), sub_id
);
5969 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
5971 con
, sub
->owner
)) != HTTP_OK
)
5973 send_http_error(con
, status
);
5978 * Copy the subscription attributes to the response using the
5979 * requested-attributes attribute that may be provided by the client.
5982 ra
= create_requested_array(con
->request
);
5984 copy_subscription_attrs(con
, sub
, ra
);
5986 cupsArrayDelete(ra
);
5988 con
->response
->request
.status
.status_code
= IPP_OK
;
5993 * 'get_subscriptions()' - Get subscriptions.
5997 get_subscriptions(cupsd_client_t
*con
, /* I - Client connection */
5998 ipp_attribute_t
*uri
) /* I - Printer/job URI */
6000 http_status_t status
; /* Policy status */
6001 int count
; /* Number of subscriptions */
6002 int limit
; /* Limit */
6003 cupsd_subscription_t
*sub
; /* Subscription */
6004 cups_array_t
*ra
; /* Requested attributes array */
6005 ipp_attribute_t
*attr
; /* Attribute */
6006 cups_ptype_t dtype
; /* Destination type (printer or class) */
6007 char method
[HTTP_MAX_URI
],
6008 /* Method portion of URI */
6009 username
[HTTP_MAX_URI
],
6010 /* Username portion of URI */
6012 /* Host portion of URI */
6013 resource
[HTTP_MAX_URI
];
6014 /* Resource portion of URI */
6015 int port
; /* Port portion of URI */
6016 cupsd_job_t
*job
; /* Job pointer */
6017 cupsd_printer_t
*printer
; /* Printer */
6020 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
6021 "get_subscriptions(con=%p[%d], uri=%s)",
6022 con
, con
->http
.fd
, uri
->values
[0].string
.text
);
6025 * Is the destination valid?
6028 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
6029 sizeof(method
), username
, sizeof(username
), host
,
6030 sizeof(host
), &port
, resource
, sizeof(resource
));
6032 if (!strcmp(resource
, "/") ||
6033 (!strncmp(resource
, "/jobs", 5) && strlen(resource
) <= 6) ||
6034 (!strncmp(resource
, "/printers", 9) && strlen(resource
) <= 10) ||
6035 (!strncmp(resource
, "/classes", 8) && strlen(resource
) <= 9))
6040 else if (!strncmp(resource
, "/jobs/", 6) && resource
[6])
6043 job
= cupsdFindJob(atoi(resource
+ 6));
6047 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%s does not exist!"),
6052 else if (!cupsdValidateDest(host
, resource
, &dtype
, &printer
))
6058 send_ipp_status(con
, IPP_NOT_FOUND
,
6059 _("The printer or class was not found."));
6062 else if ((attr
= ippFindAttribute(con
->request
, "notify-job-id",
6063 IPP_TAG_INTEGER
)) != NULL
)
6065 job
= cupsdFindJob(attr
->values
[0].integer
);
6069 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"),
6070 attr
->values
[0].integer
);
6081 if ((status
= cupsdCheckPolicy(printer
? printer
->op_policy_ptr
:
6083 con
, NULL
)) != HTTP_OK
)
6085 send_http_error(con
, status
);
6090 * Copy the subscription attributes to the response using the
6091 * requested-attributes attribute that may be provided by the client.
6094 ra
= create_requested_array(con
->request
);
6096 if ((attr
= ippFindAttribute(con
->request
, "limit",
6097 IPP_TAG_INTEGER
)) != NULL
)
6098 limit
= attr
->values
[0].integer
;
6103 * See if we only want to see subscriptions for a specific user...
6106 if ((attr
= ippFindAttribute(con
->request
, "my-subscriptions",
6107 IPP_TAG_BOOLEAN
)) != NULL
&&
6108 attr
->values
[0].boolean
)
6109 strlcpy(username
, get_username(con
), sizeof(username
));
6113 for (sub
= (cupsd_subscription_t
*)cupsArrayFirst(Subscriptions
), count
= 0;
6115 sub
= (cupsd_subscription_t
*)cupsArrayNext(Subscriptions
))
6116 if ((!printer
|| sub
->dest
== printer
) && (!job
|| sub
->job
== job
) &&
6117 (!username
[0] || !strcasecmp(username
, sub
->owner
)))
6119 ippAddSeparator(con
->response
);
6120 copy_subscription_attrs(con
, sub
, ra
);
6123 if (limit
&& count
>= limit
)
6127 cupsArrayDelete(ra
);
6130 con
->response
->request
.status
.status_code
= IPP_OK
;
6132 send_ipp_status(con
, IPP_NOT_FOUND
, _("No subscriptions found."));
6137 * 'get_username()' - Get the username associated with a request.
6140 static const char * /* O - Username */
6141 get_username(cupsd_client_t
*con
) /* I - Connection */
6143 ipp_attribute_t
*attr
; /* Attribute */
6146 if (con
->username
[0])
6147 return (con
->username
);
6148 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name",
6149 IPP_TAG_NAME
)) != NULL
)
6150 return (attr
->values
[0].string
.text
);
6152 return ("anonymous");
6157 * 'hold_job()' - Hold a print job.
6161 hold_job(cupsd_client_t
*con
, /* I - Client connection */
6162 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6164 ipp_attribute_t
*attr
, /* Current job-hold-until */
6165 *newattr
; /* New job-hold-until */
6166 int jobid
; /* Job ID */
6167 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6168 username
[HTTP_MAX_URI
], /* Username portion of URI */
6169 host
[HTTP_MAX_URI
], /* Host portion of URI */
6170 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6171 int port
; /* Port portion of URI */
6172 cupsd_job_t
*job
; /* Job information */
6175 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "hold_job(%p[%d], %s)", con
, con
->http
.fd
,
6176 uri
->values
[0].string
.text
);
6179 * See if we have a job URI or a printer URI...
6182 if (!strcmp(uri
->name
, "printer-uri"))
6185 * Got a printer URI; see if we also have a job-id attribute...
6188 if ((attr
= ippFindAttribute(con
->request
, "job-id",
6189 IPP_TAG_INTEGER
)) == NULL
)
6191 send_ipp_status(con
, IPP_BAD_REQUEST
,
6192 _("Got a printer-uri attribute but no job-id!"));
6196 jobid
= attr
->values
[0].integer
;
6201 * Got a job URI; parse it to get the job ID...
6204 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
6205 sizeof(method
), username
, sizeof(username
), host
,
6206 sizeof(host
), &port
, resource
, sizeof(resource
));
6208 if (strncmp(resource
, "/jobs/", 6))
6214 send_ipp_status(con
, IPP_BAD_REQUEST
,
6215 _("Bad job-uri attribute \"%s\"!"),
6216 uri
->values
[0].string
.text
);
6220 jobid
= atoi(resource
+ 6);
6224 * See if the job exists...
6227 if ((job
= cupsdFindJob(jobid
)) == NULL
)
6230 * Nope - return a "not found" error...
6233 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
6238 * See if the job is owned by the requesting user...
6241 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6243 send_http_error(con
, HTTP_UNAUTHORIZED
);
6248 * Hold the job and return...
6253 cupsdAddEvent(CUPSD_EVENT_JOB_STATE
, job
->printer
, job
,
6254 "Job held by user.");
6256 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until",
6257 IPP_TAG_KEYWORD
)) == NULL
)
6258 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
6260 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
6261 IPP_TAG_KEYWORD
)) == NULL
)
6262 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6267 * Free the old hold value and copy the new one over...
6270 _cupsStrFree(attr
->values
[0].string
.text
);
6274 attr
->value_tag
= newattr
->value_tag
;
6275 attr
->values
[0].string
.text
=
6276 _cupsStrAlloc(newattr
->values
[0].string
.text
);
6280 attr
->value_tag
= IPP_TAG_KEYWORD
;
6281 attr
->values
[0].string
.text
= _cupsStrAlloc("indefinite");
6285 * Hold job until specified time...
6288 cupsdSetJobHoldUntil(job
, attr
->values
[0].string
.text
);
6290 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, job
->printer
, job
,
6291 "Job job-hold-until value changed by user.");
6294 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d was held by \"%s\".", jobid
,
6297 con
->response
->request
.status
.status_code
= IPP_OK
;
6302 * 'move_job()' - Move a job to a new destination.
6306 move_job(cupsd_client_t
*con
, /* I - Client connection */
6307 ipp_attribute_t
*uri
) /* I - Job URI */
6309 http_status_t status
; /* Policy status */
6310 ipp_attribute_t
*attr
; /* Current attribute */
6311 int jobid
; /* Job ID */
6312 cupsd_job_t
*job
; /* Current job */
6313 const char *src
; /* Source printer/class */
6314 cups_ptype_t stype
, /* Source type (printer or class) */
6315 dtype
; /* Destination type (printer or class) */
6316 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6317 username
[HTTP_MAX_URI
], /* Username portion of URI */
6318 host
[HTTP_MAX_URI
], /* Host portion of URI */
6319 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6320 int port
; /* Port portion of URI */
6321 cupsd_printer_t
*sprinter
, /* Source printer */
6322 *dprinter
; /* Destination printer */
6325 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "move_job(%p[%d], %s)", con
, con
->http
.fd
,
6326 uri
->values
[0].string
.text
);
6329 * Get the new printer or class...
6332 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri",
6333 IPP_TAG_URI
)) == NULL
)
6336 * Need job-printer-uri...
6339 send_ipp_status(con
, IPP_BAD_REQUEST
,
6340 _("job-printer-uri attribute missing!"));
6344 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
, method
,
6345 sizeof(method
), username
, sizeof(username
), host
,
6346 sizeof(host
), &port
, resource
, sizeof(resource
));
6348 if (!cupsdValidateDest(host
, resource
, &dtype
, &dprinter
))
6354 send_ipp_status(con
, IPP_NOT_FOUND
,
6355 _("The printer or class was not found."));
6363 if ((status
= cupsdCheckPolicy(dprinter
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
6365 send_http_error(con
, status
);
6370 * See if we have a job URI or a printer URI...
6373 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
6374 sizeof(method
), username
, sizeof(username
), host
,
6375 sizeof(host
), &port
, resource
, sizeof(resource
));
6377 if (!strcmp(uri
->name
, "printer-uri"))
6380 * Got a printer URI; see if we also have a job-id attribute...
6383 if ((attr
= ippFindAttribute(con
->request
, "job-id",
6384 IPP_TAG_INTEGER
)) == NULL
)
6390 if ((src
= cupsdValidateDest(host
, resource
, &stype
, &sprinter
)) == NULL
)
6396 send_ipp_status(con
, IPP_NOT_FOUND
,
6397 _("The printer or class was not found."));
6406 * Otherwise, just move a single job...
6409 if ((job
= cupsdFindJob(attr
->values
[0].integer
)) == NULL
)
6412 * Nope - return a "not found" error...
6415 send_ipp_status(con
, IPP_NOT_FOUND
,
6416 _("Job #%d does not exist!"), attr
->values
[0].integer
);
6422 * Job found, initialize source pointers...
6433 * Got a job URI; parse it to get the job ID...
6436 if (strncmp(resource
, "/jobs/", 6))
6442 send_ipp_status(con
, IPP_BAD_REQUEST
,
6443 _("Bad job-uri attribute \"%s\"!"),
6444 uri
->values
[0].string
.text
);
6449 * See if the job exists...
6452 jobid
= atoi(resource
+ 6);
6454 if ((job
= cupsdFindJob(jobid
)) == NULL
)
6457 * Nope - return a "not found" error...
6460 send_ipp_status(con
, IPP_NOT_FOUND
,
6461 _("Job #%d does not exist!"), jobid
);
6467 * Job found, initialize source pointers...
6476 * Now move the job or jobs...
6482 * See if the job has been completed...
6485 if (job
->state_value
> IPP_JOB_STOPPED
)
6488 * Return a "not-possible" error...
6491 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
6492 _("Job #%d is finished and cannot be altered!"),
6498 * See if the job is owned by the requesting user...
6501 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6503 send_http_error(con
, HTTP_UNAUTHORIZED
);
6508 * Move the job to a different printer or class...
6511 cupsdMoveJob(job
, dprinter
);
6516 * Got the source printer, now look through the jobs...
6519 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
6521 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
6524 * See if the job is pointing at the source printer or has not been
6528 if (strcasecmp(job
->dest
, src
) ||
6529 job
->state_value
> IPP_JOB_STOPPED
)
6533 * See if the job can be moved by the requesting user...
6536 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6540 * Move the job to a different printer or class...
6543 cupsdMoveJob(job
, dprinter
);
6548 * Start jobs if possible...
6554 * Return with "everything is OK" status...
6557 con
->response
->request
.status
.status_code
= IPP_OK
;
6562 * 'ppd_parse_line()' - Parse a PPD default line.
6565 static int /* O - 0 on success, -1 on failure */
6566 ppd_parse_line(const char *line
, /* I - Line */
6567 char *option
, /* O - Option name */
6568 int olen
, /* I - Size of option name */
6569 char *choice
, /* O - Choice name */
6570 int clen
) /* I - Size of choice name */
6573 * Verify this is a default option line...
6576 if (strncmp(line
, "*Default", 8))
6580 * Read the option name...
6583 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
6593 * Skip everything else up to the colon (:)...
6596 while (*line
&& *line
!= ':')
6605 * Now grab the option choice, skipping leading whitespace...
6608 while (isspace(*line
& 255))
6611 for (clen
--; isalnum(*line
& 255); line
++)
6621 * Return with no errors...
6629 * 'print_job()' - Print a file to a printer or class.
6633 print_job(cupsd_client_t
*con
, /* I - Client connection */
6634 ipp_attribute_t
*uri
) /* I - Printer URI */
6636 ipp_attribute_t
*attr
; /* Current attribute */
6637 ipp_attribute_t
*format
; /* Document-format attribute */
6638 cupsd_job_t
*job
; /* New job */
6639 char filename
[1024]; /* Job filename */
6640 mime_type_t
*filetype
; /* Type of file */
6641 char super
[MIME_MAX_SUPER
], /* Supertype of file */
6642 type
[MIME_MAX_TYPE
], /* Subtype of file */
6643 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
6644 /* Textual name of mime type */
6645 cupsd_printer_t
*printer
; /* Printer data */
6646 struct stat fileinfo
; /* File information */
6647 int kbytes
; /* Size of file */
6648 int compression
; /* Document compression */
6651 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "print_job(%p[%d], %s)", con
, con
->http
.fd
,
6652 uri
->values
[0].string
.text
);
6655 * Validate print file attributes, for now just document-format and
6656 * compression (CUPS only supports "none" and "gzip")...
6659 compression
= CUPS_FILE_NONE
;
6661 if ((attr
= ippFindAttribute(con
->request
, "compression",
6662 IPP_TAG_KEYWORD
)) != NULL
)
6664 if (strcmp(attr
->values
[0].string
.text
, "none")
6666 && strcmp(attr
->values
[0].string
.text
, "gzip")
6667 #endif /* HAVE_LIBZ */
6670 send_ipp_status(con
, IPP_ATTRIBUTES
,
6671 _("Unsupported compression \"%s\"!"),
6672 attr
->values
[0].string
.text
);
6673 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
6674 "compression", NULL
, attr
->values
[0].string
.text
);
6679 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
6680 compression
= CUPS_FILE_GZIP
;
6681 #endif /* HAVE_LIBZ */
6685 * Do we have a file to print?
6690 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No file!?!"));
6695 * Is it a format we support?
6698 if ((format
= ippFindAttribute(con
->request
, "document-format",
6699 IPP_TAG_MIMETYPE
)) != NULL
)
6702 * Grab format from client...
6705 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
6707 send_ipp_status(con
, IPP_BAD_REQUEST
,
6708 _("Could not scan type \"%s\"!"),
6709 format
->values
[0].string
.text
);
6716 * No document format attribute? Auto-type it!
6719 strcpy(super
, "application");
6720 strcpy(type
, "octet-stream");
6723 if (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))
6726 * Auto-type the file...
6729 ipp_attribute_t
*doc_name
; /* document-name attribute */
6732 cupsdLogMessage(CUPSD_LOG_DEBUG
, "print_job: auto-typing file...");
6734 doc_name
= ippFindAttribute(con
->request
, "document-name", IPP_TAG_NAME
);
6735 filetype
= mimeFileType(MimeDatabase
, con
->filename
,
6736 doc_name
? doc_name
->values
[0].string
.text
: NULL
,
6742 * Replace the document-format attribute value with the auto-typed one.
6745 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
6750 _cupsStrFree(format
->values
[0].string
.text
);
6752 format
->values
[0].string
.text
= _cupsStrAlloc(mimetype
);
6755 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
6756 "document-format", NULL
, mimetype
);
6759 filetype
= mimeType(MimeDatabase
, super
, type
);
6762 filetype
= mimeType(MimeDatabase
, super
, type
);
6766 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
6767 _("Unsupported format \'%s/%s\'!"), super
, type
);
6768 cupsdLogMessage(CUPSD_LOG_INFO
,
6769 "Hint: Do you have the raw file printing rules enabled?");
6772 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
6773 "document-format", NULL
, format
->values
[0].string
.text
);
6778 cupsdLogMessage(CUPSD_LOG_DEBUG
, "print_job: request file type is %s/%s.",
6779 filetype
->super
, filetype
->type
);
6782 * Read any embedded job ticket info from PS files...
6785 if (!strcasecmp(filetype
->super
, "application") &&
6786 !strcasecmp(filetype
->type
, "postscript"))
6787 read_ps_job_ticket(con
);
6790 * Create the job object...
6793 if ((job
= add_job(con
, uri
, &printer
, filetype
)) == NULL
)
6797 * Update quota data...
6800 if (stat(con
->filename
, &fileinfo
))
6803 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6805 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
6807 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
6808 IPP_TAG_INTEGER
)) != NULL
)
6809 attr
->values
[0].integer
+= kbytes
;
6812 * Add the job file...
6815 if (add_file(con
, job
, filetype
, compression
))
6818 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6820 rename(con
->filename
, filename
);
6821 cupsdClearString(&con
->filename
);
6824 * See if we need to add the ending sheet...
6827 attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_NAME
);
6829 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6830 attr
&& attr
->num_values
> 1)
6836 cupsdLogMessage(CUPSD_LOG_INFO
, "Adding end banner page \"%s\" to job %d.",
6837 attr
->values
[1].string
.text
, job
->id
);
6839 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6841 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
6845 * Log and save the job...
6848 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d queued on \"%s\" by \"%s\".", job
->id
,
6849 job
->dest
, job
->username
);
6850 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Job %d hold_until = %d", job
->id
,
6851 (int)job
->hold_until
);
6856 * Start the job if possible...
6864 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
6866 * This function only gets called when printing a single PostScript
6867 * file using the Print-Job operation. It doesn't work for Create-Job +
6868 * Send-File, since the job attributes need to be set at job creation
6869 * time for banners to work. The embedded PS job ticket stuff is here
6870 * only to allow the Windows printer driver for CUPS to pass in JCL
6871 * options and IPP attributes which otherwise would be lost.
6873 * The format of a PS job ticket is simple:
6875 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
6877 * %cupsJobTicket: attr1=value1
6878 * %cupsJobTicket: attr2=value2
6880 * %cupsJobTicket: attrN=valueN
6882 * Job ticket lines must appear immediately after the first line that
6883 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
6884 * looking for job ticket info when it finds a line that does not begin
6885 * with "%cupsJobTicket:".
6887 * The maximum length of a job ticket line, including the prefix, is
6888 * 255 characters to conform with the Adobe DSC.
6890 * Read-only attributes are rejected with a notice to the error log in
6891 * case a malicious user tries anything. Since the job ticket is read
6892 * prior to attribute validation in print_job(), job ticket attributes
6893 * will go through the same validation as IPP attributes...
6897 read_ps_job_ticket(cupsd_client_t
*con
) /* I - Client connection */
6899 cups_file_t
*fp
; /* File to read from */
6900 char line
[256]; /* Line data */
6901 int num_options
; /* Number of options */
6902 cups_option_t
*options
; /* Options */
6903 ipp_t
*ticket
; /* New attributes */
6904 ipp_attribute_t
*attr
, /* Current attribute */
6905 *attr2
, /* Job attribute */
6906 *prev2
; /* Previous job attribute */
6910 * First open the print file...
6913 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
6915 cupsdLogMessage(CUPSD_LOG_ERROR
,
6916 "read_ps_job_ticket: Unable to open PostScript print file "
6923 * Skip the first line...
6926 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
6928 cupsdLogMessage(CUPSD_LOG_ERROR
,
6929 "read_ps_job_ticket: Unable to read from PostScript print "
6936 if (strncmp(line
, "%!PS-Adobe-", 11))
6939 * Not a DSC-compliant file, so no job ticket info will be available...
6947 * Read job ticket info from the file...
6953 while (cupsFileGets(fp
, line
, sizeof(line
)))
6956 * Stop at the first non-ticket line...
6959 if (strncmp(line
, "%cupsJobTicket:", 15))
6963 * Add the options to the option array...
6966 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
6970 * Done with the file; see if we have any options...
6975 if (num_options
== 0)
6979 * OK, convert the options to an attribute list, and apply them to
6984 cupsEncodeOptions(ticket
, num_options
, options
);
6987 * See what the user wants to change.
6990 for (attr
= ticket
->attrs
; attr
; attr
= attr
->next
)
6992 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6995 if (!strcmp(attr
->name
, "job-originating-host-name") ||
6996 !strcmp(attr
->name
, "job-originating-user-name") ||
6997 !strcmp(attr
->name
, "job-media-sheets-completed") ||
6998 !strcmp(attr
->name
, "job-k-octets") ||
6999 !strcmp(attr
->name
, "job-id") ||
7000 !strncmp(attr
->name
, "job-state", 9) ||
7001 !strncmp(attr
->name
, "time-at-", 8))
7002 continue; /* Read-only attrs */
7004 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
,
7005 IPP_TAG_ZERO
)) != NULL
)
7008 * Some other value; first free the old value...
7011 if (con
->request
->attrs
== attr2
)
7013 con
->request
->attrs
= attr2
->next
;
7018 for (prev2
= con
->request
->attrs
; prev2
; prev2
= prev2
->next
)
7019 if (prev2
->next
== attr2
)
7021 prev2
->next
= attr2
->next
;
7026 if (con
->request
->last
== attr2
)
7027 con
->request
->last
= prev2
;
7029 _ippFreeAttr(attr2
);
7033 * Add new option by copying it...
7036 copy_attribute(con
->request
, attr
, 0);
7040 * Then free the attribute list and option array...
7044 cupsFreeOptions(num_options
, options
);
7049 * 'reject_jobs()' - Reject print jobs to a printer.
7053 reject_jobs(cupsd_client_t
*con
, /* I - Client connection */
7054 ipp_attribute_t
*uri
) /* I - Printer or class URI */
7056 http_status_t status
; /* Policy status */
7057 cups_ptype_t dtype
; /* Destination type (printer or class) */
7058 char method
[HTTP_MAX_URI
], /* Method portion of URI */
7059 username
[HTTP_MAX_URI
], /* Username portion of URI */
7060 host
[HTTP_MAX_URI
], /* Host portion of URI */
7061 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
7062 int port
; /* Port portion of URI */
7063 const char *name
; /* Printer name */
7064 cupsd_printer_t
*printer
; /* Printer data */
7065 ipp_attribute_t
*attr
; /* printer-state-message text */
7068 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "reject_jobs(%p[%d], %s)", con
,
7069 con
->http
.fd
, uri
->values
[0].string
.text
);
7072 * Is the destination valid?
7075 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
7076 sizeof(method
), username
, sizeof(username
), host
,
7077 sizeof(host
), &port
, resource
, sizeof(resource
));
7079 if ((name
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7085 send_ipp_status(con
, IPP_NOT_FOUND
,
7086 _("The printer or class was not found."));
7094 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
7096 send_http_error(con
, status
);
7101 * Reject jobs sent to the printer...
7104 printer
->accepting
= 0;
7106 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
7107 IPP_TAG_TEXT
)) == NULL
)
7108 strcpy(printer
->state_message
, "Rejecting Jobs");
7110 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
7111 sizeof(printer
->state_message
));
7113 cupsdAddPrinterHistory(printer
);
7115 if (dtype
& CUPS_PRINTER_CLASS
)
7117 cupsdSaveAllClasses();
7119 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" rejecting jobs (\"%s\").",
7120 name
, get_username(con
));
7124 cupsdSaveAllPrinters();
7126 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" rejecting jobs (\"%s\").",
7127 name
, get_username(con
));
7131 * Everything was ok, so return OK status...
7134 con
->response
->request
.status
.status_code
= IPP_OK
;
7139 * 'release_job()' - Release a held print job.
7143 release_job(cupsd_client_t
*con
, /* I - Client connection */
7144 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
7146 ipp_attribute_t
*attr
; /* Current attribute */
7147 int jobid
; /* Job ID */
7148 char method
[HTTP_MAX_URI
], /* Method portion of URI */
7149 username
[HTTP_MAX_URI
], /* Username portion of URI */
7150 host
[HTTP_MAX_URI
], /* Host portion of URI */
7151 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
7152 int port
; /* Port portion of URI */
7153 cupsd_job_t
*job
; /* Job information */
7156 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "release_job(%p[%d], %s)", con
,
7157 con
->http
.fd
, uri
->values
[0].string
.text
);
7160 * See if we have a job URI or a printer URI...
7163 if (!strcmp(uri
->name
, "printer-uri"))
7166 * Got a printer URI; see if we also have a job-id attribute...
7169 if ((attr
= ippFindAttribute(con
->request
, "job-id",
7170 IPP_TAG_INTEGER
)) == NULL
)
7172 send_ipp_status(con
, IPP_BAD_REQUEST
,
7173 _("Got a printer-uri attribute but no job-id!"));
7177 jobid
= attr
->values
[0].integer
;
7182 * Got a job URI; parse it to get the job ID...
7185 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
7186 sizeof(method
), username
, sizeof(username
), host
,
7187 sizeof(host
), &port
, resource
, sizeof(resource
));
7189 if (strncmp(resource
, "/jobs/", 6))
7195 send_ipp_status(con
, IPP_BAD_REQUEST
,
7196 _("Bad job-uri attribute \"%s\"!"),
7197 uri
->values
[0].string
.text
);
7201 jobid
= atoi(resource
+ 6);
7205 * See if the job exists...
7208 if ((job
= cupsdFindJob(jobid
)) == NULL
)
7211 * Nope - return a "not found" error...
7214 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
7219 * See if job is "held"...
7222 if (job
->state_value
!= IPP_JOB_HELD
)
7225 * Nope - return a "not possible" error...
7228 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Job #%d is not held!"), jobid
);
7233 * See if the job is owned by the requesting user...
7236 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7238 send_http_error(con
, HTTP_UNAUTHORIZED
);
7243 * Reset the job-hold-until value to "no-hold"...
7246 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
7247 IPP_TAG_KEYWORD
)) == NULL
)
7248 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
7252 _cupsStrFree(attr
->values
[0].string
.text
);
7254 attr
->value_tag
= IPP_TAG_KEYWORD
;
7255 attr
->values
[0].string
.text
= _cupsStrAlloc("no-hold");
7257 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, job
->printer
, job
,
7258 "Job job-hold-until value changed by user.");
7262 * Release the job and return...
7265 cupsdReleaseJob(job
);
7267 cupsdAddEvent(CUPSD_EVENT_JOB_STATE
, job
->printer
, job
,
7268 "Job released by user.");
7270 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d was released by \"%s\".", jobid
,
7273 con
->response
->request
.status
.status_code
= IPP_OK
;
7278 * 'renew_subscription()' - Renew an existing subscription...
7283 cupsd_client_t
*con
, /* I - Client connection */
7284 int sub_id
) /* I - Subscription ID */
7286 http_status_t status
; /* Policy status */
7287 cupsd_subscription_t
*sub
; /* Subscription */
7288 ipp_attribute_t
*lease
; /* notify-lease-duration */
7291 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
7292 "renew_subscription(con=%p[%d], sub_id=%d)",
7293 con
, con
->http
.fd
, sub_id
);
7296 * Is the subscription ID valid?
7299 if ((sub
= cupsdFindSubscription(sub_id
)) == NULL
)
7302 * Bad subscription ID...
7305 send_ipp_status(con
, IPP_NOT_FOUND
,
7306 _("notify-subscription-id %d no good!"), sub_id
);
7313 * Job subscriptions cannot be renewed...
7316 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
7317 _("Job subscriptions cannot be renewed!"));
7325 if ((status
= cupsdCheckPolicy(sub
->dest
? sub
->dest
->op_policy_ptr
:
7327 con
, sub
->owner
)) != HTTP_OK
)
7329 send_http_error(con
, status
);
7334 * Renew the subscription...
7337 lease
= ippFindAttribute(con
->request
, "notify-lease-duration",
7340 sub
->lease
= lease
? lease
->values
[0].integer
: DefaultLeaseDuration
;
7342 if (MaxLeaseDuration
&& (sub
->lease
== 0 || sub
->lease
> MaxLeaseDuration
))
7344 cupsdLogMessage(CUPSD_LOG_INFO
,
7345 "renew_subscription: Limiting notify-lease-duration to "
7348 sub
->lease
= MaxLeaseDuration
;
7351 sub
->expire
= sub
->lease
? time(NULL
) + sub
->lease
: 0;
7353 cupsdSaveAllSubscriptions();
7355 con
->response
->request
.status
.status_code
= IPP_OK
;
7360 * 'restart_job()' - Restart an old print job.
7364 restart_job(cupsd_client_t
*con
, /* I - Client connection */
7365 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
7367 ipp_attribute_t
*attr
; /* Current attribute */
7368 int jobid
; /* Job ID */
7369 char method
[HTTP_MAX_URI
], /* Method portion of URI */
7370 username
[HTTP_MAX_URI
], /* Username portion of URI */
7371 host
[HTTP_MAX_URI
], /* Host portion of URI */
7372 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
7373 int port
; /* Port portion of URI */
7374 cupsd_job_t
*job
; /* Job information */
7377 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "restart_job(%p[%d], %s)", con
,
7378 con
->http
.fd
, uri
->values
[0].string
.text
);
7381 * See if we have a job URI or a printer URI...
7384 if (!strcmp(uri
->name
, "printer-uri"))
7387 * Got a printer URI; see if we also have a job-id attribute...
7390 if ((attr
= ippFindAttribute(con
->request
, "job-id",
7391 IPP_TAG_INTEGER
)) == NULL
)
7393 send_ipp_status(con
, IPP_BAD_REQUEST
,
7394 _("Got a printer-uri attribute but no job-id!"));
7398 jobid
= attr
->values
[0].integer
;
7403 * Got a job URI; parse it to get the job ID...
7406 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
7407 sizeof(method
), username
, sizeof(username
), host
,
7408 sizeof(host
), &port
, resource
, sizeof(resource
));
7410 if (strncmp(resource
, "/jobs/", 6))
7416 send_ipp_status(con
, IPP_BAD_REQUEST
,
7417 _("Bad job-uri attribute \"%s\"!"),
7418 uri
->values
[0].string
.text
);
7422 jobid
= atoi(resource
+ 6);
7426 * See if the job exists...
7429 if ((job
= cupsdFindJob(jobid
)) == NULL
)
7432 * Nope - return a "not found" error...
7435 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
7440 * See if job is in any of the "completed" states...
7443 if (job
->state_value
<= IPP_JOB_PROCESSING
)
7446 * Nope - return a "not possible" error...
7449 send_ipp_status(con
, IPP_NOT_POSSIBLE
, _("Job #%d is not complete!"),
7455 * See if we have retained the job files...
7460 if (!job
->attrs
|| job
->num_files
== 0)
7463 * Nope - return a "not possible" error...
7466 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
7467 _("Job #%d cannot be restarted - no files!"), jobid
);
7472 * See if the job is owned by the requesting user...
7475 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7477 send_http_error(con
, HTTP_UNAUTHORIZED
);
7482 * Restart the job and return...
7485 cupsdRestartJob(job
);
7487 cupsdLogMessage(CUPSD_LOG_INFO
, "Job %d was restarted by \"%s\".", jobid
,
7490 con
->response
->request
.status
.status_code
= IPP_OK
;
7495 * 'save_auth_info()' - Save authentication information for a job.
7499 save_auth_info(cupsd_client_t
*con
, /* I - Client connection */
7500 cupsd_job_t
*job
) /* I - Job */
7502 int i
; /* Looping var */
7503 char filename
[1024]; /* Job authentication filename */
7504 cups_file_t
*fp
; /* Job authentication file */
7505 char line
[1024]; /* Line for file */
7509 * This function saves the in-memory authentication information for
7510 * a job so that it can be used to authenticate with a remote host.
7511 * The information is stored in a file that is readable only by the
7512 * root user. The username and password are Base-64 encoded, each
7513 * on a separate line, followed by random number (up to 1024) of
7514 * newlines to limit the amount of information that is exposed.
7516 * Because of the potential for exposing of authentication information,
7517 * this functionality is only enabled when running cupsd as root.
7519 * This caching only works for the Basic and BasicDigest authentication
7520 * types. Digest authentication cannot be cached this way, and in
7521 * the future Kerberos authentication may make all of this obsolete.
7523 * Authentication information is saved whenever an authenticated
7524 * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
7527 * This information is deleted after a job is completed or canceled,
7528 * so reprints may require subsequent re-authentication.
7535 * Create the authentication file and change permissions...
7538 snprintf(filename
, sizeof(filename
), "%s/a%05d", RequestRoot
, job
->id
);
7539 if ((fp
= cupsFileOpen(filename
, "w")) == NULL
)
7541 cupsdLogMessage(CUPSD_LOG_ERROR
,
7542 "Unable to save authentication info to \"%s\" - %s",
7543 filename
, strerror(errno
));
7547 fchown(cupsFileNumber(fp
), 0, 0);
7548 fchmod(cupsFileNumber(fp
), 0400);
7551 * Write the authenticated username...
7554 httpEncode64_2(line
, sizeof(line
), con
->username
, strlen(con
->username
));
7555 cupsFilePrintf(fp
, "%s\n", line
);
7558 * Write the authenticated password...
7561 httpEncode64_2(line
, sizeof(line
), con
->password
, strlen(con
->password
));
7562 cupsFilePrintf(fp
, "%s\n", line
);
7565 * Write a random number of newlines to the end of the file...
7568 for (i
= (rand() % 1024); i
>= 0; i
--)
7569 cupsFilePutChar(fp
, '\n');
7572 * Close the file and return...
7580 * 'send_document()' - Send a file to a printer or class.
7584 send_document(cupsd_client_t
*con
, /* I - Client connection */
7585 ipp_attribute_t
*uri
) /* I - Printer URI */
7587 ipp_attribute_t
*attr
; /* Current attribute */
7588 ipp_attribute_t
*format
; /* Document-format attribute */
7589 int jobid
; /* Job ID number */
7590 cupsd_job_t
*job
; /* Current job */
7591 char job_uri
[HTTP_MAX_URI
],
7593 method
[HTTP_MAX_URI
],
7594 /* Method portion of URI */
7595 username
[HTTP_MAX_URI
],
7596 /* Username portion of URI */
7598 /* Host portion of URI */
7599 resource
[HTTP_MAX_URI
];
7600 /* Resource portion of URI */
7601 int port
; /* Port portion of URI */
7602 mime_type_t
*filetype
; /* Type of file */
7603 char super
[MIME_MAX_SUPER
],
7604 /* Supertype of file */
7605 type
[MIME_MAX_TYPE
],
7606 /* Subtype of file */
7607 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
7608 /* Textual name of mime type */
7609 char filename
[1024]; /* Job filename */
7610 cupsd_printer_t
*printer
; /* Current printer */
7611 struct stat fileinfo
; /* File information */
7612 int kbytes
; /* Size of file */
7613 int compression
; /* Type of compression */
7616 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_document(%p[%d], %s)", con
,
7617 con
->http
.fd
, uri
->values
[0].string
.text
);
7620 * See if we have a job URI or a printer URI...
7623 if (!strcmp(uri
->name
, "printer-uri"))
7626 * Got a printer URI; see if we also have a job-id attribute...
7629 if ((attr
= ippFindAttribute(con
->request
, "job-id",
7630 IPP_TAG_INTEGER
)) == NULL
)
7632 send_ipp_status(con
, IPP_BAD_REQUEST
,
7633 _("Got a printer-uri attribute but no job-id!"));
7637 jobid
= attr
->values
[0].integer
;
7642 * Got a job URI; parse it to get the job ID...
7645 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
7646 sizeof(method
), username
, sizeof(username
), host
,
7647 sizeof(host
), &port
, resource
, sizeof(resource
));
7649 if (strncmp(resource
, "/jobs/", 6))
7655 send_ipp_status(con
, IPP_BAD_REQUEST
,
7656 _("Bad job-uri attribute \"%s\"!"),
7657 uri
->values
[0].string
.text
);
7661 jobid
= atoi(resource
+ 6);
7665 * See if the job exists...
7668 if ((job
= cupsdFindJob(jobid
)) == NULL
)
7671 * Nope - return a "not found" error...
7674 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
7678 printer
= cupsdFindDest(job
->dest
);
7681 * See if the job is owned by the requesting user...
7684 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7686 send_http_error(con
, HTTP_UNAUTHORIZED
);
7691 * OK, see if the client is sending the document compressed - CUPS
7692 * only supports "none" and "gzip".
7695 compression
= CUPS_FILE_NONE
;
7697 if ((attr
= ippFindAttribute(con
->request
, "compression",
7698 IPP_TAG_KEYWORD
)) != NULL
)
7700 if (strcmp(attr
->values
[0].string
.text
, "none")
7702 && strcmp(attr
->values
[0].string
.text
, "gzip")
7703 #endif /* HAVE_LIBZ */
7706 send_ipp_status(con
, IPP_ATTRIBUTES
, _("Unsupported compression \"%s\"!"),
7707 attr
->values
[0].string
.text
);
7708 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7709 "compression", NULL
, attr
->values
[0].string
.text
);
7714 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
7715 compression
= CUPS_FILE_GZIP
;
7716 #endif /* HAVE_LIBZ */
7720 * Do we have a file to print?
7725 send_ipp_status(con
, IPP_BAD_REQUEST
, _("No file!?!"));
7730 * Is it a format we support?
7733 if ((format
= ippFindAttribute(con
->request
, "document-format",
7734 IPP_TAG_MIMETYPE
)) != NULL
)
7737 * Grab format from client...
7740 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7742 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad document-format \"%s\"!"),
7743 format
->values
[0].string
.text
);
7750 * No document format attribute? Auto-type it!
7753 strcpy(super
, "application");
7754 strcpy(type
, "octet-stream");
7757 if (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))
7760 * Auto-type the file...
7763 ipp_attribute_t
*doc_name
; /* document-name attribute */
7766 cupsdLogMessage(CUPSD_LOG_DEBUG
, "send_document: auto-typing file...");
7768 doc_name
= ippFindAttribute(con
->request
, "document-name", IPP_TAG_NAME
);
7769 filetype
= mimeFileType(MimeDatabase
, con
->filename
,
7770 doc_name
? doc_name
->values
[0].string
.text
: NULL
,
7776 * Replace the document-format attribute value with the auto-typed one.
7779 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
7784 _cupsStrFree(format
->values
[0].string
.text
);
7785 format
->values
[0].string
.text
= _cupsStrAlloc(mimetype
);
7788 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
7789 "document-format", NULL
, mimetype
);
7792 filetype
= mimeType(MimeDatabase
, super
, type
);
7795 filetype
= mimeType(MimeDatabase
, super
, type
);
7799 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
7800 _("Unsupported format \'%s/%s\'!"), super
, type
);
7801 cupsdLogMessage(CUPSD_LOG_INFO
,
7802 "Hint: Do you have the raw file printing rules enabled?");
7805 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7806 "document-format", NULL
, format
->values
[0].string
.text
);
7811 if (printer
->filetypes
&& !cupsArrayFind(printer
->filetypes
, filetype
))
7813 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
7816 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
7817 _("Unsupported format \'%s\'!"), mimetype
);
7819 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7820 "document-format", NULL
, mimetype
);
7825 cupsdLogMessage(CUPSD_LOG_DEBUG
,
7826 "send_document: request file type is %s/%s.",
7827 filetype
->super
, filetype
->type
);
7830 * Add the file to the job...
7835 if (add_file(con
, job
, filetype
, compression
))
7838 if (stat(con
->filename
, &fileinfo
))
7841 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
7843 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
7845 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets",
7846 IPP_TAG_INTEGER
)) != NULL
)
7847 attr
->values
[0].integer
+= kbytes
;
7849 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
7851 rename(con
->filename
, filename
);
7853 cupsdClearString(&con
->filename
);
7855 cupsdLogMessage(CUPSD_LOG_INFO
,
7856 "File of type %s/%s queued in job #%d by \"%s\".",
7857 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
7860 * Start the job if this is the last document...
7863 if ((attr
= ippFindAttribute(con
->request
, "last-document",
7864 IPP_TAG_BOOLEAN
)) != NULL
&&
7865 attr
->values
[0].boolean
)
7868 * See if we need to add the ending sheet...
7872 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
7873 (attr
= ippFindAttribute(job
->attrs
, "job-sheets",
7874 IPP_TAG_ZERO
)) != NULL
&&
7875 attr
->num_values
> 1)
7881 cupsdLogMessage(CUPSD_LOG_INFO
,
7882 "Adding end banner page \"%s\" to job %d.",
7883 attr
->values
[1].string
.text
, job
->id
);
7885 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
7887 cupsdUpdateQuota(printer
, job
->username
, 0, kbytes
);
7890 if (job
->state_value
== IPP_JOB_STOPPED
)
7892 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
7893 job
->state_value
= IPP_JOB_PENDING
;
7895 else if (job
->state_value
== IPP_JOB_HELD
)
7897 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
7898 IPP_TAG_KEYWORD
)) == NULL
)
7899 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
7901 if (!attr
|| !strcmp(attr
->values
[0].string
.text
, "no-hold"))
7903 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
7904 job
->state_value
= IPP_JOB_PENDING
;
7911 * Start the job if possible... Since cupsdCheckJobs() can cancel a
7912 * job if it doesn't print, we need to re-find the job afterwards...
7919 job
= cupsdFindJob(jobid
);
7923 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until",
7924 IPP_TAG_KEYWORD
)) == NULL
)
7925 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
7927 if (!attr
|| !strcmp(attr
->values
[0].string
.text
, "no-hold"))
7929 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
7930 job
->state_value
= IPP_JOB_HELD
;
7931 job
->hold_until
= time(NULL
) + 60;
7937 * Fill in the response info...
7940 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
7943 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
7946 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
7948 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
7949 job
? job
->state_value
: IPP_JOB_CANCELED
);
7950 add_job_state_reasons(con
, job
);
7952 con
->response
->request
.status
.status_code
= IPP_OK
;
7957 * 'send_http_error()' - Send a HTTP error back to the IPP client.
7961 send_http_error(cupsd_client_t
*con
, /* I - Client connection */
7962 http_status_t status
) /* I - HTTP status code */
7964 cupsdLogMessage(CUPSD_LOG_ERROR
, "%s: %s",
7965 ippOpString(con
->request
->request
.op
.operation_id
),
7966 httpStatus(status
));
7968 cupsdSendError(con
, status
);
7970 ippDelete(con
->response
);
7971 con
->response
= NULL
;
7978 * 'send_ipp_status()' - Send a status back to the IPP client.
7982 send_ipp_status(cupsd_client_t
*con
, /* I - Client connection */
7983 ipp_status_t status
, /* I - IPP status code */
7984 const char *message
, /* I - Status message */
7985 ...) /* I - Additional args as needed */
7987 va_list ap
; /* Pointer to additional args */
7988 char formatted
[1024]; /* Formatted errror message */
7993 va_start(ap
, message
);
7994 vsnprintf(formatted
, sizeof(formatted
),
7995 _cupsLangString(con
->language
, message
), ap
);
7998 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s %s: %s",
7999 ippOpString(con
->request
->request
.op
.operation_id
),
8000 ippErrorString(status
), formatted
);
8003 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%s %s",
8004 ippOpString(con
->request
->request
.op
.operation_id
),
8005 ippErrorString(status
));
8007 con
->response
->request
.status
.status_code
= status
;
8009 if (ippFindAttribute(con
->response
, "attributes-charset",
8010 IPP_TAG_ZERO
) == NULL
)
8011 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
8012 "attributes-charset", NULL
, DefaultCharset
);
8014 if (ippFindAttribute(con
->response
, "attributes-natural-language",
8015 IPP_TAG_ZERO
) == NULL
)
8016 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
8017 "attributes-natural-language", NULL
, DefaultLanguage
);
8020 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
8021 "status-message", NULL
, formatted
);
8026 * 'set_default()' - Set the default destination...
8030 set_default(cupsd_client_t
*con
, /* I - Client connection */
8031 ipp_attribute_t
*uri
) /* I - Printer URI */
8033 http_status_t status
; /* Policy status */
8034 cups_ptype_t dtype
; /* Destination type (printer or class) */
8035 char method
[HTTP_MAX_URI
],
8036 /* Method portion of URI */
8037 username
[HTTP_MAX_URI
],
8038 /* Username portion of URI */
8040 /* Host portion of URI */
8041 resource
[HTTP_MAX_URI
];
8042 /* Resource portion of URI */
8043 int port
; /* Port portion of URI */
8044 const char *name
; /* Printer name */
8045 cupsd_printer_t
*printer
; /* Printer */
8048 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_default(%p[%d], %s)", con
,
8049 con
->http
.fd
, uri
->values
[0].string
.text
);
8052 * Is the destination valid?
8055 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
8056 sizeof(method
), username
, sizeof(username
), host
,
8057 sizeof(host
), &port
, resource
, sizeof(resource
));
8059 if ((name
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
8065 send_ipp_status(con
, IPP_NOT_FOUND
,
8066 _("The printer or class was not found."));
8074 if ((status
= cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
)) != HTTP_OK
)
8076 send_http_error(con
, status
);
8081 * Set it as the default...
8084 DefaultPrinter
= printer
;
8086 cupsdSaveAllPrinters();
8087 cupsdSaveAllClasses();
8089 cupsdWritePrintcap();
8091 cupsdLogMessage(CUPSD_LOG_INFO
,
8092 "Default destination set to \"%s\" by \"%s\".", name
,
8096 * Everything was ok, so return OK status...
8099 con
->response
->request
.status
.status_code
= IPP_OK
;
8104 * 'set_job_attrs()' - Set job attributes.
8108 set_job_attrs(cupsd_client_t
*con
, /* I - Client connection */
8109 ipp_attribute_t
*uri
) /* I - Job URI */
8111 ipp_attribute_t
*attr
, /* Current attribute */
8112 *attr2
; /* Job attribute */
8113 int jobid
; /* Job ID */
8114 cupsd_job_t
*job
; /* Current job */
8115 char method
[HTTP_MAX_URI
],
8116 /* Method portion of URI */
8117 username
[HTTP_MAX_URI
],
8118 /* Username portion of URI */
8120 /* Host portion of URI */
8121 resource
[HTTP_MAX_URI
];
8122 /* Resource portion of URI */
8123 int port
; /* Port portion of URI */
8124 int event
; /* Events? */
8127 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_job_attrs(%p[%d], %s)", con
,
8128 con
->http
.fd
, uri
->values
[0].string
.text
);
8131 * Start with "everything is OK" status...
8134 con
->response
->request
.status
.status_code
= IPP_OK
;
8137 * See if we have a job URI or a printer URI...
8140 if (!strcmp(uri
->name
, "printer-uri"))
8143 * Got a printer URI; see if we also have a job-id attribute...
8146 if ((attr
= ippFindAttribute(con
->request
, "job-id",
8147 IPP_TAG_INTEGER
)) == NULL
)
8149 send_ipp_status(con
, IPP_BAD_REQUEST
,
8150 _("Got a printer-uri attribute but no job-id!"));
8154 jobid
= attr
->values
[0].integer
;
8159 * Got a job URI; parse it to get the job ID...
8162 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
8163 sizeof(method
), username
, sizeof(username
), host
,
8164 sizeof(host
), &port
, resource
, sizeof(resource
));
8166 if (strncmp(resource
, "/jobs/", 6))
8172 send_ipp_status(con
, IPP_BAD_REQUEST
,
8173 _("Bad job-uri attribute \"%s\"!"),
8174 uri
->values
[0].string
.text
);
8178 jobid
= atoi(resource
+ 6);
8182 * See if the job exists...
8185 if ((job
= cupsdFindJob(jobid
)) == NULL
)
8188 * Nope - return a "not found" error...
8191 send_ipp_status(con
, IPP_NOT_FOUND
, _("Job #%d does not exist!"), jobid
);
8196 * See if the job has been completed...
8199 if (job
->state_value
> IPP_JOB_STOPPED
)
8202 * Return a "not-possible" error...
8205 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8206 _("Job #%d is finished and cannot be altered!"), jobid
);
8211 * See if the job is owned by the requesting user...
8214 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
8216 send_http_error(con
, HTTP_UNAUTHORIZED
);
8221 * See what the user wants to change.
8228 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
8230 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
8233 if (!strcmp(attr
->name
, "attributes-charset") ||
8234 !strcmp(attr
->name
, "attributes-natural-language") ||
8235 !strcmp(attr
->name
, "document-compression") ||
8236 !strcmp(attr
->name
, "document-format") ||
8237 !strcmp(attr
->name
, "job-detailed-status-messages") ||
8238 !strcmp(attr
->name
, "job-document-access-errors") ||
8239 !strcmp(attr
->name
, "job-id") ||
8240 !strcmp(attr
->name
, "job-k-octets") ||
8241 !strcmp(attr
->name
, "job-originating-host-name") ||
8242 !strcmp(attr
->name
, "job-originating-user-name") ||
8243 !strcmp(attr
->name
, "job-printer-up-time") ||
8244 !strcmp(attr
->name
, "job-printer-uri") ||
8245 !strcmp(attr
->name
, "job-sheets") ||
8246 !strcmp(attr
->name
, "job-state-message") ||
8247 !strcmp(attr
->name
, "job-state-reasons") ||
8248 !strcmp(attr
->name
, "job-uri") ||
8249 !strcmp(attr
->name
, "number-of-documents") ||
8250 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
8251 !strcmp(attr
->name
, "output-device-assigned") ||
8252 !strncmp(attr
->name
, "date-time-at-", 13) ||
8253 !strncmp(attr
->name
, "job-impressions", 15) ||
8254 !strncmp(attr
->name
, "job-k-octets", 12) ||
8255 !strncmp(attr
->name
, "job-media-sheets", 16) ||
8256 !strncmp(attr
->name
, "time-at-", 8))
8262 send_ipp_status(con
, IPP_ATTRIBUTES_NOT_SETTABLE
,
8263 _("%s cannot be changed."), attr
->name
);
8265 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
8266 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
8271 if (!strcmp(attr
->name
, "job-priority"))
8274 * Change the job priority...
8277 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
8279 send_ipp_status(con
, IPP_REQUEST_VALUE
, _("Bad job-priority value!"));
8281 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
8282 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
8284 else if (job
->state_value
>= IPP_JOB_PROCESSING
)
8286 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8287 _("Job is completed and cannot be changed."));
8290 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
8292 cupsdSetJobPriority(job
, attr
->values
[0].integer
);
8293 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
;
8296 else if (!strcmp(attr
->name
, "job-state"))
8299 * Change the job state...
8302 if (attr
->value_tag
!= IPP_TAG_ENUM
)
8304 send_ipp_status(con
, IPP_REQUEST_VALUE
, _("Bad job-state value!"));
8306 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
8307 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
8311 switch (attr
->values
[0].integer
)
8313 case IPP_JOB_PENDING
:
8315 if (job
->state_value
> IPP_JOB_HELD
)
8317 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8318 _("Job state cannot be changed."));
8321 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
8323 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
8324 job
->state_value
= (ipp_jstate_t
)attr
->values
[0].integer
;
8326 event
|= CUPSD_EVENT_JOB_STATE
;
8330 case IPP_JOB_PROCESSING
:
8331 case IPP_JOB_STOPPED
:
8332 if (job
->state_value
!= attr
->values
[0].integer
)
8334 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8335 _("Job state cannot be changed."));
8340 case IPP_JOB_CANCELED
:
8341 case IPP_JOB_ABORTED
:
8342 case IPP_JOB_COMPLETED
:
8343 if (job
->state_value
> IPP_JOB_PROCESSING
)
8345 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8346 _("Job state cannot be changed."));
8349 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
8350 cupsdCancelJob(job
, 0, (ipp_jstate_t
)attr
->values
[0].integer
);
8355 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
8357 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
,
8358 IPP_TAG_ZERO
)) != NULL
)
8361 * Some other value; first free the old value...
8364 if (job
->attrs
->prev
)
8365 job
->attrs
->prev
->next
= attr2
->next
;
8367 job
->attrs
->attrs
= attr2
->next
;
8369 if (job
->attrs
->last
== attr2
)
8370 job
->attrs
->last
= job
->attrs
->prev
;
8372 _ippFreeAttr(attr2
);
8375 * Then copy the attribute...
8378 copy_attribute(job
->attrs
, attr
, 0);
8381 * See if the job-name or job-hold-until is being changed.
8384 if (!strcmp(attr
->name
, "job-hold-until"))
8386 cupsdSetJobHoldUntil(job
, attr
->values
[0].string
.text
);
8388 if (!strcmp(attr
->values
[0].string
.text
, "no-hold"))
8389 cupsdReleaseJob(job
);
8393 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
| CUPSD_EVENT_JOB_STATE
;
8396 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
8399 * Delete the attribute...
8402 if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
,
8403 IPP_TAG_ZERO
)) != NULL
)
8405 if (job
->attrs
->prev
)
8406 job
->attrs
->prev
->next
= attr2
->next
;
8408 job
->attrs
->attrs
= attr2
->next
;
8410 if (attr2
== job
->attrs
->last
)
8411 job
->attrs
->last
= job
->attrs
->prev
;
8413 _ippFreeAttr(attr2
);
8415 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
;
8421 * Add new option by copying it...
8424 copy_attribute(job
->attrs
, attr
, 0);
8426 event
|= CUPSD_EVENT_JOB_CONFIG_CHANGED
;
8437 * Send events as needed...
8440 if (event
& CUPSD_EVENT_JOB_STATE
)
8441 cupsdAddEvent(CUPSD_EVENT_JOB_STATE
, job
->printer
, job
,
8442 job
->state_value
== IPP_JOB_HELD
?
8443 "Job held by user." : "Job restarted by user.");
8445 if (event
& CUPSD_EVENT_JOB_CONFIG_CHANGED
)
8446 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED
, job
->printer
, job
,
8447 "Job options changed by user.");
8450 * Start jobs if possible...
8458 * 'set_printer_defaults()' - Set printer default options from a request.
8462 set_printer_defaults(
8463 cupsd_client_t
*con
, /* I - Client connection */
8464 cupsd_printer_t
*printer
) /* I - Printer */
8466 int i
; /* Looping var */
8467 ipp_attribute_t
*attr
; /* Current attribute */
8468 int namelen
; /* Length of attribute name */
8469 char name
[256], /* New attribute name */
8470 value
[256]; /* String version of integer attrs */
8473 for (attr
= con
->request
->attrs
; attr
; attr
= attr
->next
)
8476 * Skip non-printer attributes...
8479 if (attr
->group_tag
!= IPP_TAG_PRINTER
|| !attr
->name
)
8482 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "set_printer_defaults: %s", attr
->name
);
8484 if (!strcmp(attr
->name
, "job-sheets-default"))
8487 * Only allow keywords and names...
8490 if (attr
->value_tag
!= IPP_TAG_NAME
&& attr
->value_tag
!= IPP_TAG_KEYWORD
)
8494 * Only allow job-sheets-default to be set when running without a
8495 * system high classification level...
8501 cupsdSetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
8503 if (attr
->num_values
> 1)
8504 cupsdSetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
8506 cupsdSetString(&printer
->job_sheets
[1], "none");
8508 else if (!strcmp(attr
->name
, "requesting-user-name-allowed"))
8510 cupsdFreePrinterUsers(printer
);
8512 printer
->deny_users
= 0;
8514 if (attr
->value_tag
== IPP_TAG_NAME
&&
8515 (attr
->num_values
> 1 ||
8516 strcmp(attr
->values
[0].string
.text
, "all")))
8518 for (i
= 0; i
< attr
->num_values
; i
++)
8519 cupsdAddPrinterUser(printer
, attr
->values
[i
].string
.text
);
8522 else if (!strcmp(attr
->name
, "requesting-user-name-denied"))
8524 cupsdFreePrinterUsers(printer
);
8526 printer
->deny_users
= 1;
8528 if (attr
->value_tag
== IPP_TAG_NAME
&&
8529 (attr
->num_values
> 1 ||
8530 strcmp(attr
->values
[0].string
.text
, "none")))
8532 for (i
= 0; i
< attr
->num_values
; i
++)
8533 cupsdAddPrinterUser(printer
, attr
->values
[i
].string
.text
);
8536 else if (!strcmp(attr
->name
, "job-quota-period"))
8538 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
8541 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-quota-period to %d...",
8542 attr
->values
[0].integer
);
8543 cupsdFreeQuotas(printer
);
8545 printer
->quota_period
= attr
->values
[0].integer
;
8547 else if (!strcmp(attr
->name
, "job-k-limit"))
8549 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
8552 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-k-limit to %d...",
8553 attr
->values
[0].integer
);
8554 cupsdFreeQuotas(printer
);
8556 printer
->k_limit
= attr
->values
[0].integer
;
8558 else if (!strcmp(attr
->name
, "job-page-limit"))
8560 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
8563 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Setting job-page-limit to %d...",
8564 attr
->values
[0].integer
);
8565 cupsdFreeQuotas(printer
);
8567 printer
->page_limit
= attr
->values
[0].integer
;
8569 else if (!strcmp(attr
->name
, "printer-op-policy"))
8571 cupsd_policy_t
*p
; /* Policy */
8574 if (attr
->value_tag
!= IPP_TAG_NAME
)
8577 if ((p
= cupsdFindPolicy(attr
->values
[0].string
.text
)) != NULL
)
8579 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8580 "Setting printer-op-policy to \"%s\"...",
8581 attr
->values
[0].string
.text
);
8582 cupsdSetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
8583 printer
->op_policy_ptr
= p
;
8587 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8588 _("Unknown printer-op-policy \"%s\"."),
8589 attr
->values
[0].string
.text
);
8593 else if (!strcmp(attr
->name
, "printer-error-policy"))
8595 if (attr
->value_tag
!= IPP_TAG_NAME
&& attr
->value_tag
!= IPP_TAG_KEYWORD
)
8598 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
8599 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
8600 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
8602 send_ipp_status(con
, IPP_NOT_POSSIBLE
,
8603 _("Unknown printer-error-policy \"%s\"."),
8604 attr
->values
[0].string
.text
);
8608 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8609 "Setting printer-error-policy to \"%s\"...",
8610 attr
->values
[0].string
.text
);
8611 cupsdSetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
8613 else if (!strcmp(attr
->name
, "document-format-default") ||
8614 !strcmp(attr
->name
, "notify-lease-duration-default") ||
8615 !strcmp(attr
->name
, "notify-events-default"))
8619 * Skip any other non-default attributes...
8622 namelen
= strlen(attr
->name
);
8623 if (namelen
< 9 || strcmp(attr
->name
+ namelen
- 8, "-default") ||
8624 namelen
> (sizeof(name
) - 1) || attr
->num_values
!= 1)
8628 * OK, anything else must be a user-defined default...
8631 strlcpy(name
, attr
->name
, sizeof(name
));
8632 name
[namelen
- 8] = '\0'; /* Strip "-default" */
8634 switch (attr
->value_tag
)
8636 case IPP_TAG_DELETEATTR
:
8637 printer
->num_options
= cupsRemoveOption(name
,
8638 printer
->num_options
,
8639 &(printer
->options
));
8640 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8641 "Deleting %s", attr
->name
);
8645 case IPP_TAG_KEYWORD
:
8647 printer
->num_options
= cupsAddOption(name
,
8648 attr
->values
[0].string
.text
,
8649 printer
->num_options
,
8650 &(printer
->options
));
8651 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8652 "Setting %s to \"%s\"...", attr
->name
,
8653 attr
->values
[0].string
.text
);
8656 case IPP_TAG_BOOLEAN
:
8657 printer
->num_options
= cupsAddOption(name
,
8658 attr
->values
[0].boolean
?
8660 printer
->num_options
,
8661 &(printer
->options
));
8662 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8663 "Setting %s to %s...", attr
->name
,
8664 attr
->values
[0].boolean
? "true" : "false");
8667 case IPP_TAG_INTEGER
:
8669 sprintf(value
, "%d", attr
->values
[0].integer
);
8670 printer
->num_options
= cupsAddOption(name
, value
,
8671 printer
->num_options
,
8672 &(printer
->options
));
8673 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8674 "Setting %s to %s...", attr
->name
, value
);
8677 case IPP_TAG_RANGE
:
8678 sprintf(value
, "%d-%d", attr
->values
[0].range
.lower
,
8679 attr
->values
[0].range
.upper
);
8680 printer
->num_options
= cupsAddOption(name
, value
,
8681 printer
->num_options
,
8682 &(printer
->options
));
8683 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8684 "Setting %s to %s...", attr
->name
, value
);
8687 case IPP_TAG_RESOLUTION
:
8688 sprintf(value
, "%dx%d%s", attr
->values
[0].resolution
.xres
,
8689 attr
->values
[0].resolution
.yres
,
8690 attr
->values
[0].resolution
.units
== IPP_RES_PER_INCH
?
8692 printer
->num_options
= cupsAddOption(name
, value
,
8693 printer
->num_options
,
8694 &(printer
->options
));
8695 cupsdLogMessage(CUPSD_LOG_DEBUG
,
8696 "Setting %s to %s...", attr
->name
, value
);
8700 /* Do nothing for other values */
8708 * 'start_printer()' - Start a printer.
8712 start_printer(cupsd_client_t
*con
, /* I - Client connection */
8713 ipp_attribute_t
*uri
) /* I - Printer URI */
8715 http_status_t status
; /* Policy status */
8716 cups_ptype_t dtype
; /* Destination type (printer or class) */
8717 char method
[HTTP_MAX_URI
],
8718 /* Method portion of URI */
8719 username
[HTTP_MAX_URI
],
8720 /* Username portion of URI */
8722 /* Host portion of URI */
8723 resource
[HTTP_MAX_URI
];
8724 /* Resource portion of URI */
8725 int port
; /* Port portion of URI */
8726 const char *name
; /* Printer name */
8727 cupsd_printer_t
*printer
; /* Printer data */
8730 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "start_printer(%p[%d], %s)", con
,
8731 con
->http
.fd
, uri
->values
[0].string
.text
);
8734 * Is the destination valid?
8737 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
8738 sizeof(method
), username
, sizeof(username
), host
,
8739 sizeof(host
), &port
, resource
, sizeof(resource
));
8741 if ((name
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
8747 send_ipp_status(con
, IPP_NOT_FOUND
,
8748 _("The printer or class was not found."));
8756 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
8758 send_http_error(con
, status
);
8763 * Start the printer...
8766 printer
->state_message
[0] = '\0';
8768 cupsdStartPrinter(printer
, 1);
8770 if (dtype
& CUPS_PRINTER_CLASS
)
8771 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" started by \"%s\".", name
,
8774 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" started by \"%s\".", name
,
8780 * Everything was ok, so return OK status...
8783 con
->response
->request
.status
.status_code
= IPP_OK
;
8788 * 'stop_printer()' - Stop a printer.
8792 stop_printer(cupsd_client_t
*con
, /* I - Client connection */
8793 ipp_attribute_t
*uri
) /* I - Printer URI */
8795 http_status_t status
; /* Policy status */
8796 cups_ptype_t dtype
; /* Destination type (printer or class) */
8797 char method
[HTTP_MAX_URI
],
8798 /* Method portion of URI */
8799 username
[HTTP_MAX_URI
],
8800 /* Username portion of URI */
8802 /* Host portion of URI */
8803 resource
[HTTP_MAX_URI
];
8804 /* Resource portion of URI */
8805 int port
; /* Port portion of URI */
8806 const char *name
; /* Printer name */
8807 cupsd_printer_t
*printer
; /* Printer data */
8808 ipp_attribute_t
*attr
; /* printer-state-message attribute */
8811 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "stop_printer(%p[%d], %s)", con
,
8812 con
->http
.fd
, uri
->values
[0].string
.text
);
8815 * Is the destination valid?
8818 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
8819 sizeof(method
), username
, sizeof(username
), host
,
8820 sizeof(host
), &port
, resource
, sizeof(resource
));
8822 if ((name
= cupsdValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
8828 send_ipp_status(con
, IPP_NOT_FOUND
,
8829 _("The printer or class was not found."));
8837 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
8839 send_http_error(con
, status
);
8844 * Stop the printer...
8847 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
8848 IPP_TAG_TEXT
)) == NULL
)
8849 strcpy(printer
->state_message
, "Paused");
8852 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
8853 sizeof(printer
->state_message
));
8856 cupsdStopPrinter(printer
, 1);
8858 if (dtype
& CUPS_PRINTER_CLASS
)
8859 cupsdLogMessage(CUPSD_LOG_INFO
, "Class \"%s\" stopped by \"%s\".", name
,
8862 cupsdLogMessage(CUPSD_LOG_INFO
, "Printer \"%s\" stopped by \"%s\".", name
,
8866 * Everything was ok, so return OK status...
8869 con
->response
->request
.status
.status_code
= IPP_OK
;
8874 * 'url_encode_attr()' - URL-encode a string attribute.
8878 url_encode_attr(ipp_attribute_t
*attr
, /* I - Attribute */
8879 char *buffer
,/* I - String buffer */
8880 int bufsize
)/* I - Size of buffer */
8882 int i
; /* Looping var */
8883 char *bufptr
, /* Pointer into buffer */
8884 *bufend
, /* End of buffer */
8885 *valptr
; /* Pointer into value */
8888 strlcpy(buffer
, attr
->name
, bufsize
);
8889 bufptr
= buffer
+ strlen(buffer
);
8890 bufend
= buffer
+ bufsize
- 1;
8892 for (i
= 0; i
< attr
->num_values
; i
++)
8894 if (bufptr
>= bufend
)
8902 if (bufptr
>= bufend
)
8907 for (valptr
= attr
->values
[i
].string
.text
;
8908 *valptr
&& bufptr
< bufend
;
8912 if (bufptr
>= (bufend
- 2))
8919 else if (*valptr
== '\'' || *valptr
== '\\')
8922 *bufptr
++ = *valptr
;
8925 *bufptr
++ = *valptr
;
8927 if (bufptr
>= bufend
)
8938 * 'user_allowed()' - See if a user is allowed to print to a queue.
8941 static int /* O - 0 if not allowed, 1 if allowed */
8942 user_allowed(cupsd_printer_t
*p
, /* I - Printer or class */
8943 const char *username
) /* I - Username */
8945 int i
; /* Looping var */
8946 struct passwd
*pw
; /* User password data */
8949 if (p
->num_users
== 0)
8952 if (!strcmp(username
, "root"))
8955 pw
= getpwnam(username
);
8958 for (i
= 0; i
< p
->num_users
; i
++)
8960 if (p
->users
[i
][0] == '@')
8963 * Check group membership...
8966 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
8969 else if (!strcasecmp(username
, p
->users
[i
]))
8973 return ((i
< p
->num_users
) != p
->deny_users
);
8978 * 'validate_job()' - Validate printer options and destination.
8982 validate_job(cupsd_client_t
*con
, /* I - Client connection */
8983 ipp_attribute_t
*uri
) /* I - Printer URI */
8985 http_status_t status
; /* Policy status */
8986 ipp_attribute_t
*attr
; /* Current attribute */
8987 ipp_attribute_t
*format
; /* Document-format attribute */
8988 cups_ptype_t dtype
; /* Destination type (printer or class) */
8989 char method
[HTTP_MAX_URI
],
8990 /* Method portion of URI */
8991 username
[HTTP_MAX_URI
],
8992 /* Username portion of URI */
8994 /* Host portion of URI */
8995 resource
[HTTP_MAX_URI
];
8996 /* Resource portion of URI */
8997 int port
; /* Port portion of URI */
8998 char super
[MIME_MAX_SUPER
],
8999 /* Supertype of file */
9000 type
[MIME_MAX_TYPE
];
9001 /* Subtype of file */
9002 cupsd_printer_t
*printer
; /* Printer */
9005 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "validate_job(%p[%d], %s)", con
,
9006 con
->http
.fd
, uri
->values
[0].string
.text
);
9009 * OK, see if the client is sending the document compressed - CUPS
9010 * doesn't support compression yet...
9013 if ((attr
= ippFindAttribute(con
->request
, "compression",
9014 IPP_TAG_KEYWORD
)) != NULL
&&
9015 !strcmp(attr
->values
[0].string
.text
, "none"))
9017 send_ipp_status(con
, IPP_ATTRIBUTES
,
9018 _("Unsupported compression attribute %s!"),
9019 attr
->values
[0].string
.text
);
9020 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
9021 "compression", NULL
, attr
->values
[0].string
.text
);
9026 * Is it a format we support?
9029 if ((format
= ippFindAttribute(con
->request
, "document-format",
9030 IPP_TAG_MIMETYPE
)) != NULL
)
9032 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
9034 send_ipp_status(con
, IPP_BAD_REQUEST
, _("Bad document-format \"%s\"!"),
9035 format
->values
[0].string
.text
);
9039 if ((strcmp(super
, "application") || strcmp(type
, "octet-stream")) &&
9040 !mimeType(MimeDatabase
, super
, type
))
9042 cupsdLogMessage(CUPSD_LOG_INFO
,
9043 "Hint: Do you have the raw file printing rules enabled?");
9044 send_ipp_status(con
, IPP_DOCUMENT_FORMAT
,
9045 _("Unsupported format \"%s\"!"),
9046 format
->values
[0].string
.text
);
9047 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
9048 "document-format", NULL
, format
->values
[0].string
.text
);
9054 * Is the destination valid?
9057 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
->values
[0].string
.text
, method
,
9058 sizeof(method
), username
, sizeof(username
), host
,
9059 sizeof(host
), &port
, resource
, sizeof(resource
));
9061 if (cupsdValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
9067 send_ipp_status(con
, IPP_NOT_FOUND
,
9068 _("The printer or class was not found."));
9076 if ((status
= cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
)) != HTTP_OK
)
9078 send_http_error(con
, status
);
9083 * Everything was ok, so return OK status...
9086 con
->response
->request
.status
.status_code
= IPP_OK
;
9091 * 'validate_name()' - Make sure the printer name only contains valid chars.
9094 static int /* O - 0 if name is no good, 1 if name is good */
9095 validate_name(const char *name
) /* I - Name to check */
9097 const char *ptr
; /* Pointer into name */
9101 * Scan the whole name...
9104 for (ptr
= name
; *ptr
; ptr
++)
9105 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
9109 * All the characters are good; validate the length, too...
9112 return ((ptr
- name
) < 128);
9117 * 'validate_user()' - Validate the user for the request.
9120 static int /* O - 1 if permitted, 0 otherwise */
9121 validate_user(cupsd_job_t
*job
, /* I - Job */
9122 cupsd_client_t
*con
, /* I - Client connection */
9123 const char *owner
, /* I - Owner of job/resource */
9124 char *username
, /* O - Authenticated username */
9125 int userlen
) /* I - Length of username */
9127 cupsd_printer_t
*printer
; /* Printer for job */
9130 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
9131 "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, "
9133 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
9140 if (!con
|| !owner
|| !username
|| userlen
<= 0)
9144 * Get the best authenticated username that is available.
9147 strlcpy(username
, get_username(con
), userlen
);
9150 * Check the username against the owner...
9153 printer
= cupsdFindDest(job
->dest
);
9155 return (cupsdCheckPolicy(printer
? printer
->op_policy_ptr
: DefaultPolicyPtr
,
9156 con
, owner
) == HTTP_OK
);
9161 * End of "$Id: ipp.c 6032 2006-10-12 19:19:47Z mike $".