4 * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 1997-2005 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 * ProcessIPPRequest() - 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_state_reasons() - Add the "job-state-reasons" attribute based
31 * upon the job and printer state...
32 * add_job_subscriptions() - Add any subcriptions for a job.
33 * add_printer() - Add a printer to the system.
34 * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
35 * based upon the printer state...
36 * add_queued_job_count() - Add the "queued-job-count" attribute for
37 * authenticate_job() - Set job authentication info.
38 * cancel_all_jobs() - Cancel all print jobs.
39 * cancel_job() - Cancel a print job.
40 * cancel_subscription() - Cancel a subscription.
41 * check_quotas() - Check quotas for a printer and user.
42 * copy_attribute() - Copy a single attribute.
43 * copy_attrs() - Copy attributes from one request to another.
44 * copy_banner() - Copy a banner file to the requests directory
45 * for the specified job.
46 * copy_file() - Copy a PPD file or interface script...
47 * copy_model() - Copy a PPD model file, substituting default
49 * create_job() - Print a file to a printer or class.
50 * create_subscription() - Create a notification subscription.
51 * delete_printer() - Remove a printer or class from the system.
52 * get_default() - Get the default destination.
53 * get_devices() - Get the list of available devices on the
55 * get_jobs() - Get a list of jobs for the specified printer.
56 * get_job_attrs() - Get job attributes.
57 * get_notifications() - Get events for a subscription.
58 * get_ppds() - Get the list of PPD files on the local
60 * get_printer_attrs() - Get printer attributes.
61 * get_printers() - Get a list of printers.
62 * get_subscription_attrs() - Get subscription attributes.
63 * get_subscriptions() - Get subscriptions.
64 * hold_job() - Hold a print job.
65 * move_job() - Move a job to a new destination.
66 * ppd_add_default() - Add a PPD default choice.
67 * ppd_parse_line() - Parse a PPD default line.
68 * print_job() - Print a file to a printer or class.
69 * read_ps_line() - Read a line from a PS file...
70 * read_ps_job_ticket() - Reads a job ticket embedded in a PS file.
71 * reject_jobs() - Reject print jobs to a printer.
72 * release_job() - Release a held print job.
73 * restart_job() - Restart an old print job.
74 * save_auth_info() - Save authentication information for a job.
75 * send_document() - Send a file to a printer or class.
76 * send_ipp_error() - Send an error status back to the IPP client.
77 * set_default() - Set the default destination...
78 * set_job_attrs() - Set job attributes.
79 * start_printer() - Start a printer.
80 * stop_printer() - Stop a printer.
81 * user_allowed() - See if a user is allowed to print to a queue.
82 * validate_job() - Validate printer options and destination.
83 * validate_name() - Make sure the printer name only contains
85 * validate_user() - Validate the user for the request.
89 * Include necessary headers...
96 #endif /* HAVE_LIBPAPER */
100 * PPD default choice structure...
105 char option
[PPD_MAX_NAME
]; /* Main keyword (option name) */
106 char choice
[PPD_MAX_NAME
]; /* Option keyword (choice name) */
114 static void accept_jobs(client_t
*con
, ipp_attribute_t
*uri
);
115 static void add_class(client_t
*con
, ipp_attribute_t
*uri
);
116 static int add_file(client_t
*con
, job_t
*job
, mime_type_t
*filetype
,
118 static void add_job_state_reasons(client_t
*con
, job_t
*job
);
119 static void add_job_subscriptions(client_t
*con
, job_t
*job
);
120 static void add_printer(client_t
*con
, ipp_attribute_t
*uri
);
121 static void add_printer_state_reasons(client_t
*con
, printer_t
*p
);
122 static void add_queued_job_count(client_t
*con
, printer_t
*p
);
123 static void authenticate_job(client_t
*con
, ipp_attribute_t
*uri
);
124 static void cancel_all_jobs(client_t
*con
, ipp_attribute_t
*uri
);
125 static void cancel_job(client_t
*con
, ipp_attribute_t
*uri
);
126 static void cancel_subscription(client_t
*con
, int id
);
127 static int check_quotas(client_t
*con
, printer_t
*p
);
128 static ipp_attribute_t
*copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
130 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, ipp_attribute_t
*req
,
131 ipp_tag_t group
, int quickcopy
);
132 static int copy_banner(client_t
*con
, job_t
*job
, const char *name
);
133 static int copy_file(const char *from
, const char *to
);
134 static int copy_model(client_t
*con
, const char *from
, const char *to
);
135 static void create_job(client_t
*con
, ipp_attribute_t
*uri
);
136 static void create_subscription(client_t
*con
, ipp_attribute_t
*uri
);
137 static void delete_printer(client_t
*con
, ipp_attribute_t
*uri
);
138 static void get_default(client_t
*con
);
139 static void get_devices(client_t
*con
);
140 static void get_jobs(client_t
*con
, ipp_attribute_t
*uri
);
141 static void get_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
142 static void get_notifications(client_t
*con
, int id
);
143 static void get_ppds(client_t
*con
);
144 static void get_printers(client_t
*con
, int type
);
145 static void get_printer_attrs(client_t
*con
, ipp_attribute_t
*uri
);
146 static void get_subscription_attrs(client_t
*con
, int sub_id
);
147 static void get_subscriptions(client_t
*con
, ipp_attribute_t
*uri
);
148 static void hold_job(client_t
*con
, ipp_attribute_t
*uri
);
149 static void move_job(client_t
*con
, ipp_attribute_t
*uri
);
150 static int ppd_add_default(const char *option
, const char *choice
,
151 int num_defaults
, ppd_default_t
**defaults
);
152 static int ppd_parse_line(const char *line
, char *option
, int olen
,
153 char *choice
, int clen
);
154 static void print_job(client_t
*con
, ipp_attribute_t
*uri
);
155 static void read_ps_job_ticket(client_t
*con
);
156 static void reject_jobs(client_t
*con
, ipp_attribute_t
*uri
);
157 static void release_job(client_t
*con
, ipp_attribute_t
*uri
);
158 static void renew_subscription(client_t
*con
, int sub_id
);
159 static void restart_job(client_t
*con
, ipp_attribute_t
*uri
);
160 static void save_auth_info(client_t
*con
, int job_id
);
161 static void send_document(client_t
*con
, ipp_attribute_t
*uri
);
162 static void send_ipp_error(client_t
*con
, ipp_status_t status
);
163 static void set_default(client_t
*con
, ipp_attribute_t
*uri
);
164 static void set_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
165 static void start_printer(client_t
*con
, ipp_attribute_t
*uri
);
166 static void stop_printer(client_t
*con
, ipp_attribute_t
*uri
);
167 static int user_allowed(printer_t
*p
, const char *username
);
168 static void validate_job(client_t
*con
, ipp_attribute_t
*uri
);
169 static int validate_name(const char *name
);
170 static int validate_user(job_t
*job
, client_t
*con
,
171 const char *owner
, char *username
,
176 * 'ProcessIPPRequest()' - Process an incoming IPP request...
179 int /* O - 1 on success, 0 on failure */
180 ProcessIPPRequest(client_t
*con
) /* I - Client connection */
182 ipp_tag_t group
; /* Current group tag */
183 ipp_attribute_t
*attr
; /* Current attribute */
184 ipp_attribute_t
*charset
; /* Character set attribute */
185 ipp_attribute_t
*language
; /* Language attribute */
186 ipp_attribute_t
*uri
; /* Printer URI attribute */
187 ipp_attribute_t
*username
; /* requesting-user-name attr */
188 int sub_id
; /* Subscription ID */
191 LogMessage(L_DEBUG2
, "ProcessIPPRequest(%p[%d]): operation_id = %04x",
192 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
195 * First build an empty response message for this request...
198 con
->response
= ippNew();
200 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
201 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
202 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
205 * Then validate the request header and required attributes...
208 if (con
->request
->request
.any
.version
[0] != 1)
211 * Return an error, since we only support IPP 1.x.
214 LogMessage(L_ERROR
, "ProcessIPPRequest: bad request version (%d.%d)!",
215 con
->request
->request
.any
.version
[0],
216 con
->request
->request
.any
.version
[1]);
218 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
219 "%04X %s Bad request version (%d.%d)",
220 IPP_VERSION_NOT_SUPPORTED
, con
->http
.hostname
,
221 con
->request
->request
.any
.version
[0],
222 con
->request
->request
.any
.version
[1]);
224 send_ipp_error(con
, IPP_VERSION_NOT_SUPPORTED
);
226 else if (con
->request
->attrs
== NULL
)
228 LogMessage(L_ERROR
, "ProcessIPPRequest: no attributes in request!");
230 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
231 "%04X %s No attributes in request",
232 IPP_BAD_REQUEST
, con
->http
.hostname
);
234 send_ipp_error(con
, IPP_BAD_REQUEST
);
239 * Make sure that the attributes are provided in the correct order and
240 * don't repeat groups...
243 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
246 if (attr
->group_tag
< group
)
249 * Out of order; return an error...
252 LogMessage(L_ERROR
, "ProcessIPPRequest: attribute groups are out of order!");
254 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
255 "%04X %s Attribute groups are out of order",
256 IPP_BAD_REQUEST
, con
->http
.hostname
);
258 send_ipp_error(con
, IPP_BAD_REQUEST
);
262 group
= attr
->group_tag
;
267 * Then make sure that the first three attributes are:
270 * attributes-natural-language
271 * printer-uri/job-uri
274 attr
= con
->request
->attrs
;
275 if (attr
&& !strcmp(attr
->name
, "attributes-charset") &&
276 attr
->value_tag
== IPP_TAG_CHARSET
)
284 if (attr
&& !strcmp(attr
->name
, "attributes-natural-language") &&
285 attr
->value_tag
== IPP_TAG_LANGUAGE
)
290 if ((attr
= ippFindAttribute(con
->request
, "printer-uri", IPP_TAG_URI
)) != NULL
)
292 else if ((attr
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
)) != NULL
)
298 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
299 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
301 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
302 "attributes-charset", NULL
, DefaultCharset
);
305 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
306 "attributes-natural-language", NULL
,
307 language
->values
[0].string
.text
);
309 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
310 "attributes-natural-language", NULL
, DefaultLanguage
);
312 if (charset
== NULL
|| language
== NULL
||
314 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
315 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
316 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
317 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
318 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
321 * Return an error, since attributes-charset,
322 * attributes-natural-language, and printer-uri/job-uri are required
323 * for all operations.
328 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-charset attribute!");
330 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
331 "%04X %s Missing attributes-charset attribute",
332 IPP_BAD_REQUEST
, con
->http
.hostname
);
337 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-natural-language attribute!");
339 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
340 "%04X %s Missing attributes-natural-language attribute",
341 IPP_BAD_REQUEST
, con
->http
.hostname
);
346 LogMessage(L_ERROR
, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
348 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
349 "%04X %s Missing printer-uri or job-uri attribute",
350 IPP_BAD_REQUEST
, con
->http
.hostname
);
353 LogMessage(L_DEBUG
, "Request attributes follow...");
355 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
356 LogMessage(L_DEBUG
, "attr \"%s\": group_tag = %x, value_tag = %x",
357 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
360 LogMessage(L_DEBUG
, "End of attributes...");
362 send_ipp_error(con
, IPP_BAD_REQUEST
);
367 * OK, all the checks pass so far; make sure requesting-user-name is
368 * not "root" from a remote host...
371 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name",
372 IPP_TAG_NAME
)) != NULL
)
375 * Check for root user...
378 if (strcmp(username
->values
[0].string
.text
, "root") == 0 &&
379 strcasecmp(con
->http
.hostname
, "localhost") != 0 &&
380 strcmp(con
->username
, "root") != 0)
383 * Remote unauthenticated user masquerading as local root...
386 SetString(&(username
->values
[0].string
.text
), RemoteRoot
);
390 if ((attr
= ippFindAttribute(con
->request
, "notify-subscription-id",
391 IPP_TAG_INTEGER
)) != NULL
)
392 sub_id
= attr
->values
[0].integer
;
397 * Then try processing the operation...
401 LogMessage(L_DEBUG2
, "ProcessIPPRequest: URI=\"%s\"",
402 uri
->values
[0].string
.text
);
404 switch (con
->request
->request
.op
.operation_id
)
410 case IPP_VALIDATE_JOB
:
411 validate_job(con
, uri
);
414 case IPP_CREATE_JOB
:
415 create_job(con
, uri
);
418 case IPP_SEND_DOCUMENT
:
419 send_document(con
, uri
);
422 case IPP_CANCEL_JOB
:
423 cancel_job(con
, uri
);
426 case IPP_GET_JOB_ATTRIBUTES
:
427 get_job_attrs(con
, uri
);
434 case IPP_GET_PRINTER_ATTRIBUTES
:
435 get_printer_attrs(con
, uri
);
442 case IPP_RELEASE_JOB
:
443 release_job(con
, uri
);
446 case IPP_RESTART_JOB
:
447 restart_job(con
, uri
);
450 case IPP_PAUSE_PRINTER
:
451 stop_printer(con
, uri
);
454 case IPP_RESUME_PRINTER
:
455 start_printer(con
, uri
);
458 case IPP_PURGE_JOBS
:
459 cancel_all_jobs(con
, uri
);
462 case IPP_SET_JOB_ATTRIBUTES
:
463 set_job_attrs(con
, uri
);
466 case CUPS_GET_DEFAULT
:
470 case CUPS_GET_PRINTERS
:
471 get_printers(con
, 0);
474 case CUPS_GET_CLASSES
:
475 get_printers(con
, CUPS_PRINTER_CLASS
);
478 case CUPS_ADD_PRINTER
:
479 add_printer(con
, uri
);
482 case CUPS_DELETE_PRINTER
:
483 delete_printer(con
, uri
);
486 case CUPS_ADD_CLASS
:
490 case CUPS_DELETE_CLASS
:
491 delete_printer(con
, uri
);
494 case CUPS_ACCEPT_JOBS
:
495 case IPP_ENABLE_PRINTER
:
496 accept_jobs(con
, uri
);
499 case CUPS_REJECT_JOBS
:
500 case IPP_DISABLE_PRINTER
:
501 reject_jobs(con
, uri
);
504 case CUPS_SET_DEFAULT
:
505 set_default(con
, uri
);
508 case CUPS_GET_DEVICES
:
520 case CUPS_AUTHENTICATE_JOB
:
521 authenticate_job(con
, uri
);
524 case IPP_CREATE_PRINTER_SUBSCRIPTION
:
525 case IPP_CREATE_JOB_SUBSCRIPTION
:
526 create_subscription(con
, uri
);
529 case IPP_GET_SUBSCRIPTION_ATTRIBUTES
:
530 get_subscription_attrs(con
, sub_id
);
533 case IPP_GET_SUBSCRIPTIONS
:
534 get_subscriptions(con
, uri
);
537 case IPP_RENEW_SUBSCRIPTION
:
538 renew_subscription(con
, sub_id
);
541 case IPP_CANCEL_SUBSCRIPTION
:
542 cancel_subscription(con
, sub_id
);
545 case IPP_GET_NOTIFICATIONS
:
546 get_notifications(con
, sub_id
);
550 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
551 "%04X %s Operation %04X (%s) not supported",
552 IPP_OPERATION_NOT_SUPPORTED
, con
->http
.hostname
,
553 con
->request
->request
.op
.operation_id
,
554 ippOpString(con
->request
->request
.op
.operation_id
));
556 send_ipp_error(con
, IPP_OPERATION_NOT_SUPPORTED
);
566 * Sending data from the scheduler...
569 LogMessage(L_DEBUG
, "ProcessIPPRequest: %d status_code=%x (%s)",
570 con
->http
.fd
, con
->response
->request
.status
.status_code
,
571 ippErrorString(con
->response
->request
.status
.status_code
));
573 if (SendHeader(con
, HTTP_OK
, "application/ipp"))
575 if (con
->http
.version
== HTTP_1_1
)
577 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
579 httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n");
583 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
584 con
->http
.data_remaining
= ippLength(con
->response
);
586 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
587 con
->http
.data_remaining
);
590 LogMessage(L_DEBUG2
, "ProcessIPPRequest: Adding fd %d to OutputSet...",
593 FD_SET(con
->http
.fd
, OutputSet
);
596 * Tell the caller the response header was sent successfully...
604 * Tell the caller the response header could not be sent...
613 * Sending data from a subprocess like cups-deviced; tell the caller
614 * everything is A-OK so far...
623 * 'accept_jobs()' - Accept print jobs to a printer.
627 accept_jobs(client_t
*con
, /* I - Client connection */
628 ipp_attribute_t
*uri
) /* I - Printer or class URI */
630 cups_ptype_t dtype
; /* Destination type (printer or class) */
631 char method
[HTTP_MAX_URI
], /* Method portion of URI */
632 username
[HTTP_MAX_URI
], /* Username portion of URI */
633 host
[HTTP_MAX_URI
], /* Host portion of URI */
634 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
635 int port
; /* Port portion of URI */
636 const char *name
; /* Printer name */
637 printer_t
*printer
; /* Printer data */
640 LogMessage(L_DEBUG2
, "accept_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
641 uri
->values
[0].string
.text
);
644 * Was this operation called from the correct URI?
647 if (strncmp(con
->uri
, "/admin/", 7) != 0)
649 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
651 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
656 * Is the destination valid?
659 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
661 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
667 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
668 send_ipp_error(con
, IPP_NOT_FOUND
);
676 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
678 LogMessage(L_ERROR
, "accept_jobs: not authorized!");
679 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
684 * Accept jobs sent to the printer...
687 printer
->accepting
= 1;
688 printer
->state_message
[0] = '\0';
690 AddPrinterHistory(printer
);
692 if (dtype
& CUPS_PRINTER_CLASS
)
697 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
701 * Everything was ok, so return OK status...
704 con
->response
->request
.status
.status_code
= IPP_OK
;
709 * 'add_class()' - Add a class to the system.
713 add_class(client_t
*con
, /* I - Client connection */
714 ipp_attribute_t
*uri
) /* I - URI of class */
716 int i
; /* Looping var */
717 char method
[HTTP_MAX_URI
], /* Method portion of URI */
718 username
[HTTP_MAX_URI
], /* Username portion of URI */
719 host
[HTTP_MAX_URI
], /* Host portion of URI */
720 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
721 int port
; /* Port portion of URI */
722 printer_t
*pclass
, /* Class */
723 *member
; /* Member printer/class */
724 cups_ptype_t dtype
; /* Destination type */
725 const char *dest
; /* Printer or class name */
726 ipp_attribute_t
*attr
; /* Printer attribute */
727 int modify
; /* Non-zero if we just modified */
730 LogMessage(L_DEBUG2
, "add_class(%p[%d], %s)\n", con
, con
->http
.fd
,
731 uri
->values
[0].string
.text
);
734 * Was this operation called from the correct URI?
737 if (strncmp(con
->uri
, "/admin/", 7) != 0)
739 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
741 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
746 * Do we have a valid URI?
749 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
751 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
754 * No, return an error...
757 send_ipp_error(con
, IPP_BAD_REQUEST
);
762 * Do we have a valid printer name?
765 if (!validate_name(resource
+ 9))
768 * No, return an error...
771 send_ipp_error(con
, IPP_BAD_REQUEST
);
779 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
781 LogMessage(L_ERROR
, "add_class: not authorized!");
782 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
787 * See if the class already exists; if not, create a new class...
790 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
793 * Class doesn't exist; see if we have a printer of the same name...
796 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
797 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
800 * Yes, return an error...
803 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
808 * No, add the pclass...
811 pclass
= AddClass(resource
+ 9);
814 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
817 * Rename the implicit class to "AnyClass" or remove it...
820 if (ImplicitAnyClasses
)
822 cupsArrayRemove(Printers
, pclass
);
823 SetStringf(&pclass
->name
, "Any%s", resource
+ 9);
824 cupsArrayAdd(Printers
, pclass
);
827 DeletePrinter(pclass
, 1);
830 * Add the class as a new local class...
833 pclass
= AddClass(resource
+ 9);
836 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
839 * Rename the remote class to "Class"...
842 DeletePrinterFilters(pclass
);
843 cupsArrayRemove(Printers
, pclass
);
844 SetStringf(&pclass
->name
, "%s@%s", resource
+ 9, pclass
->hostname
);
845 SetPrinterAttrs(pclass
);
846 cupsArrayAdd(Printers
, pclass
);
849 * Add the class as a new local class...
852 pclass
= AddClass(resource
+ 9);
859 * Look for attributes and copy them over as needed...
862 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
863 SetString(&pclass
->location
, attr
->values
[0].string
.text
);
865 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
866 SetString(&pclass
->info
, attr
->values
[0].string
.text
);
868 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
870 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
871 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
873 pclass
->accepting
= attr
->values
[0].boolean
;
874 AddPrinterHistory(pclass
);
877 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared", IPP_TAG_BOOLEAN
)) != NULL
)
879 LogMessage(L_INFO
, "Setting %s printer-is-shared to %d (was %d.)",
880 pclass
->name
, attr
->values
[0].boolean
, pclass
->shared
);
882 pclass
->shared
= attr
->values
[0].boolean
;
885 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
887 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
888 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
890 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
891 pclass
->name
, attr
->values
[0].integer
);
892 send_ipp_error(con
, IPP_BAD_REQUEST
);
896 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
897 attr
->values
[0].integer
, pclass
->state
);
899 SetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
901 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
903 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
904 sizeof(pclass
->state_message
));
905 AddPrinterHistory(pclass
);
907 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
910 SetString(&pclass
->job_sheets
[0], attr
->values
[0].string
.text
);
911 if (attr
->num_values
> 1)
912 SetString(&pclass
->job_sheets
[1], attr
->values
[1].string
.text
);
914 SetString(&pclass
->job_sheets
[1], "none");
916 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
917 IPP_TAG_ZERO
)) != NULL
)
919 FreePrinterUsers(pclass
);
921 pclass
->deny_users
= 0;
922 if (attr
->value_tag
== IPP_TAG_NAME
&&
923 (attr
->num_values
> 1 ||
924 strcmp(attr
->values
[0].string
.text
, "all") != 0))
925 for (i
= 0; i
< attr
->num_values
; i
++)
926 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
928 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
929 IPP_TAG_ZERO
)) != NULL
)
931 FreePrinterUsers(pclass
);
933 pclass
->deny_users
= 1;
934 if (attr
->value_tag
== IPP_TAG_NAME
&&
935 (attr
->num_values
> 1 ||
936 strcmp(attr
->values
[0].string
.text
, "none") != 0))
937 for (i
= 0; i
< attr
->num_values
; i
++)
938 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
940 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
941 IPP_TAG_INTEGER
)) != NULL
)
943 LogMessage(L_DEBUG
, "add_class: Setting job-quota-period to %d...",
944 attr
->values
[0].integer
);
946 pclass
->quota_period
= attr
->values
[0].integer
;
948 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
949 IPP_TAG_INTEGER
)) != NULL
)
951 LogMessage(L_DEBUG
, "add_class: Setting job-k-limit to %d...",
952 attr
->values
[0].integer
);
954 pclass
->k_limit
= attr
->values
[0].integer
;
956 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
957 IPP_TAG_INTEGER
)) != NULL
)
959 LogMessage(L_DEBUG
, "add_class: Setting job-page-limit to %d...",
960 attr
->values
[0].integer
);
962 pclass
->page_limit
= attr
->values
[0].integer
;
964 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
966 cupsd_policy_t
*p
; /* Policy */
969 if ((p
= cupsdFindPolicy(attr
->values
[0].string
.text
)) != NULL
)
971 LogMessage(L_DEBUG
, "add_class: Setting printer-op-policy to \"%s\"...",
972 attr
->values
[0].string
.text
);
973 SetString(&pclass
->op_policy
, attr
->values
[0].string
.text
);
974 pclass
->op_policy_ptr
= p
;
978 LogMessage(L_ERROR
, "add_class: Unknown printer-op-policy \"%s\"...",
979 attr
->values
[0].string
.text
);
980 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
984 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
986 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
987 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
988 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
990 LogMessage(L_ERROR
, "add_class: Unknown printer-error-policy \"%s\"...",
991 attr
->values
[0].string
.text
);
992 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
996 LogMessage(L_DEBUG
, "add_class: Setting printer-error-policy to \"%s\"...",
997 attr
->values
[0].string
.text
);
998 SetString(&pclass
->error_policy
, attr
->values
[0].string
.text
);
1000 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
1003 * Clear the printer array as needed...
1006 if (pclass
->num_printers
> 0)
1008 free(pclass
->printers
);
1009 pclass
->num_printers
= 0;
1013 * Add each printer or class that is listed...
1016 for (i
= 0; i
< attr
->num_values
; i
++)
1019 * Search for the printer or class URI...
1022 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
1025 if ((dest
= ValidateDest(host
, resource
, &dtype
, &member
)) == NULL
)
1031 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
1032 send_ipp_error(con
, IPP_NOT_FOUND
);
1037 * Add it to the class...
1040 AddPrinterToClass(pclass
, member
);
1045 * Update the printer class attributes and return...
1048 SetPrinterAttrs(pclass
);
1056 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1057 "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1060 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1065 AddPrinterHistory(pclass
);
1067 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1068 "New class \'%s\' added by \'%s\'.", pclass
->name
,
1071 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
1075 con
->response
->request
.status
.status_code
= IPP_OK
;
1080 * 'add_file()' - Add a file to a job.
1083 static int /* O - 0 on success, -1 on error */
1084 add_file(client_t
*con
, /* I - Connection to client */
1085 job_t
*job
, /* I - Job to add to */
1086 mime_type_t
*filetype
, /* I - Type of file */
1087 int compression
) /* I - Compression */
1089 mime_type_t
**filetypes
; /* New filetypes array... */
1090 int *compressions
; /* New compressions array... */
1093 LogMessage(L_DEBUG2
, "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)\n",
1094 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1098 * Add the file to the job...
1101 if (job
->num_files
== 0)
1103 compressions
= (int *)malloc(sizeof(int));
1104 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1108 compressions
= (int *)realloc(job
->compressions
,
1109 (job
->num_files
+ 1) * sizeof(int));
1110 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1111 (job
->num_files
+ 1) *
1112 sizeof(mime_type_t
*));
1115 if (compressions
== NULL
|| filetypes
== NULL
)
1117 CancelJob(job
->id
, 1);
1118 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
1119 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
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_state_reasons()' - Add the "job-state-reasons" attribute based
1136 * upon the job and printer state...
1140 add_job_state_reasons(client_t
*con
, /* I - Client connection */
1141 job_t
*job
) /* I - Job info */
1143 printer_t
*dest
; /* Destination printer */
1146 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
1149 switch (job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
)
1151 case IPP_JOB_PENDING
:
1152 if (job
->dtype
& CUPS_PRINTER_CLASS
)
1153 dest
= FindClass(job
->dest
);
1155 dest
= FindPrinter(job
->dest
);
1157 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
1158 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1159 "job-state-reasons", NULL
, "printer-stopped");
1161 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1162 "job-state-reasons", NULL
, "none");
1166 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
1167 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
1168 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1169 "job-state-reasons", NULL
, "job-hold-until-specified");
1171 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1172 "job-state-reasons", NULL
, "job-incoming");
1175 case IPP_JOB_PROCESSING
:
1176 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1177 "job-state-reasons", NULL
, "job-printing");
1180 case IPP_JOB_STOPPED
:
1181 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1182 "job-state-reasons", NULL
, "job-stopped");
1185 case IPP_JOB_CANCELLED
:
1186 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1187 "job-state-reasons", NULL
, "job-canceled-by-user");
1190 case IPP_JOB_ABORTED
:
1191 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1192 "job-state-reasons", NULL
, "aborted-by-system");
1195 case IPP_JOB_COMPLETED
:
1196 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1197 "job-state-reasons", NULL
, "job-completed-successfully");
1204 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1208 add_job_subscriptions(client_t
*con
, /* I - Client connection */
1209 job_t
*job
) /* I - Newly created job */
1211 int i
; /* Looping var */
1212 ipp_attribute_t
*prev
, /* Previous attribute */
1213 *next
, /* Next attribute */
1214 *attr
; /* Current attribute */
1215 cupsd_subscription_t
*sub
; /* Subscription object */
1216 const char *recipient
, /* notify-recipient-uri */
1217 *pullmethod
; /* notify-pull-method */
1218 ipp_attribute_t
*user_data
; /* notify-user-data */
1219 int interval
; /* notify-time-interval */
1220 unsigned mask
; /* notify-events */
1224 * Find the first subscription group attribute; return if we have
1228 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; prev
= attr
, attr
= attr
->next
)
1229 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1236 * Process the subscription attributes in the request...
1245 mask
= CUPSD_EVENT_NONE
;
1247 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1249 if (!strcmp(attr
->name
, "notify-recipient") &&
1250 attr
->value_tag
== IPP_TAG_URI
)
1251 recipient
= attr
->values
[0].string
.text
;
1252 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1253 attr
->value_tag
== IPP_TAG_KEYWORD
)
1254 pullmethod
= attr
->values
[0].string
.text
;
1255 else if (!strcmp(attr
->name
, "notify-charset") &&
1256 attr
->value_tag
== IPP_TAG_CHARSET
&&
1257 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1259 send_ipp_error(con
, IPP_CHARSET
);
1262 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1263 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
1264 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
))
1266 send_ipp_error(con
, IPP_CHARSET
);
1269 else if (!strcmp(attr
->name
, "notify-user-data") &&
1270 attr
->value_tag
== IPP_TAG_STRING
)
1272 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1274 send_ipp_error(con
, IPP_REQUEST_VALUE
);
1280 else if (!strcmp(attr
->name
, "notify-events") &&
1281 attr
->value_tag
== IPP_TAG_KEYWORD
)
1283 for (i
= 0; i
< attr
->num_values
; i
++)
1284 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1286 else if (!strcmp(attr
->name
, "notify-lease-time"))
1288 send_ipp_error(con
, IPP_BAD_REQUEST
);
1291 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1292 attr
->value_tag
== IPP_TAG_INTEGER
)
1293 interval
= attr
->values
[0].integer
;
1298 if (!recipient
&& !pullmethod
)
1301 if (mask
== CUPSD_EVENT_NONE
)
1302 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1304 sub
= cupsdAddSubscription(mask
, FindDest(job
->dest
), job
, recipient
);
1306 sub
->interval
= interval
;
1308 SetString(&sub
->owner
, job
->username
);
1312 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1313 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1314 sub
->user_data_len
);
1322 * Remove all of the subscription attributes from the job request...
1325 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1329 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1330 attr
->group_tag
== IPP_TAG_ZERO
)
1333 * Free and remove this attribute...
1336 _ipp_free_attr(attr
);
1341 job
->attrs
->attrs
= next
;
1347 job
->attrs
->last
= prev
;
1348 job
->attrs
->current
= prev
;
1353 * 'add_printer()' - Add a printer to the system.
1357 add_printer(client_t
*con
, /* I - Client connection */
1358 ipp_attribute_t
*uri
) /* I - URI of printer */
1360 int i
; /* Looping var */
1361 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1362 username
[HTTP_MAX_URI
], /* Username portion of URI */
1363 host
[HTTP_MAX_URI
], /* Host portion of URI */
1364 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1365 int port
; /* Port portion of URI */
1366 printer_t
*printer
; /* Printer/class */
1367 ipp_attribute_t
*attr
; /* Printer attribute */
1368 cups_file_t
*fp
; /* Script/PPD file */
1369 char line
[1024]; /* Line from file... */
1370 char srcfile
[1024], /* Source Script/PPD file */
1371 dstfile
[1024]; /* Destination Script/PPD file */
1372 int modify
; /* Non-zero if we are modifying */
1375 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
1376 uri
->values
[0].string
.text
);
1379 * Was this operation called from the correct URI?
1382 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1384 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
1386 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1391 * Do we have a valid URI?
1394 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1396 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1399 * No, return an error...
1402 LogMessage(L_ERROR
, "add_printer: bad printer URI \"%s\"!",
1403 uri
->values
[0].string
.text
);
1404 send_ipp_error(con
, IPP_BAD_REQUEST
);
1409 * Do we have a valid printer name?
1412 if (!validate_name(resource
+ 10))
1415 * No, return an error...
1418 send_ipp_error(con
, IPP_BAD_REQUEST
);
1426 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
1428 LogMessage(L_ERROR
, "add_printer: not authorized!");
1429 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1434 * See if the printer already exists; if not, create a new printer...
1437 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1440 * Printer doesn't exist; see if we have a class of the same name...
1443 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1444 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1447 * Yes, return an error...
1450 LogMessage(L_ERROR
, "add_printer: \"%s\" already exists as a class!",
1452 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1457 * No, add the printer...
1460 printer
= AddPrinter(resource
+ 10);
1463 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1466 * Rename the implicit printer to "AnyPrinter" or delete it...
1469 if (ImplicitAnyClasses
)
1471 cupsArrayRemove(Printers
, printer
);
1472 SetStringf(&printer
->name
, "Any%s", resource
+ 10);
1473 cupsArrayAdd(Printers
, printer
);
1476 DeletePrinter(printer
, 1);
1479 * Add the printer as a new local printer...
1482 printer
= AddPrinter(resource
+ 10);
1485 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1488 * Rename the remote printer to "Printer@server"...
1491 DeletePrinterFilters(printer
);
1492 cupsArrayRemove(Printers
, printer
);
1493 SetStringf(&printer
->name
, "%s@%s", resource
+ 10, printer
->hostname
);
1494 SetPrinterAttrs(printer
);
1495 cupsArrayAdd(Printers
, printer
);
1498 * Add the printer as a new local printer...
1501 printer
= AddPrinter(resource
+ 10);
1508 * Look for attributes and copy them over as needed...
1511 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1512 SetString(&printer
->location
, attr
->values
[0].string
.text
);
1514 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1515 SetString(&printer
->info
, attr
->values
[0].string
.text
);
1517 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1520 * Do we have a valid device URI?
1523 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1526 if (!strcmp(method
, "file"))
1529 * See if the administrator has enabled file devices...
1532 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
1535 * File devices are disabled and the URL is not file:/dev/null...
1538 LogMessage(L_ERROR
, "add_printer: File device URIs have been disabled! "
1539 "To enable, see the FileDevice directive in cupsd.conf.");
1540 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1547 * See if the backend exists and is executable...
1550 snprintf(srcfile
, sizeof(srcfile
), "%s/backend/%s", ServerBin
, method
);
1551 if (access(srcfile
, X_OK
))
1554 * Could not find device in list!
1557 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1558 attr
->values
[0].string
.text
);
1559 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1564 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1566 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
, sizeof(line
)),
1567 cupsdSanitizeURI(printer
->device_uri
, resource
, sizeof(resource
)));
1569 SetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
1572 if ((attr
= ippFindAttribute(con
->request
, "port-monitor", IPP_TAG_KEYWORD
)) != NULL
)
1574 ipp_attribute_t
*supported
; /* port-monitor-supported attribute */
1577 supported
= ippFindAttribute(printer
->attrs
, "port-monitor-supported",
1579 for (i
= 0; i
< supported
->num_values
; i
++)
1580 if (!strcmp(supported
->values
[i
].string
.text
,
1581 attr
->values
[0].string
.text
))
1584 if (i
>= supported
->num_values
)
1586 LogMessage(L_ERROR
, "add_printer: bad port-monitor attribute \'%s\'!",
1587 attr
->values
[0].string
.text
);
1588 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1592 LogMessage(L_INFO
, "Setting %s port-monitor to \"%s\" (was \"%s\".)",
1593 printer
->name
, attr
->values
[0].string
.text
,
1594 printer
->port_monitor
);
1596 if (strcmp(attr
->values
[0].string
.text
, "none"))
1597 SetString(&printer
->port_monitor
, attr
->values
[0].string
.text
);
1599 ClearString(&printer
->port_monitor
);
1602 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1604 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1605 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1607 printer
->accepting
= attr
->values
[0].boolean
;
1608 AddPrinterHistory(printer
);
1611 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared", IPP_TAG_BOOLEAN
)) != NULL
)
1613 LogMessage(L_INFO
, "Setting %s printer-is-shared to %d (was %d.)",
1614 printer
->name
, attr
->values
[0].boolean
, printer
->shared
);
1616 printer
->shared
= attr
->values
[0].boolean
;
1619 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1621 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1622 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1624 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
1625 printer
->name
, attr
->values
[0].integer
);
1626 send_ipp_error(con
, IPP_BAD_REQUEST
);
1630 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1631 attr
->values
[0].integer
, printer
->state
);
1633 SetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1635 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1637 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
1638 sizeof(printer
->state_message
));
1639 AddPrinterHistory(printer
);
1641 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1644 SetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
1645 if (attr
->num_values
> 1)
1646 SetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
1648 SetString(&printer
->job_sheets
[1], "none");
1650 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1651 IPP_TAG_ZERO
)) != NULL
)
1653 FreePrinterUsers(printer
);
1655 printer
->deny_users
= 0;
1656 if (attr
->value_tag
== IPP_TAG_NAME
&&
1657 (attr
->num_values
> 1 ||
1658 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1659 for (i
= 0; i
< attr
->num_values
; i
++)
1660 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1662 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1663 IPP_TAG_ZERO
)) != NULL
)
1665 FreePrinterUsers(printer
);
1667 printer
->deny_users
= 1;
1668 if (attr
->value_tag
== IPP_TAG_NAME
&&
1669 (attr
->num_values
> 1 ||
1670 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1671 for (i
= 0; i
< attr
->num_values
; i
++)
1672 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1674 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1675 IPP_TAG_INTEGER
)) != NULL
)
1677 LogMessage(L_DEBUG
, "add_printer: Setting job-quota-period to %d...",
1678 attr
->values
[0].integer
);
1679 FreeQuotas(printer
);
1680 printer
->quota_period
= attr
->values
[0].integer
;
1682 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1683 IPP_TAG_INTEGER
)) != NULL
)
1685 LogMessage(L_DEBUG
, "add_printer: Setting job-k-limit to %d...",
1686 attr
->values
[0].integer
);
1687 FreeQuotas(printer
);
1688 printer
->k_limit
= attr
->values
[0].integer
;
1690 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1691 IPP_TAG_INTEGER
)) != NULL
)
1693 LogMessage(L_DEBUG
, "add_printer: Setting job-page-limit to %d...",
1694 attr
->values
[0].integer
);
1695 FreeQuotas(printer
);
1696 printer
->page_limit
= attr
->values
[0].integer
;
1698 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
1700 cupsd_policy_t
*p
; /* Policy */
1703 if ((p
= cupsdFindPolicy(attr
->values
[0].string
.text
)) != NULL
)
1705 LogMessage(L_DEBUG
, "add_printer: Setting printer-op-policy to \"%s\"...",
1706 attr
->values
[0].string
.text
);
1707 SetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
1708 printer
->op_policy_ptr
= p
;
1712 LogMessage(L_ERROR
, "add_printer: Unknown printer-op-policy \"%s\"...",
1713 attr
->values
[0].string
.text
);
1714 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1718 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
1720 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
1721 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
1722 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
1724 LogMessage(L_ERROR
, "add_printer: Unknown printer-error-policy \"%s\"...",
1725 attr
->values
[0].string
.text
);
1726 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1730 LogMessage(L_DEBUG
, "add_printer: Setting printer-error-policy to \"%s\"...",
1731 attr
->values
[0].string
.text
);
1732 SetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
1736 * See if we have all required attributes...
1739 if (!printer
->device_uri
)
1740 SetString(&printer
->device_uri
, "file:/dev/null");
1743 * See if we have an interface script or PPD file attached to the request...
1748 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
1750 if ((fp
= cupsFileOpen(srcfile
, "rb")) != NULL
)
1753 * Yes; get the first line from it...
1757 cupsFileGets(fp
, line
, sizeof(line
));
1761 * Then see what kind of file it is...
1764 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1767 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1770 * The new file is a PPD file, so remove any old interface script
1771 * that might be lying around...
1779 * This must be an interface script, so move the file over to the
1780 * interfaces directory and make it executable...
1783 if (copy_file(srcfile
, dstfile
))
1785 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1786 srcfile
, dstfile
, strerror(errno
));
1787 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1792 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1793 chmod(dstfile
, 0755);
1797 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1800 if (!strncmp(line
, "*PPD-Adobe", 10))
1803 * The new file is a PPD file, so move the file over to the
1804 * ppd directory and make it readable by all...
1807 if (copy_file(srcfile
, dstfile
))
1809 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1810 srcfile
, dstfile
, strerror(errno
));
1811 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1816 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1817 chmod(dstfile
, 0644);
1823 * This must be an interface script, so remove any old PPD file that
1824 * may be lying around...
1831 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1833 if (!strcmp(attr
->values
[0].string
.text
, "raw"))
1836 * Raw driver, remove any existing PPD or interface script files.
1839 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1843 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1853 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1857 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1860 if (copy_model(con
, attr
->values
[0].string
.text
, dstfile
))
1862 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1863 attr
->values
[0].string
.text
, dstfile
, strerror(errno
));
1864 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1869 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1870 chmod(dstfile
, 0644);
1876 * Make this printer the default if there is none...
1879 if (DefaultPrinter
== NULL
)
1880 DefaultPrinter
= printer
;
1883 * Update the printer attributes and return...
1886 SetPrinterAttrs(printer
);
1889 if (printer
->job
!= NULL
)
1894 * Stop the current job and then restart it below...
1897 job
= (job_t
*)printer
->job
;
1899 StopJob(job
->id
, 1);
1900 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1909 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
1910 "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1913 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1918 AddPrinterHistory(printer
);
1920 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
1921 "New printer \'%s\' added by \'%s\'.", printer
->name
,
1924 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1928 con
->response
->request
.status
.status_code
= IPP_OK
;
1933 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1934 * based upon the printer state...
1938 add_printer_state_reasons(
1939 client_t
*con
, /* I - Client connection */
1940 printer_t
*p
) /* I - Printer info */
1942 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1943 con
, con
->http
.fd
, p
, p
->name
);
1945 if (p
->num_reasons
== 0)
1946 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1947 "printer-state-reasons", NULL
,
1948 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
1950 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1951 "printer-state-reasons", p
->num_reasons
, NULL
,
1952 (const char * const *)p
->reasons
);
1957 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1958 * the specified printer or class.
1962 add_queued_job_count(client_t
*con
, /* I - Client connection */
1963 printer_t
*p
) /* I - Printer or class */
1965 int count
; /* Number of jobs on destination */
1968 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1969 con
, con
->http
.fd
, p
, p
->name
);
1971 count
= GetPrinterJobCount(p
->name
);
1973 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1974 "queued-job-count", count
);
1979 * 'authenticate_job()' - Set job authentication info.
1983 authenticate_job(client_t
*con
, /* I - Client connection */
1984 ipp_attribute_t
*uri
) /* I - Job URI */
1986 ipp_attribute_t
*attr
; /* Job-id attribute */
1987 int jobid
; /* Job ID */
1988 job_t
*job
; /* Current job */
1989 char method
[HTTP_MAX_URI
],
1990 /* Method portion of URI */
1991 username
[HTTP_MAX_URI
],
1992 /* Username portion of URI */
1994 /* Host portion of URI */
1995 resource
[HTTP_MAX_URI
];
1996 /* Resource portion of URI */
1997 int port
; /* Port portion of URI */
2000 LogMessage(L_DEBUG2
, "authenticate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2001 uri
->values
[0].string
.text
);
2004 * Start with "everything is OK" status...
2007 con
->response
->request
.status
.status_code
= IPP_OK
;
2010 * See if we have a job URI or a printer URI...
2013 if (!strcmp(uri
->name
, "printer-uri"))
2016 * Got a printer URI; see if we also have a job-id attribute...
2019 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2021 LogMessage(L_ERROR
, "authenticate_job: got a printer-uri attribute but no job-id!");
2022 send_ipp_error(con
, IPP_BAD_REQUEST
);
2026 jobid
= attr
->values
[0].integer
;
2031 * Got a job URI; parse it to get the job ID...
2034 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2036 if (strncmp(resource
, "/jobs/", 6))
2042 LogMessage(L_ERROR
, "authenticate_job: bad job-uri attribute \'%s\'!\n",
2043 uri
->values
[0].string
.text
);
2044 send_ipp_error(con
, IPP_BAD_REQUEST
);
2048 jobid
= atoi(resource
+ 6);
2052 * See if the job exists...
2055 if ((job
= FindJob(jobid
)) == NULL
)
2058 * Nope - return a "not found" error...
2061 LogMessage(L_ERROR
, "authenticate_job: job #%d doesn't exist!", jobid
);
2062 send_ipp_error(con
, IPP_NOT_FOUND
);
2067 * See if the job has been completed...
2070 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
2073 * Return a "not-possible" error...
2076 LogMessage(L_ERROR
, "authenticate_job: job #%d is not held for authentication!", jobid
);
2077 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2082 * See if we have already authenticated...
2085 if (!con
->username
[0])
2087 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2092 * See if the job is owned by the requesting user...
2095 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2097 LogMessage(L_ERROR
, "authenticate_job: \"%s\" not authorized to authenticate job id %d owned by \"%s\"!",
2098 username
, jobid
, job
->username
);
2099 send_ipp_error(con
, IPP_FORBIDDEN
);
2104 * Save the authentication information for this job...
2107 save_auth_info(con
, job
->id
);
2110 * Reset the job-hold-until value to "no-hold"...
2113 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
2114 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
2118 attr
->value_tag
= IPP_TAG_KEYWORD
;
2119 SetString(&(attr
->values
[0].string
.text
), "no-hold");
2123 * Release the job and return...
2128 LogMessage(L_INFO
, "Job %d was authenticated by \'%s\'.", jobid
,
2134 * 'cancel_all_jobs()' - Cancel all print jobs.
2138 cancel_all_jobs(client_t
*con
, /* I - Client connection */
2139 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2141 const char *dest
; /* Destination */
2142 cups_ptype_t dtype
; /* Destination type */
2143 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2144 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
2145 host
[HTTP_MAX_URI
], /* Host portion of URI */
2146 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2147 int port
; /* Port portion of URI */
2148 ipp_attribute_t
*attr
; /* Attribute in request */
2149 const char *username
; /* Username */
2150 int purge
; /* Purge? */
2151 printer_t
*printer
; /* Printer */
2154 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
2155 uri
->values
[0].string
.text
);
2158 * Was this operation called from the correct URI?
2161 if (strncmp(con
->uri
, "/admin/", 7) &&
2162 strncmp(con
->uri
, "/jobs/", 7))
2164 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
2166 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2171 * See if we have a printer URI...
2174 if (strcmp(uri
->name
, "printer-uri"))
2176 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
2177 uri
->name
, uri
->values
[0].string
.text
);
2178 send_ipp_error(con
, IPP_BAD_REQUEST
);
2183 * Get the username (if any) for the jobs we want to cancel (only if
2184 * "my-jobs" is specified...
2187 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
2188 attr
->values
[0].boolean
)
2190 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
2191 username
= attr
->values
[0].string
.text
;
2194 LogMessage(L_ERROR
, "cancel_all_jobs: missing requesting-user-name attribute!");
2195 send_ipp_error(con
, IPP_BAD_REQUEST
);
2203 (username
&& con
->username
[0] && strcmp(username
, con
->username
))) &&
2204 strncmp(con
->uri
, "/admin/", 7))
2206 LogMessage(L_ERROR
, "cancel_all_jobs: only administrators can cancel "
2207 "other users\' jobs!");
2208 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2213 * Look for the "purge-jobs" attribute...
2216 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
2217 purge
= attr
->values
[0].boolean
;
2222 * And if the destination is valid...
2225 httpSeparate(uri
->values
[0].string
.text
, method
, userpass
, host
, &port
,
2228 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2234 if (strcmp(resource
, "/printers/") != 0)
2236 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
2237 send_ipp_error(con
, IPP_NOT_FOUND
);
2245 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
2247 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2248 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2253 * Cancel all jobs on all printers...
2256 CancelJobs(NULL
, username
, purge
);
2258 LogMessage(L_INFO
, "All jobs were %s by \'%s\'.",
2259 purge
? "purged" : "cancelled", con
->username
);
2267 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
2269 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2270 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2275 * Cancel all of the jobs on the named printer...
2278 CancelJobs(dest
, username
, purge
);
2280 LogMessage(L_INFO
, "All jobs on \'%s\' were %s by \'%s\'.", dest
,
2281 purge
? "purged" : "cancelled", con
->username
);
2284 con
->response
->request
.status
.status_code
= IPP_OK
;
2289 * 'cancel_job()' - Cancel a print job.
2293 cancel_job(client_t
*con
, /* I - Client connection */
2294 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2296 ipp_attribute_t
*attr
; /* Current attribute */
2297 int jobid
; /* Job ID */
2298 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2299 username
[HTTP_MAX_URI
], /* Username portion of URI */
2300 host
[HTTP_MAX_URI
], /* Host portion of URI */
2301 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2302 int port
; /* Port portion of URI */
2303 job_t
*job
; /* Job information */
2304 const char *dest
; /* Destination */
2305 cups_ptype_t dtype
; /* Destination type (printer or class) */
2306 printer_t
*printer
; /* Printer data */
2309 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2310 uri
->values
[0].string
.text
);
2313 * Verify that the POST operation was done to a valid URI.
2316 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2317 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
2318 strncmp(con
->uri
, "/printers/", 10) != 0)
2320 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
2322 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2327 * See if we have a job URI or a printer URI...
2330 if (strcmp(uri
->name
, "printer-uri") == 0)
2333 * Got a printer URI; see if we also have a job-id attribute...
2336 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2338 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
2339 send_ipp_error(con
, IPP_BAD_REQUEST
);
2343 if ((jobid
= attr
->values
[0].integer
) == 0)
2346 * Find the current job on the specified printer...
2349 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2351 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2357 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
2358 send_ipp_error(con
, IPP_NOT_FOUND
);
2363 * See if the printer is currently printing a job...
2367 jobid
= ((job_t
*)printer
->job
)->id
;
2371 * No, see if there are any pending jobs...
2374 for (job
= (job_t
*)cupsArrayFirst(ActiveJobs
);
2376 job
= (job_t
*)cupsArrayNext(ActiveJobs
))
2377 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
2378 !strcasecmp(job
->dest
, dest
))
2385 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
2386 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2395 * Got a job URI; parse it to get the job ID...
2398 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2400 if (strncmp(resource
, "/jobs/", 6) != 0)
2406 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
2407 uri
->values
[0].string
.text
);
2408 send_ipp_error(con
, IPP_BAD_REQUEST
);
2412 jobid
= atoi(resource
+ 6);
2416 * See if the job exists...
2419 if ((job
= FindJob(jobid
)) == NULL
)
2422 * Nope - return a "not found" error...
2425 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
2426 send_ipp_error(con
, IPP_NOT_FOUND
);
2431 * See if the job is owned by the requesting user...
2434 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2436 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
2437 username
, jobid
, job
->username
);
2438 send_ipp_error(con
, IPP_FORBIDDEN
);
2443 * See if the job is already completed, cancelled, or aborted; if so,
2444 * we can't cancel...
2447 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
2449 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
2451 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
2452 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
2454 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2459 * Cancel the job and return...
2462 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED
, job
->printer
, job
,
2463 "Job cancelled by \'%s\'.", username
);
2465 CancelJob(jobid
, 0);
2468 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
2470 con
->response
->request
.status
.status_code
= IPP_OK
;
2475 * 'cancel_subscription()' - Cancel a subscription.
2479 cancel_subscription(client_t
*con
, /* I - Client connection */
2480 int sub_id
) /* I - Subscription ID */
2486 * 'check_quotas()' - Check quotas for a printer and user.
2489 static int /* O - 1 if OK, 0 if not */
2490 check_quotas(client_t
*con
, /* I - Client connection */
2491 printer_t
*p
) /* I - Printer or class */
2493 int i
; /* Looping var */
2494 ipp_attribute_t
*attr
; /* Current attribute */
2495 char username
[33]; /* Username */
2496 quota_t
*q
; /* Quota data */
2497 struct passwd
*pw
; /* User password data */
2500 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
2501 con
, con
->http
.fd
, p
, p
->name
);
2507 if (con
== NULL
|| p
== NULL
)
2511 * Figure out who is printing...
2514 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
2516 if (con
->username
[0])
2517 strlcpy(username
, con
->username
, sizeof(username
));
2518 else if (attr
!= NULL
)
2520 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
2521 attr
->values
[0].string
.text
);
2523 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
2526 strcpy(username
, "anonymous");
2529 * Check global active job limits for printers and users...
2532 if (MaxJobsPerPrinter
)
2535 * Check if there are too many pending jobs on this printer...
2538 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
2540 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
2548 * Check if there are too many pending jobs for this user...
2551 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
2553 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
2559 * Check against users...
2562 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
2567 pw
= getpwnam(username
);
2570 for (i
= 0; i
< p
->num_users
; i
++)
2571 if (p
->users
[i
][0] == '@')
2574 * Check group membership...
2577 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
2580 else if (!strcasecmp(username
, p
->users
[i
]))
2583 if ((i
< p
->num_users
) == p
->deny_users
)
2585 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
2595 if (p
->k_limit
|| p
->page_limit
)
2597 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
2599 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
2604 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
2605 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
2607 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
2614 * If we have gotten this far, we're done!
2622 * 'copy_attribute()' - Copy a single attribute.
2625 static ipp_attribute_t
* /* O - New attribute */
2627 ipp_t
*to
, /* O - Destination request/response */
2628 ipp_attribute_t
*attr
, /* I - Attribute to copy */
2629 int quickcopy
) /* I - Do a quick copy? */
2631 int i
; /* Looping var */
2632 ipp_attribute_t
*toattr
; /* Destination attribute */
2635 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
2636 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
2639 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2642 toattr
= ippAddSeparator(to
);
2645 case IPP_TAG_INTEGER
:
2647 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2648 attr
->name
, attr
->num_values
, NULL
);
2650 for (i
= 0; i
< attr
->num_values
; i
++)
2651 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
2654 case IPP_TAG_BOOLEAN
:
2655 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
2656 attr
->num_values
, NULL
);
2658 for (i
= 0; i
< attr
->num_values
; i
++)
2659 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
2662 case IPP_TAG_STRING
:
2665 case IPP_TAG_KEYWORD
:
2667 case IPP_TAG_URISCHEME
:
2668 case IPP_TAG_CHARSET
:
2669 case IPP_TAG_LANGUAGE
:
2670 case IPP_TAG_MIMETYPE
:
2671 toattr
= ippAddStrings(to
, attr
->group_tag
,
2672 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2673 attr
->name
, attr
->num_values
, NULL
, NULL
);
2677 for (i
= 0; i
< attr
->num_values
; i
++)
2678 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2682 for (i
= 0; i
< attr
->num_values
; i
++)
2683 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2688 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
2689 attr
->values
[0].date
);
2692 case IPP_TAG_RESOLUTION
:
2693 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
2694 attr
->num_values
, IPP_RES_PER_INCH
,
2697 for (i
= 0; i
< attr
->num_values
; i
++)
2699 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
2700 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
2701 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
2705 case IPP_TAG_RANGE
:
2706 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
2707 attr
->num_values
, NULL
, NULL
);
2709 for (i
= 0; i
< attr
->num_values
; i
++)
2711 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
2712 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
2716 case IPP_TAG_TEXTLANG
:
2717 case IPP_TAG_NAMELANG
:
2718 toattr
= ippAddStrings(to
, attr
->group_tag
,
2719 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2720 attr
->name
, attr
->num_values
, NULL
, NULL
);
2724 for (i
= 0; i
< attr
->num_values
; i
++)
2726 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
2727 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2732 for (i
= 0; i
< attr
->num_values
; i
++)
2735 toattr
->values
[i
].string
.charset
=
2736 strdup(attr
->values
[i
].string
.charset
);
2738 toattr
->values
[i
].string
.charset
=
2739 toattr
->values
[0].string
.charset
;
2741 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2746 case IPP_TAG_BEGIN_COLLECTION
:
2747 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
2748 attr
->num_values
, NULL
);
2750 for (i
= 0; i
< attr
->num_values
; i
++)
2752 toattr
->values
[i
].collection
= ippNew();
2753 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
2754 NULL
, IPP_TAG_ZERO
, 0);
2759 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2760 attr
->name
, attr
->num_values
, NULL
);
2762 for (i
= 0; i
< attr
->num_values
; i
++)
2764 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
2766 if (toattr
->values
[i
].unknown
.length
> 0)
2768 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
2769 toattr
->values
[i
].unknown
.length
= 0;
2771 memcpy(toattr
->values
[i
].unknown
.data
,
2772 attr
->values
[i
].unknown
.data
,
2773 toattr
->values
[i
].unknown
.length
);
2776 break; /* anti-compiler-warning-code */
2784 * 'copy_attrs()' - Copy attributes from one request to another.
2788 copy_attrs(ipp_t
*to
, /* I - Destination request */
2789 ipp_t
*from
, /* I - Source request */
2790 ipp_attribute_t
*req
, /* I - Requested attributes */
2791 ipp_tag_t group
, /* I - Group to copy */
2792 int quickcopy
) /* I - Do a quick copy? */
2794 int i
; /* Looping var */
2795 ipp_attribute_t
*fromattr
; /* Source attribute */
2798 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2800 if (to
== NULL
|| from
== NULL
)
2803 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2804 req
= NULL
; /* "all" means no filter... */
2806 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2809 * Filter attributes as needed...
2812 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2813 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2816 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2818 for (i
= 0; i
< req
->num_values
; i
++)
2819 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2822 if (i
== req
->num_values
)
2826 copy_attribute(to
, fromattr
, quickcopy
);
2832 * 'copy_banner()' - Copy a banner file to the requests directory for the
2836 static int /* O - Size of banner file in kbytes */
2837 copy_banner(client_t
*con
, /* I - Client connection */
2838 job_t
*job
, /* I - Job information */
2839 const char *name
) /* I - Name of banner */
2841 int i
; /* Looping var */
2842 int kbytes
; /* Size of banner file in kbytes */
2843 char filename
[1024]; /* Job filename */
2844 banner_t
*banner
; /* Pointer to banner */
2845 cups_file_t
*in
; /* Input file */
2846 cups_file_t
*out
; /* Output file */
2847 int ch
; /* Character from file */
2848 char attrname
[255], /* Name of attribute */
2849 *s
; /* Pointer into name */
2850 ipp_attribute_t
*attr
; /* Attribute */
2853 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2854 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2857 * Find the banner; return if not found or "none"...
2861 strcmp(name
, "none") == 0 ||
2862 (banner
= FindBanner(name
)) == NULL
)
2866 * Open the banner and job files...
2869 if (add_file(con
, job
, banner
->filetype
, 0))
2872 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2874 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
2876 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2877 filename
, strerror(errno
));
2882 fchmod(cupsFileNumber(out
), 0640);
2883 fchown(cupsFileNumber(out
), RunUser
, Group
);
2886 * Try the localized banner file under the subdirectory...
2889 strlcpy(attrname
, con
->request
->attrs
->next
->values
[0].string
.text
,
2891 if (strlen(attrname
) > 2 && attrname
[2] == '-')
2894 * Convert ll-cc to ll_CC...
2898 attrname
[3] = toupper(attrname
[3] & 255);
2899 attrname
[4] = toupper(attrname
[4] & 255);
2902 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2905 if (access(filename
, 0) && strlen(attrname
) > 2)
2908 * Wasn't able to find "ll_CC" locale file; try the non-national
2909 * localization banner directory.
2914 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2918 if (access(filename
, 0))
2921 * Use the non-localized banner file.
2924 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2927 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
2931 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2932 filename
, strerror(errno
));
2938 * Parse the file to the end...
2941 while ((ch
= cupsFileGetChar(in
)) != EOF
)
2945 * Get an attribute name...
2948 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
2949 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
2951 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2961 * Ignore { followed by stuff that is not an attribute name...
2964 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
2969 * See if it is defined...
2972 if (attrname
[0] == '?')
2977 if (strcmp(s
, "printer-name") == 0)
2979 cupsFilePuts(out
, job
->dest
);
2982 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2985 * See if we have a leading question mark...
2988 if (attrname
[0] != '?')
2991 * Nope, write to file as-is; probably a PostScript procedure...
2994 cupsFilePrintf(out
, "{%s}", attrname
);
3001 * Output value(s)...
3004 for (i
= 0; i
< attr
->num_values
; i
++)
3007 cupsFilePutChar(out
, ',');
3009 switch (attr
->value_tag
)
3011 case IPP_TAG_INTEGER
:
3013 if (strncmp(s
, "time-at-", 8) == 0)
3014 cupsFilePuts(out
, GetDateTime(attr
->values
[i
].integer
));
3016 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
3019 case IPP_TAG_BOOLEAN
:
3020 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
3023 case IPP_TAG_NOVALUE
:
3024 cupsFilePuts(out
, "novalue");
3027 case IPP_TAG_RANGE
:
3028 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
3029 attr
->values
[i
].range
.upper
);
3032 case IPP_TAG_RESOLUTION
:
3033 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
3034 attr
->values
[i
].resolution
.yres
,
3035 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3040 case IPP_TAG_STRING
:
3043 case IPP_TAG_KEYWORD
:
3044 case IPP_TAG_CHARSET
:
3045 case IPP_TAG_LANGUAGE
:
3046 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
3049 * Need to quote strings for PS banners...
3054 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
3056 if (*p
== '(' || *p
== ')' || *p
== '\\')
3058 cupsFilePutChar(out
, '\\');
3059 cupsFilePutChar(out
, *p
);
3061 else if (*p
< 32 || *p
> 126)
3062 cupsFilePrintf(out
, "\\%03o", *p
& 255);
3064 cupsFilePutChar(out
, *p
);
3068 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
3072 break; /* anti-compiler-warning-code */
3076 else if (ch
== '\\') /* Quoted char */
3078 ch
= cupsFileGetChar(in
);
3080 if (ch
!= '{') /* Only do special handling for \{ */
3081 cupsFilePutChar(out
, '\\');
3083 cupsFilePutChar(out
, ch
);
3086 cupsFilePutChar(out
, ch
);
3090 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
3092 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3093 attr
->values
[0].integer
+= kbytes
;
3102 * 'copy_file()' - Copy a PPD file or interface script...
3105 static int /* O - 0 = success, -1 = error */
3106 copy_file(const char *from
, /* I - Source file */
3107 const char *to
) /* I - Destination file */
3109 cups_file_t
*src
, /* Source file */
3110 *dst
; /* Destination file */
3111 int bytes
; /* Bytes to read/write */
3112 char buffer
[2048]; /* Copy buffer */
3115 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
3118 * Open the source and destination file for a copy...
3121 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3124 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3131 * Copy the source file to the destination...
3134 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
3135 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
3143 * Close both files and return...
3148 return (cupsFileClose(dst
));
3153 * 'copy_model()' - Copy a PPD model file, substituting default values
3157 static int /* O - 0 = success, -1 = error */
3158 copy_model(client_t
*con
, /* I - Client connection */
3159 const char *from
, /* I - Source file */
3160 const char *to
) /* I - Destination file */
3162 fd_set
*input
; /* select() input set */
3163 struct timeval timeout
; /* select() timeout */
3164 int maxfd
; /* Maximum file descriptor for select() */
3165 char tempfile
[1024]; /* Temporary PPD file */
3166 int tempfd
; /* Temporary PPD file descriptor */
3167 int temppid
; /* Process ID of cups-driverd */
3168 int temppipe
[2]; /* Temporary pipes */
3169 char *argv
[4], /* Command-line arguments */
3170 *envp
[100]; /* Environment */
3171 cups_file_t
*src
, /* Source file */
3172 *dst
; /* Destination file */
3173 int bytes
, /* Bytes from pipe */
3174 total
; /* Total bytes from pipe */
3175 char buffer
[2048], /* Copy buffer */
3176 *ptr
; /* Pointer into buffer */
3177 int i
; /* Looping var */
3178 char option
[PPD_MAX_NAME
], /* Option name */
3179 choice
[PPD_MAX_NAME
]; /* Choice name */
3180 int num_defaults
; /* Number of default options */
3181 ppd_default_t
*defaults
; /* Default options */
3182 char cups_protocol
[PPD_MAX_LINE
];
3183 /* cupsProtocol attribute */
3184 int have_letter
, /* Have Letter size */
3185 have_a4
; /* Have A4 size */
3186 #ifdef HAVE_LIBPAPER
3187 char *paper_result
; /* Paper size name from libpaper */
3188 char system_paper
[64]; /* Paper size name buffer */
3189 #endif /* HAVE_LIBPAPER */
3192 LogMessage(L_DEBUG2
, "copy_model(con=%p, from=\"%s\", to=\"%s\")\n",
3196 * Run cups-driverd to get the PPD file...
3199 argv
[0] = "cups-driverd";
3201 argv
[2] = (char *)from
;
3204 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
3206 snprintf(buffer
, sizeof(buffer
), "%s/daemon/cups-driverd", ServerBin
);
3207 snprintf(tempfile
, sizeof(tempfile
), "%s/%d.ppd", TempDir
, con
->http
.fd
);
3208 tempfd
= open(tempfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
3212 cupsdOpenPipe(temppipe
);
3214 if ((input
= calloc(1, SetSize
)) == NULL
)
3219 LogMessage(L_ERROR
, "copy_model: Unable to allocate %d bytes for select()...",
3224 LogMessage(L_DEBUG
, "copy_model: Running \"cups-driverd cat %s\"...", from
);
3226 if (!cupsdStartProcess(buffer
, argv
, envp
, -1, temppipe
[1], CGIPipes
[1],
3237 * Wait up to 30 seconds for the PPD file to be copied...
3242 if (temppipe
[0] > CGIPipes
[0])
3243 maxfd
= temppipe
[0] + 1;
3245 maxfd
= CGIPipes
[0] + 1;
3250 * See if we have data ready...
3255 FD_SET(temppipe
[0], input
);
3256 FD_SET(CGIPipes
[0], input
);
3258 timeout
.tv_sec
= 30;
3259 timeout
.tv_usec
= 0;
3261 if ((i
= select(maxfd
, input
, NULL
, NULL
, &timeout
)) < 0)
3271 * We have timed out...
3277 if (FD_ISSET(temppipe
[0], input
))
3280 * Read the PPD file from the pipe, and write it to the PPD file.
3283 if ((bytes
= read(temppipe
[0], buffer
, sizeof(buffer
))) > 0)
3285 if (write(tempfd
, buffer
, bytes
) < bytes
)
3294 if (FD_ISSET(CGIPipes
[0], input
))
3304 * No data from cups-deviced...
3307 LogMessage(L_ERROR
, "copy_model: empty PPD file!");
3313 * Read the source file and see what page sizes are supported...
3316 if ((src
= cupsFileOpen(tempfile
, "rb")) == NULL
)
3325 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3326 if (!strncmp(buffer
, "*PageSize ", 10))
3329 * Strip UI text and command data from the end of the line...
3332 if ((ptr
= strchr(buffer
+ 10, '/')) != NULL
)
3334 if ((ptr
= strchr(buffer
+ 10, ':')) != NULL
)
3337 for (ptr
= buffer
+ 10; isspace(*ptr
); ptr
++);
3340 * Look for Letter and A4 page sizes...
3343 if (!strcmp(ptr
, "Letter"))
3346 if (!strcmp(ptr
, "A4"))
3350 cupsFileRewind(src
);
3353 * Open the destination (if possible) and set the default options...
3358 cups_protocol
[0] = '\0';
3360 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
3363 * Read all of the default lines from the old PPD...
3366 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)) != NULL
)
3367 if (!strncmp(buffer
, "*Default", 8))
3370 * Add the default option...
3373 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3374 choice
, sizeof(choice
)))
3375 num_defaults
= ppd_add_default(option
, choice
, num_defaults
,
3378 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
3379 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
3383 #ifdef HAVE_LIBPAPER
3384 else if ((paper_result
= systempapername()) != NULL
)
3387 * Set the default media sizes from the systemwide default...
3390 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
3391 system_paper
[0] = toupper(system_paper
[0] & 255);
3393 if ((!strcmp(system_paper
, "Letter") && have_letter
) ||
3394 (!strcmp(system_paper
, "A4") && have_a4
))
3396 num_defaults
= ppd_add_default("PageSize", system_paper
,
3397 num_defaults
, &defaults
);
3398 num_defaults
= ppd_add_default("PageRegion", system_paper
,
3399 num_defaults
, &defaults
);
3400 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
3401 num_defaults
, &defaults
);
3402 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
3403 num_defaults
, &defaults
);
3406 #endif /* HAVE_LIBPAPER */
3410 * Add the default media sizes...
3412 * Note: These values are generally not valid for large-format devices
3413 * like plotters, however it is probably safe to say that those
3414 * users will configure the media size after initially adding
3415 * the device anyways...
3418 if (!DefaultLanguage
||
3419 !strcasecmp(DefaultLanguage
, "C") ||
3420 !strcasecmp(DefaultLanguage
, "POSIX") ||
3421 !strcasecmp(DefaultLanguage
, "en") ||
3422 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
3423 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
3424 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
3427 * These are the only locales that will default to "letter" size...
3432 num_defaults
= ppd_add_default("PageSize", "Letter", num_defaults
,
3434 num_defaults
= ppd_add_default("PageRegion", "Letter", num_defaults
,
3436 num_defaults
= ppd_add_default("PaperDimension", "Letter", num_defaults
,
3438 num_defaults
= ppd_add_default("ImageableArea", "Letter", num_defaults
,
3445 * The rest default to "a4" size...
3448 num_defaults
= ppd_add_default("PageSize", "A4", num_defaults
,
3450 num_defaults
= ppd_add_default("PageRegion", "A4", num_defaults
,
3452 num_defaults
= ppd_add_default("PaperDimension", "A4", num_defaults
,
3454 num_defaults
= ppd_add_default("ImageableArea", "A4", num_defaults
,
3460 * Open the destination file for a copy...
3463 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3465 if (num_defaults
> 0)
3474 * Copy the source file to the destination...
3477 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3479 if (!strncmp(buffer
, "*Default", 8))
3482 * Check for an previous default option choice...
3485 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3486 choice
, sizeof(choice
)))
3488 for (i
= 0; i
< num_defaults
; i
++)
3489 if (!strcmp(option
, defaults
[i
].option
))
3492 * Substitute the previous choice...
3495 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
,
3496 defaults
[i
].choice
);
3502 cupsFilePrintf(dst
, "%s\n", buffer
);
3505 if (cups_protocol
[0])
3506 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
3508 if (num_defaults
> 0)
3512 * Close both files and return...
3519 return (cupsFileClose(dst
));
3524 * 'create_job()' - Print a file to a printer or class.
3528 create_job(client_t
*con
, /* I - Client connection */
3529 ipp_attribute_t
*uri
) /* I - Printer URI */
3531 ipp_attribute_t
*attr
; /* Current attribute */
3532 const char *dest
; /* Destination */
3533 cups_ptype_t dtype
; /* Destination type (printer or class) */
3534 int priority
; /* Job priority */
3535 char *title
; /* Job name/title */
3536 job_t
*job
; /* Current job */
3537 char job_uri
[HTTP_MAX_URI
], /* Job URI */
3538 method
[HTTP_MAX_URI
], /* Method portion of URI */
3539 username
[HTTP_MAX_URI
], /* Username portion of URI */
3540 host
[HTTP_MAX_URI
], /* Host portion of URI */
3541 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3542 int port
; /* Port portion of URI */
3543 printer_t
*printer
; /* Printer data */
3544 int kbytes
; /* Size of print file */
3545 int i
; /* Looping var */
3546 int lowerpagerange
; /* Page range bound */
3549 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3550 uri
->values
[0].string
.text
);
3553 * Verify that the POST operation was done to a valid URI.
3556 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3557 strncmp(con
->uri
, "/printers/", 10) != 0)
3559 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
3561 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3566 * Is the destination valid?
3569 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3571 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3577 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
3578 send_ipp_error(con
, IPP_NOT_FOUND
);
3583 * Check remote printing to non-shared printer...
3586 if (!printer
->shared
&&
3587 strcasecmp(con
->http
.hostname
, "localhost") &&
3588 strcasecmp(con
->http
.hostname
, ServerName
))
3590 LogMessage(L_ERROR
, "print_job: printer not shared!");
3591 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3599 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
) ||
3600 ((printer
->type
& CUPS_PRINTER_AUTHENTICATED
) && !con
->username
[0]))
3602 LogMessage(L_ERROR
, "create_job: not authorized!");
3603 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3608 * See if the printer is accepting jobs...
3611 if (!printer
->accepting
)
3613 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
3615 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3620 * Validate job template attributes; for now just copies and page-ranges...
3623 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
3625 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
3627 LogMessage(L_ERROR
, "create_job: Bad copies value %d.",
3628 attr
->values
[0].integer
);
3629 send_ipp_error(con
, IPP_ATTRIBUTES
);
3630 ippAddInteger(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_INTEGER
,
3631 "copies", attr
->values
[0].integer
);
3636 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
3638 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
3640 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
3641 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3643 LogMessage(L_ERROR
, "create_job: bad page-ranges values %d-%d.",
3644 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3645 send_ipp_error(con
, IPP_BAD_REQUEST
);
3649 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
3654 * Make sure we aren't over our limit...
3657 if (cupsArrayCount(Jobs
) >= MaxJobs
&& MaxJobs
)
3660 if (cupsArrayCount(Jobs
) >= MaxJobs
&& MaxJobs
)
3662 LogMessage(L_INFO
, "create_job: too many jobs.");
3663 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3667 if (!check_quotas(con
, printer
))
3669 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3674 * Create the job and set things up...
3677 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3678 priority
= attr
->values
[0].integer
;
3680 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3683 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3684 title
= attr
->values
[0].string
.text
;
3686 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3687 title
= "Untitled");
3689 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3691 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
3693 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3698 job
->attrs
= con
->request
;
3699 con
->request
= NULL
;
3701 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3703 if (con
->username
[0])
3705 SetString(&job
->username
, con
->username
);
3706 save_auth_info(con
, job
->id
);
3708 else if (attr
!= NULL
)
3710 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
3711 attr
->values
[0].string
.text
);
3713 SetString(&job
->username
, attr
->values
[0].string
.text
);
3716 SetString(&job
->username
, "anonymous");
3719 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3720 NULL
, job
->username
);
3723 attr
->group_tag
= IPP_TAG_JOB
;
3724 SetString(&attr
->name
, "job-originating-user-name");
3727 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
3728 IPP_TAG_ZERO
)) != NULL
)
3731 * Request contains a job-originating-host-name attribute; validate it...
3734 if (attr
->value_tag
!= IPP_TAG_NAME
||
3735 attr
->num_values
!= 1 ||
3736 strcmp(con
->http
.hostname
, "localhost") != 0)
3739 * Can't override the value if we aren't connected via localhost.
3740 * Also, we can only have 1 value and it must be a name value.
3743 switch (attr
->value_tag
)
3745 case IPP_TAG_STRING
:
3746 case IPP_TAG_TEXTLANG
:
3747 case IPP_TAG_NAMELANG
:
3750 case IPP_TAG_KEYWORD
:
3752 case IPP_TAG_URISCHEME
:
3753 case IPP_TAG_CHARSET
:
3754 case IPP_TAG_LANGUAGE
:
3755 case IPP_TAG_MIMETYPE
:
3757 * Free old strings...
3760 for (i
= 0; i
< attr
->num_values
; i
++)
3762 free(attr
->values
[i
].string
.text
);
3763 attr
->values
[i
].string
.text
= NULL
;
3764 if (attr
->values
[i
].string
.charset
)
3766 free(attr
->values
[i
].string
.charset
);
3767 attr
->values
[i
].string
.charset
= NULL
;
3776 * Use the default connection hostname instead...
3779 attr
->value_tag
= IPP_TAG_NAME
;
3780 attr
->num_values
= 1;
3781 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
3784 attr
->group_tag
= IPP_TAG_JOB
;
3789 * No job-originating-host-name attribute, so use the hostname from
3793 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3794 "job-originating-host-name", NULL
, con
->http
.hostname
);
3797 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3799 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3800 "time-at-processing", 0);
3801 attr
->value_tag
= IPP_TAG_NOVALUE
;
3802 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3803 "time-at-completed", 0);
3804 attr
->value_tag
= IPP_TAG_NOVALUE
;
3807 * Add remaining job attributes...
3810 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3811 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3812 "job-state", IPP_JOB_STOPPED
);
3813 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3814 "job-media-sheets-completed", 0);
3815 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3817 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3820 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3821 attr
->values
[0].integer
= 0;
3823 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3826 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3827 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3829 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
3830 "job-hold-until", NULL
, "no-hold");
3831 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
3832 !(printer
->type
& CUPS_PRINTER_REMOTE
))
3835 * Hold job until specified time...
3838 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3841 job
->hold_until
= time(NULL
) + 60;
3843 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
3845 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
3849 * Add job sheets options...
3852 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
3854 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
3855 printer
->job_sheets
[0], printer
->job_sheets
[1]);
3857 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
3859 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
3860 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
3863 job
->job_sheets
= attr
;
3866 * Enforce classification level if set...
3871 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
3872 Classification
? Classification
: "(null)", ClassifyOverride
);
3874 if (ClassifyOverride
)
3876 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
3877 (attr
->num_values
== 1 ||
3878 strcmp(attr
->values
[1].string
.text
, "none") == 0))
3881 * Force the leading banner to have the classification on it...
3884 SetString(&attr
->values
[0].string
.text
, Classification
);
3886 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3887 "job-sheets=\"%s,none\", "
3888 "job-originating-user-name=\"%s\"",
3889 job
->id
, Classification
,
3892 else if (attr
->num_values
== 2 &&
3893 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
3894 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
3895 strcmp(attr
->values
[1].string
.text
, "none") != 0)
3898 * Can't put two different security markings on the same document!
3901 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
3903 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3904 "job-sheets=\"%s,%s\", "
3905 "job-originating-user-name=\"%s\"",
3906 job
->id
, attr
->values
[0].string
.text
,
3907 attr
->values
[1].string
.text
,
3910 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
3911 strcmp(attr
->values
[0].string
.text
, "none") &&
3912 (attr
->num_values
== 1 ||
3913 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
3914 strcmp(attr
->values
[1].string
.text
, "none"))))
3916 if (attr
->num_values
== 1)
3917 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3918 "job-sheets=\"%s\", "
3919 "job-originating-user-name=\"%s\"",
3920 job
->id
, attr
->values
[0].string
.text
,
3923 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3924 "job-sheets=\"%s,%s\",fffff "
3925 "job-originating-user-name=\"%s\"",
3926 job
->id
, attr
->values
[0].string
.text
,
3927 attr
->values
[1].string
.text
,
3931 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
3932 (attr
->num_values
== 1 ||
3933 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
3936 * Force the banner to have the classification on it...
3939 if (attr
->num_values
> 1 &&
3940 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
3942 SetString(&(attr
->values
[0].string
.text
), Classification
);
3943 SetString(&(attr
->values
[1].string
.text
), Classification
);
3947 if (attr
->num_values
== 1 ||
3948 strcmp(attr
->values
[0].string
.text
, "none"))
3949 SetString(&(attr
->values
[0].string
.text
), Classification
);
3951 if (attr
->num_values
> 1 &&
3952 strcmp(attr
->values
[1].string
.text
, "none"))
3953 SetString(&(attr
->values
[1].string
.text
), Classification
);
3956 if (attr
->num_values
> 1)
3957 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3958 "job-sheets=\"%s,%s\", "
3959 "job-originating-user-name=\"%s\"",
3960 job
->id
, attr
->values
[0].string
.text
,
3961 attr
->values
[1].string
.text
,
3964 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3965 "job-sheets=\"%s\", "
3966 "job-originating-user-name=\"%s\"",
3967 job
->id
, Classification
,
3973 * See if we need to add the starting sheet...
3976 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
3978 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
3979 attr
->values
[0].string
.text
, job
->id
);
3981 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
3983 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3986 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
3990 * Add any job subscriptions...
3993 add_job_subscriptions(con
, job
);
3996 * Set all but the first two attributes to the job attributes group...
3999 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
4000 attr
->group_tag
= IPP_TAG_JOB
;
4003 * Save and log the job...
4008 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
4009 job
->dest
, job
->username
);
4011 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
4014 * Fill in the response info...
4017 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4018 LocalPort
, job
->id
);
4020 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
4022 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4024 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
4025 job
->state
->values
[0].integer
);
4027 con
->response
->request
.status
.status_code
= IPP_OK
;
4032 * 'create_subscription()' - Create a notification subscription.
4036 create_subscription(
4037 client_t
*con
, /* I - Client connection */
4038 ipp_attribute_t
*uri
) /* I - Printer URI */
4044 * 'delete_printer()' - Remove a printer or class from the system.
4048 delete_printer(client_t
*con
, /* I - Client connection */
4049 ipp_attribute_t
*uri
) /* I - URI of printer or class */
4051 const char *dest
; /* Destination */
4052 cups_ptype_t dtype
; /* Destination type (printer or class) */
4053 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4054 username
[HTTP_MAX_URI
], /* Username portion of URI */
4055 host
[HTTP_MAX_URI
], /* Host portion of URI */
4056 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4057 int port
; /* Port portion of URI */
4058 printer_t
*printer
; /* Printer/class */
4059 char filename
[1024]; /* Script/PPD filename */
4062 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
4063 uri
->values
[0].string
.text
);
4066 * Was this operation called from the correct URI?
4069 if (strncmp(con
->uri
, "/admin/", 7) != 0)
4071 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
4073 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4078 * Do we have a valid URI?
4081 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4083 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4089 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
4090 send_ipp_error(con
, IPP_NOT_FOUND
);
4098 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4100 LogMessage(L_ERROR
, "delete_printer: not authorized!");
4101 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4106 * Remove old jobs...
4109 CancelJobs(dest
, NULL
, 1);
4112 * Remove old subscriptions and send a "deleted printer" event...
4115 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
4116 "%s \'%s\' deleted by \'%s\'.",
4117 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
4118 dest
, con
->username
);
4120 cupsdExpireSubscriptions(printer
, NULL
);
4123 * Remove any old PPD or script files...
4126 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
4129 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
4132 if (dtype
& CUPS_PRINTER_CLASS
)
4134 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
4137 DeletePrinter(printer
, 0);
4142 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
4145 DeletePrinter(printer
, 0);
4150 * Return with no errors...
4153 con
->response
->request
.status
.status_code
= IPP_OK
;
4158 * 'get_default()' - Get the default destination.
4162 get_default(client_t
*con
) /* I - Client connection */
4164 int i
; /* Looping var */
4165 ipp_attribute_t
*requested
, /* requested-attributes */
4166 *history
; /* History collection */
4167 int need_history
; /* Need to send history collection? */
4168 char printer_uri
[HTTP_MAX_URI
];
4170 time_t curtime
; /* Current time */
4173 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
4179 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4181 LogMessage(L_ERROR
, "get_default: not authorized!");
4182 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4186 if (DefaultPrinter
!= NULL
)
4189 * Copy the printer attributes to the response using requested-attributes
4190 * and document-format attributes that may be provided by the client.
4193 if (!ippFindAttribute(DefaultPrinter
->attrs
, "printer-uri-supported",
4196 snprintf(printer_uri
, sizeof(printer_uri
), "ipp://%s:%d/printers/%s",
4197 con
->servername
, con
->serverport
, DefaultPrinter
->name
);
4198 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
4199 "printer-uri-supported", NULL
, printer_uri
);
4200 LogMessage(L_DEBUG2
, "printer-uri-supported=\"%s\"", printer_uri
);
4203 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4204 DefaultPrinter
->state
);
4206 add_printer_state_reasons(con
, DefaultPrinter
);
4208 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4209 "printer-state-message", NULL
, DefaultPrinter
->state_message
);
4211 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4212 DefaultPrinter
->accepting
);
4213 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
4214 DefaultPrinter
->shared
);
4216 curtime
= time(NULL
);
4217 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4218 "printer-up-time", curtime
);
4219 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4220 "printer-state-time", DefaultPrinter
->state_time
);
4221 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4222 ippTimeToDate(curtime
));
4224 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4225 "printer-error-policy", NULL
, DefaultPrinter
->op_policy
);
4226 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4227 "printer-op-policy", NULL
, DefaultPrinter
->op_policy
);
4229 add_queued_job_count(con
, DefaultPrinter
);
4231 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4234 copy_attrs(con
->response
, DefaultPrinter
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4235 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4239 if (MaxPrinterHistory
> 0 && DefaultPrinter
->num_history
> 0 && requested
)
4241 for (i
= 0; i
< requested
->num_values
; i
++)
4242 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4243 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4252 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4253 "printer-state-history",
4254 DefaultPrinter
->num_history
, NULL
);
4256 for (i
= 0; i
< DefaultPrinter
->num_history
; i
++)
4257 copy_attrs(history
->values
[i
].collection
= ippNew(),
4258 DefaultPrinter
->history
[i
],
4259 NULL
, IPP_TAG_ZERO
, 0);
4262 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4265 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
4270 * 'get_devices()' - Get the list of available devices on the local system.
4274 get_devices(client_t
*con
) /* I - Client connection */
4276 int i
; /* Looping var */
4277 ipp_attribute_t
*limit
, /* Limit attribute */
4278 *requested
; /* requested-attributes attribute */
4279 char command
[1024], /* cups-deviced command */
4280 options
[1024], /* Options to pass to command */
4281 attrs
[1024], /* String for requested attributes */
4282 *aptr
; /* Pointer into string */
4283 int alen
; /* Length of attribute value */
4286 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
4292 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4294 LogMessage(L_ERROR
, "get_devices: not authorized!");
4295 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4300 * Run cups-deviced command with the given options...
4303 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
4304 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4309 for (i
= 0, aptr
= attrs
; i
< requested
->num_values
; i
++)
4312 * Check that we have enough room...
4315 alen
= strlen(requested
->values
[i
].string
.text
);
4316 if (alen
> (sizeof(attrs
) - (aptr
- attrs
) - 2))
4320 * Put commas between values...
4327 * Add the value to the end of the string...
4330 strcpy(aptr
, requested
->values
[i
].string
.text
);
4335 * If we have more attribute names than will fit, default to "all"...
4338 if (i
< requested
->num_values
)
4339 strcpy(attrs
, "all");
4342 strcpy(attrs
, "all");
4344 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
4345 snprintf(options
, sizeof(options
),
4346 "cups-deviced %d+%d+requested-attributes=%s",
4347 con
->request
->request
.op
.request_id
,
4348 limit
? limit
->values
[0].integer
: 0,
4351 if (SendCommand(con
, command
, options
, 1))
4354 * Command started successfully, don't send an IPP response here...
4357 ippDelete(con
->response
);
4358 con
->response
= NULL
;
4363 * Command failed, return "internal error" so the user knows something
4367 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
4373 * 'get_jobs()' - Get a list of jobs for the specified printer.
4377 get_jobs(client_t
*con
, /* I - Client connection */
4378 ipp_attribute_t
*uri
) /* I - Printer URI */
4380 ipp_attribute_t
*attr
, /* Current attribute */
4381 *requested
; /* Requested attributes */
4382 const char *dest
; /* Destination */
4383 cups_ptype_t dtype
; /* Destination type (printer or class) */
4384 cups_ptype_t dmask
; /* Destination type mask */
4385 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4386 username
[HTTP_MAX_URI
], /* Username portion of URI */
4387 host
[HTTP_MAX_URI
], /* Host portion of URI */
4388 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4389 int port
; /* Port portion of URI */
4390 int completed
; /* Completed jobs? */
4391 int first
; /* First job ID */
4392 int limit
; /* Maximum number of jobs to return */
4393 int count
; /* Number of jobs that match */
4394 job_t
*job
; /* Current job pointer */
4395 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4396 printer_t
*printer
; /* Printer */
4397 cups_array_t
*list
; /* Which job list... */
4400 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
4401 uri
->values
[0].string
.text
);
4404 * Is the destination valid?
4407 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4409 if (strcmp(resource
, "/") == 0 ||
4410 (strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6))
4413 dtype
= (cups_ptype_t
)0;
4414 dmask
= (cups_ptype_t
)0;
4417 else if (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10)
4420 dtype
= (cups_ptype_t
)0;
4421 dmask
= CUPS_PRINTER_CLASS
;
4424 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
4427 dtype
= CUPS_PRINTER_CLASS
;
4428 dmask
= CUPS_PRINTER_CLASS
;
4431 else if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4437 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
4438 send_ipp_error(con
, IPP_NOT_FOUND
);
4442 dmask
= CUPS_PRINTER_CLASS
;
4450 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4452 LogMessage(L_ERROR
, "get_jobs: not authorized!");
4453 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4457 else if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4459 LogMessage(L_ERROR
, "get_jobs: not authorized!");
4460 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4465 * See if the "which-jobs" attribute have been specified...
4468 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
4469 !strcmp(attr
->values
[0].string
.text
, "completed"))
4474 else if (attr
&& !strcmp(attr
->values
[0].string
.text
, "all"))
4486 * See if they want to limit the number of jobs reported...
4489 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4490 limit
= attr
->values
[0].integer
;
4494 if ((attr
= ippFindAttribute(con
->request
, "first", IPP_TAG_INTEGER
)) != NULL
)
4495 first
= attr
->values
[0].integer
;
4500 * See if we only want to see jobs for a specific user...
4503 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
4504 attr
->values
[0].boolean
)
4506 if (con
->username
[0])
4507 strlcpy(username
, con
->username
, sizeof(username
));
4508 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4509 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
4511 strcpy(username
, "anonymous");
4516 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4520 * OK, build a list of jobs for this printer...
4523 for (count
= 0, job
= (job_t
*)cupsArrayFirst(list
);
4524 count
< limit
&& job
;
4525 job
= (job_t
*)cupsArrayNext(list
))
4528 * Filter out jobs that don't match...
4531 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
4533 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0) &&
4534 (job
->printer
== NULL
|| dest
== NULL
||
4535 strcmp(job
->printer
->name
, dest
) != 0))
4537 if ((job
->dtype
& dmask
) != dtype
&&
4538 (job
->printer
== NULL
|| (job
->printer
->type
& dmask
) != dtype
))
4540 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
4543 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
4546 if (job
->id
< first
)
4551 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
4554 * Send the requested attributes for each job...
4557 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4558 LocalPort
, job
->id
);
4560 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4561 "job-more-info", NULL
, job_uri
);
4563 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4564 "job-uri", NULL
, job_uri
);
4566 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4567 "job-printer-up-time", time(NULL
));
4570 * Copy the job attributes to the response using the requested-attributes
4571 * attribute that may be provided by the client.
4574 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4576 add_job_state_reasons(con
, job
);
4578 ippAddSeparator(con
->response
);
4581 if (requested
!= NULL
)
4582 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4584 con
->response
->request
.status
.status_code
= IPP_OK
;
4589 * 'get_job_attrs()' - Get job attributes.
4593 get_job_attrs(client_t
*con
, /* I - Client connection */
4594 ipp_attribute_t
*uri
) /* I - Job URI */
4596 ipp_attribute_t
*attr
, /* Current attribute */
4597 *requested
; /* Requested attributes */
4598 int jobid
; /* Job ID */
4599 job_t
*job
; /* Current job */
4600 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4601 username
[HTTP_MAX_URI
], /* Username portion of URI */
4602 host
[HTTP_MAX_URI
], /* Host portion of URI */
4603 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4604 int port
; /* Port portion of URI */
4605 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4608 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4609 uri
->values
[0].string
.text
);
4612 * See if we have a job URI or a printer URI...
4615 if (strcmp(uri
->name
, "printer-uri") == 0)
4618 * Got a printer URI; see if we also have a job-id attribute...
4621 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4623 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
4624 send_ipp_error(con
, IPP_BAD_REQUEST
);
4628 jobid
= attr
->values
[0].integer
;
4633 * Got a job URI; parse it to get the job ID...
4636 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4638 if (strncmp(resource
, "/jobs/", 6) != 0)
4644 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
4645 uri
->values
[0].string
.text
);
4646 send_ipp_error(con
, IPP_BAD_REQUEST
);
4650 jobid
= atoi(resource
+ 6);
4654 * See if the job exists...
4657 if ((job
= FindJob(jobid
)) == NULL
)
4660 * Nope - return a "not found" error...
4663 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
4664 send_ipp_error(con
, IPP_NOT_FOUND
);
4672 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4674 LogMessage(L_ERROR
, "get_job_attrs: not authorized!");
4675 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4680 * Put out the standard attributes...
4683 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
4684 ServerName
, LocalPort
, job
->id
);
4686 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4688 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4689 "job-more-info", NULL
, job_uri
);
4691 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4692 "job-uri", NULL
, job_uri
);
4694 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4695 "job-printer-up-time", time(NULL
));
4698 * Copy the job attributes to the response using the requested-attributes
4699 * attribute that may be provided by the client.
4702 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4705 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4707 add_job_state_reasons(con
, job
);
4709 if (requested
!= NULL
)
4710 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4712 con
->response
->request
.status
.status_code
= IPP_OK
;
4717 * 'get_notifications()' - Get events for a subscription.
4721 get_notifications(client_t
*con
, /* I - Client connection */
4722 int id
) /* I - Subscription ID */
4728 * 'get_ppds()' - Get the list of PPD files on the local system.
4732 get_ppds(client_t
*con
) /* I - Client connection */
4734 int i
; /* Looping var */
4735 ipp_attribute_t
*limit
, /* Limit attribute */
4736 *make
, /* ppd-make attribute */
4737 *requested
; /* requested-attributes attribute */
4738 char command
[1024], /* cups-deviced command */
4739 options
[1024], /* Options to pass to command */
4740 attrs
[1024], /* String for requested attributes */
4741 *aptr
; /* Pointer into string */
4742 int alen
; /* Length of attribute value */
4745 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
4751 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4753 LogMessage(L_ERROR
, "get_ppds: not authorized!");
4754 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4759 * Run cups-driverd command with the given options...
4762 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
4763 make
= ippFindAttribute(con
->request
, "ppd-make", IPP_TAG_TEXT
);
4764 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4769 for (i
= 0, aptr
= attrs
; i
< requested
->num_values
; i
++)
4772 * Check that we have enough room...
4775 alen
= strlen(requested
->values
[i
].string
.text
);
4776 if (alen
> (sizeof(attrs
) - (aptr
- attrs
) - 2))
4780 * Put commas between values...
4787 * Add the value to the end of the string...
4790 strcpy(aptr
, requested
->values
[i
].string
.text
);
4795 * If we have more attribute names than will fit, default to "all"...
4798 if (i
< requested
->num_values
)
4799 strcpy(attrs
, "all");
4802 strcpy(attrs
, "all");
4804 snprintf(command
, sizeof(command
), "%s/daemon/cups-driverd", ServerBin
);
4805 snprintf(options
, sizeof(options
),
4806 "cups-driverd list+%d+%d+requested-attributes=%s%s%s",
4807 con
->request
->request
.op
.request_id
,
4808 limit
? limit
->values
[0].integer
: 0,
4810 make
? "%20ppd-make=" : "",
4811 make
? make
->values
[0].string
.text
: "");
4813 if (SendCommand(con
, command
, options
, 0))
4816 * Command started successfully, don't send an IPP response here...
4819 ippDelete(con
->response
);
4820 con
->response
= NULL
;
4825 * Command failed, return "internal error" so the user knows something
4829 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
4835 * 'get_printer_attrs()' - Get printer attributes.
4839 get_printer_attrs(client_t
*con
, /* I - Client connection */
4840 ipp_attribute_t
*uri
) /* I - Printer URI */
4842 const char *dest
; /* Destination */
4843 cups_ptype_t dtype
; /* Destination type (printer or class) */
4844 char method
[HTTP_MAX_URI
],
4845 /* Method portion of URI */
4846 username
[HTTP_MAX_URI
],
4847 /* Username portion of URI */
4849 /* Host portion of URI */
4850 resource
[HTTP_MAX_URI
];
4851 /* Resource portion of URI */
4852 int port
; /* Port portion of URI */
4853 printer_t
*printer
; /* Printer/class */
4854 char printer_uri
[HTTP_MAX_URI
];
4856 time_t curtime
; /* Current time */
4857 int i
; /* Looping var */
4858 ipp_attribute_t
*requested
, /* requested-attributes */
4859 *history
; /* History collection */
4860 int need_history
; /* Need to send history collection? */
4863 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4864 uri
->values
[0].string
.text
);
4867 * Is the destination valid?
4870 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4872 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4878 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
4879 send_ipp_error(con
, IPP_NOT_FOUND
);
4887 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4889 LogMessage(L_ERROR
, "get_printer_attrs: not authorized!");
4890 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4894 curtime
= time(NULL
);
4897 * Copy the printer attributes to the response using requested-attributes
4898 * and document-format attributes that may be provided by the client.
4901 if (!ippFindAttribute(printer
->attrs
, "printer-uri-supported",
4904 snprintf(printer_uri
, sizeof(printer_uri
), "ipp://%s:%d/printers/%s",
4905 con
->servername
, con
->serverport
, printer
->name
);
4906 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
4907 "printer-uri-supported", NULL
, printer_uri
);
4908 LogMessage(L_DEBUG2
, "printer-uri-supported=\"%s\"", printer_uri
);
4911 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4914 add_printer_state_reasons(con
, printer
);
4916 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4917 "printer-state-message", NULL
, printer
->state_message
);
4919 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4920 printer
->accepting
);
4921 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
4924 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4925 "printer-up-time", curtime
);
4926 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4927 "printer-state-time", printer
->state_time
);
4928 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4929 ippTimeToDate(curtime
));
4931 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4932 "printer-error-policy", NULL
, printer
->op_policy
);
4933 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4934 "printer-op-policy", NULL
, printer
->op_policy
);
4936 add_queued_job_count(con
, printer
);
4938 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4941 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4942 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4946 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 && requested
)
4948 for (i
= 0; i
< requested
->num_values
; i
++)
4949 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4950 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4959 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4960 "printer-state-history",
4961 printer
->num_history
, NULL
);
4963 for (i
= 0; i
< printer
->num_history
; i
++)
4964 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4965 NULL
, IPP_TAG_ZERO
, 0);
4968 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4973 * 'get_printers()' - Get a list of printers or classes.
4977 get_printers(client_t
*con
, /* I - Client connection */
4978 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
4980 int i
; /* Looping var */
4981 ipp_attribute_t
*requested
, /* requested-attributes */
4982 *history
, /* History collection */
4983 *attr
; /* Current attribute */
4984 int need_history
; /* Need to send history collection? */
4985 int limit
; /* Maximum number of printers to return */
4986 int count
; /* Number of printers that match */
4987 printer_t
*printer
; /* Current printer pointer */
4988 time_t curtime
; /* Current time */
4989 int printer_type
, /* printer-type attribute */
4990 printer_mask
; /* printer-type-mask attribute */
4991 char *location
; /* Location string */
4992 char name
[IPP_MAX_NAME
], /* Printer name */
4993 *nameptr
; /* Pointer into name */
4994 printer_t
*iclass
; /* Implicit class */
4995 const char *username
; /* Current user */
4996 char printer_uri
[HTTP_MAX_URI
];
5000 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
5002 if (!Printers
|| !cupsArrayCount(Printers
))
5004 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
5012 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
5014 LogMessage(L_ERROR
, "get_printers: not authorized!");
5015 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5020 * See if they want to limit the number of printers reported...
5023 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
5024 limit
= attr
->values
[0].integer
;
5029 * Support filtering...
5032 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
5033 printer_type
= attr
->values
[0].integer
;
5037 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
5038 printer_mask
= attr
->values
[0].integer
;
5042 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
5043 location
= attr
->values
[0].string
.text
;
5047 if (con
->username
[0])
5048 username
= con
->username
;
5049 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
5050 username
= attr
->values
[0].string
.text
;
5054 requested
= ippFindAttribute(con
->request
, "requested-attributes",
5059 if (MaxPrinterHistory
> 0 && requested
)
5061 for (i
= 0; i
< requested
->num_values
; i
++)
5062 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
5063 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
5071 * OK, build a list of printers for this printer...
5074 curtime
= time(NULL
);
5076 for (count
= 0, printer
= (printer_t
*)cupsArrayFirst(Printers
);
5077 count
< limit
&& printer
!= NULL
;
5078 printer
= (printer_t
*)cupsArrayNext(Printers
))
5079 if ((!type
|| (printer
->type
& CUPS_PRINTER_CLASS
) == type
) &&
5080 (printer
->type
& printer_mask
) == printer_type
&&
5081 (location
== NULL
|| printer
->location
== NULL
||
5082 !strcasecmp(printer
->location
, location
)))
5085 * If HideImplicitMembers is enabled, see if this printer or class
5086 * is a member of an implicit class...
5089 if (ImplicitClasses
&& HideImplicitMembers
&&
5090 (printer
->type
& CUPS_PRINTER_REMOTE
))
5093 * Make a copy of the printer name...
5096 strlcpy(name
, printer
->name
, sizeof(name
));
5098 if ((nameptr
= strchr(name
, '@')) != NULL
)
5101 * Strip trailing @server...
5107 * Find the core printer, if any...
5110 if ((iclass
= FindPrinter(name
)) != NULL
&&
5111 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
5117 * If a username is specified, see if it is allowed or denied
5121 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
5125 * Add the group separator as needed...
5129 ippAddSeparator(con
->response
);
5134 * Send the following attributes for each printer:
5137 * printer-state-message
5138 * printer-is-accepting-jobs
5141 * printer-state-time
5142 * + all printer attributes
5145 if (!ippFindAttribute(printer
->attrs
, "printer-uri-supported",
5148 snprintf(printer_uri
, sizeof(printer_uri
), "ipp://%s:%d/printers/%s",
5149 con
->servername
, con
->serverport
, printer
->name
);
5150 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
5151 "printer-uri-supported", NULL
, printer_uri
);
5152 LogMessage(L_DEBUG2
, "printer-uri-supported=\"%s\"", printer_uri
);
5155 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
5156 "printer-state", printer
->state
);
5158 add_printer_state_reasons(con
, printer
);
5160 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
5161 "printer-state-message", NULL
, printer
->state_message
);
5163 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
5164 printer
->accepting
);
5165 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
5168 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
5169 "printer-up-time", curtime
);
5170 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
5171 "printer-state-time", printer
->state_time
);
5172 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
5173 ippTimeToDate(curtime
));
5175 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
5176 "printer-error-policy", NULL
, printer
->op_policy
);
5177 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
5178 "printer-op-policy", NULL
, printer
->op_policy
);
5180 add_queued_job_count(con
, printer
);
5182 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
5184 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
,
5187 if (need_history
&& printer
->num_history
> 0)
5189 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
5190 "printer-state-history",
5191 printer
->num_history
, NULL
);
5193 for (i
= 0; i
< printer
->num_history
; i
++)
5194 copy_attrs(history
->values
[i
].collection
= ippNew(),
5195 printer
->history
[i
], NULL
, IPP_TAG_ZERO
, 0);
5199 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
5204 * 'get_subscription_attrs()' - Get subscription attributes.
5208 get_subscription_attrs(client_t
*con
, /* I - Client connection */
5209 int sub_id
) /* I - Subscription ID */
5215 * 'get_subscriptions()' - Get subscriptions.
5219 get_subscriptions(client_t
*con
, /* I - Client connection */
5220 ipp_attribute_t
*uri
) /* I - Printer URI */
5226 * 'hold_job()' - Hold a print job.
5230 hold_job(client_t
*con
, /* I - Client connection */
5231 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
5233 ipp_attribute_t
*attr
, /* Current job-hold-until */
5234 *newattr
; /* New job-hold-until */
5235 int jobid
; /* Job ID */
5236 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5237 username
[HTTP_MAX_URI
], /* Username portion of URI */
5238 host
[HTTP_MAX_URI
], /* Host portion of URI */
5239 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5240 int port
; /* Port portion of URI */
5241 job_t
*job
; /* Job information */
5244 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5245 uri
->values
[0].string
.text
);
5248 * Verify that the POST operation was done to a valid URI.
5251 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5252 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
5253 strncmp(con
->uri
, "/printers/", 10) != 0)
5255 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
5257 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5262 * See if we have a job URI or a printer URI...
5265 if (strcmp(uri
->name
, "printer-uri") == 0)
5268 * Got a printer URI; see if we also have a job-id attribute...
5271 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
5273 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
5274 send_ipp_error(con
, IPP_BAD_REQUEST
);
5278 jobid
= attr
->values
[0].integer
;
5283 * Got a job URI; parse it to get the job ID...
5286 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5288 if (strncmp(resource
, "/jobs/", 6) != 0)
5294 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
5295 uri
->values
[0].string
.text
);
5296 send_ipp_error(con
, IPP_BAD_REQUEST
);
5300 jobid
= atoi(resource
+ 6);
5304 * See if the job exists...
5307 if ((job
= FindJob(jobid
)) == NULL
)
5310 * Nope - return a "not found" error...
5313 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
5314 send_ipp_error(con
, IPP_NOT_FOUND
);
5319 * See if the job is owned by the requesting user...
5322 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
5324 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
5325 username
, jobid
, job
->username
);
5326 send_ipp_error(con
, IPP_FORBIDDEN
);
5331 * Hold the job and return...
5336 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5337 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
5339 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5340 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
5345 * Free the old hold value and copy the new one over...
5348 free(attr
->values
[0].string
.text
);
5350 if (newattr
!= NULL
)
5352 attr
->value_tag
= newattr
->value_tag
;
5353 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
5357 attr
->value_tag
= IPP_TAG_KEYWORD
;
5358 attr
->values
[0].string
.text
= strdup("indefinite");
5362 * Hold job until specified time...
5365 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5368 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
5370 con
->response
->request
.status
.status_code
= IPP_OK
;
5375 * 'move_job()' - Move a job to a new destination.
5379 move_job(client_t
*con
, /* I - Client connection */
5380 ipp_attribute_t
*uri
) /* I - Job URI */
5382 ipp_attribute_t
*attr
; /* Current attribute */
5383 int jobid
; /* Job ID */
5384 job_t
*job
; /* Current job */
5385 const char *dest
; /* Destination */
5386 cups_ptype_t dtype
; /* Destination type (printer or class) */
5387 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5388 username
[HTTP_MAX_URI
], /* Username portion of URI */
5389 host
[HTTP_MAX_URI
], /* Host portion of URI */
5390 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5391 int port
; /* Port portion of URI */
5392 printer_t
*printer
; /* Printer */
5395 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5396 uri
->values
[0].string
.text
);
5399 * See if we have a job URI or a printer URI...
5402 if (strcmp(uri
->name
, "printer-uri") == 0)
5405 * Got a printer URI; see if we also have a job-id attribute...
5408 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
5410 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
5411 send_ipp_error(con
, IPP_BAD_REQUEST
);
5415 jobid
= attr
->values
[0].integer
;
5420 * Got a job URI; parse it to get the job ID...
5423 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5425 if (strncmp(resource
, "/jobs/", 6) != 0)
5431 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
5432 uri
->values
[0].string
.text
);
5433 send_ipp_error(con
, IPP_BAD_REQUEST
);
5437 jobid
= atoi(resource
+ 6);
5441 * See if the job exists...
5444 if ((job
= FindJob(jobid
)) == NULL
)
5447 * Nope - return a "not found" error...
5450 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
5451 send_ipp_error(con
, IPP_NOT_FOUND
);
5456 * See if the job has been completed...
5459 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
5462 * Return a "not-possible" error...
5465 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
5466 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5471 * See if the job is owned by the requesting user...
5474 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
5476 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
5477 username
, jobid
, job
->username
);
5478 send_ipp_error(con
, IPP_FORBIDDEN
);
5482 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
5485 * Need job-printer-uri...
5488 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
5489 send_ipp_error(con
, IPP_BAD_REQUEST
);
5494 * Get the new printer or class...
5497 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
5499 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5505 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
5506 send_ipp_error(con
, IPP_NOT_FOUND
);
5514 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5516 LogMessage(L_ERROR
, "move_job: not authorized!");
5517 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5522 * Move the job to a different printer or class...
5525 MoveJob(jobid
, dest
);
5528 * Start jobs if possible...
5534 * Return with "everything is OK" status...
5537 con
->response
->request
.status
.status_code
= IPP_OK
;
5542 * 'ppd_add_default()' - Add a PPD default choice.
5545 static int /* O - Number of defaults */
5547 const char *option
, /* I - Option name */
5548 const char *choice
, /* I - Choice name */
5549 int num_defaults
, /* I - Number of defaults */
5550 ppd_default_t
**defaults
) /* IO - Defaults */
5552 int i
; /* Looping var */
5553 ppd_default_t
*temp
; /* Temporary defaults array */
5557 * First check if the option already has a default value; the PPD spec
5558 * says that the first one is used...
5561 for (i
= 0, temp
= *defaults
; i
< num_defaults
; i
++)
5562 if (!strcmp(option
, temp
[i
].option
))
5563 return (num_defaults
);
5566 * Now add the option...
5569 if (num_defaults
== 0)
5570 temp
= malloc(sizeof(ppd_default_t
));
5572 temp
= realloc(*defaults
, (num_defaults
+ 1) * sizeof(ppd_default_t
));
5576 LogMessage(L_ERROR
, "ppd_add_default: Unable to add default value for \"%s\" - %s",
5577 option
, strerror(errno
));
5578 return (num_defaults
);
5582 temp
+= num_defaults
;
5584 strlcpy(temp
->option
, option
, sizeof(temp
->option
));
5585 strlcpy(temp
->choice
, choice
, sizeof(temp
->choice
));
5587 return (num_defaults
+ 1);
5592 * 'ppd_parse_line()' - Parse a PPD default line.
5595 static int /* O - 0 on success, -1 on failure */
5596 ppd_parse_line(const char *line
, /* I - Line */
5597 char *option
, /* O - Option name */
5598 int olen
, /* I - Size of option name */
5599 char *choice
, /* O - Choice name */
5600 int clen
) /* I - Size of choice name */
5603 * Verify this is a default option line...
5606 if (strncmp(line
, "*Default", 8))
5610 * Read the option name...
5613 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
5623 * Skip everything else up to the colon (:)...
5626 while (*line
&& *line
!= ':')
5635 * Now grab the option choice, skipping leading whitespace...
5638 while (isspace(*line
& 255))
5641 for (clen
--; isalnum(*line
& 255); line
++)
5651 * Return with no errors...
5659 * 'print_job()' - Print a file to a printer or class.
5663 print_job(client_t
*con
, /* I - Client connection */
5664 ipp_attribute_t
*uri
) /* I - Printer URI */
5666 ipp_attribute_t
*attr
; /* Current attribute */
5667 ipp_attribute_t
*format
; /* Document-format attribute */
5668 const char *dest
; /* Destination */
5669 cups_ptype_t dtype
; /* Destination type (printer or class) */
5670 int priority
; /* Job priority */
5671 char *title
; /* Job name/title */
5672 job_t
*job
; /* Current job */
5673 int jobid
; /* Job ID number */
5674 char job_uri
[HTTP_MAX_URI
], /* Job URI */
5675 method
[HTTP_MAX_URI
], /* Method portion of URI */
5676 username
[HTTP_MAX_URI
], /* Username portion of URI */
5677 host
[HTTP_MAX_URI
], /* Host portion of URI */
5678 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5679 filename
[1024]; /* Job filename */
5680 int port
; /* Port portion of URI */
5681 mime_type_t
*filetype
; /* Type of file */
5682 char super
[MIME_MAX_SUPER
], /* Supertype of file */
5683 type
[MIME_MAX_TYPE
], /* Subtype of file */
5684 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
5685 /* Textual name of mime type */
5686 printer_t
*printer
; /* Printer data */
5687 struct stat fileinfo
; /* File information */
5688 int kbytes
; /* Size of file */
5689 int i
; /* Looping var */
5690 int lowerpagerange
; /* Page range bound */
5691 int compression
; /* Document compression */
5694 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5695 uri
->values
[0].string
.text
);
5698 * Verify that the POST operation was done to a valid URI.
5701 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5702 strncmp(con
->uri
, "/printers/", 10) != 0)
5704 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
5706 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5711 * Validate job template attributes; for now just copies and page-ranges...
5714 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
5716 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
5718 LogMessage(L_ERROR
, "print_job: Bad copies value %d.",
5719 attr
->values
[0].integer
);
5720 send_ipp_error(con
, IPP_ATTRIBUTES
);
5721 ippAddInteger(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_INTEGER
,
5722 "copies", attr
->values
[0].integer
);
5727 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
5729 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
5731 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
5732 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5734 LogMessage(L_ERROR
, "print_job: bad page-ranges values %d-%d.",
5735 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
5736 send_ipp_error(con
, IPP_BAD_REQUEST
);
5740 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
5745 * OK, see if the client is sending the document compressed - CUPS
5746 * only supports "none" and "gzip".
5749 compression
= CUPS_FILE_NONE
;
5751 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
5753 if (strcmp(attr
->values
[0].string
.text
, "none")
5755 && strcmp(attr
->values
[0].string
.text
, "gzip")
5756 #endif /* HAVE_LIBZ */
5759 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
5760 attr
->values
[0].string
.text
);
5761 send_ipp_error(con
, IPP_ATTRIBUTES
);
5762 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5763 "compression", NULL
, attr
->values
[0].string
.text
);
5768 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
5769 compression
= CUPS_FILE_GZIP
;
5770 #endif /* HAVE_LIBZ */
5774 * Do we have a file to print?
5779 LogMessage(L_ERROR
, "print_job: No file!?!");
5780 send_ipp_error(con
, IPP_BAD_REQUEST
);
5785 * Is it a format we support?
5788 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5791 * Grab format from client...
5794 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5796 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
5797 format
->values
[0].string
.text
);
5798 send_ipp_error(con
, IPP_BAD_REQUEST
);
5805 * No document format attribute? Auto-type it!
5808 strcpy(super
, "application");
5809 strcpy(type
, "octet-stream");
5812 if (!strcmp(super
, "application") && !strcmp(type
, "octet-stream"))
5815 * Auto-type the file...
5818 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
5820 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
5822 if (filetype
!= NULL
)
5825 * Replace the document-format attribute value with the auto-typed one.
5828 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
5833 free(format
->values
[0].string
.text
);
5834 format
->values
[0].string
.text
= strdup(mimetype
);
5837 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
5838 "document-format", NULL
, mimetype
);
5841 filetype
= mimeType(MimeDatabase
, super
, type
);
5844 filetype
= mimeType(MimeDatabase
, super
, type
);
5846 if (filetype
== NULL
)
5848 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
5850 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
5851 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5854 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5855 "document-format", NULL
, format
->values
[0].string
.text
);
5860 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
5861 filetype
->super
, filetype
->type
);
5864 * Read any embedded job ticket info from PS files...
5867 if (!strcasecmp(filetype
->super
, "application") &&
5868 !strcasecmp(filetype
->type
, "postscript"))
5869 read_ps_job_ticket(con
);
5872 * Is the destination valid?
5875 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5877 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5883 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
5884 send_ipp_error(con
, IPP_NOT_FOUND
);
5889 * Check remote printing to non-shared printer...
5892 if (!printer
->shared
&&
5893 strcasecmp(con
->http
.hostname
, "localhost") &&
5894 strcasecmp(con
->http
.hostname
, ServerName
))
5896 LogMessage(L_ERROR
, "print_job: printer not shared!");
5897 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5905 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
) ||
5906 ((printer
->type
& CUPS_PRINTER_AUTHENTICATED
) && !con
->username
[0]))
5908 LogMessage(L_ERROR
, "print_job: not authorized!");
5909 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5914 * See if the printer is accepting jobs...
5917 if (!printer
->accepting
)
5919 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
5921 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
5926 * Make sure we aren't over our limit...
5929 if (cupsArrayCount(Jobs
) >= MaxJobs
&& MaxJobs
)
5932 if (cupsArrayCount(Jobs
) >= MaxJobs
&& MaxJobs
)
5934 LogMessage(L_INFO
, "print_job: too many jobs - %d jobs, max jobs is %d.",
5935 cupsArrayCount(Jobs
), MaxJobs
);
5936 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5940 if (!check_quotas(con
, printer
))
5942 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5947 * Create the job and set things up...
5950 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
5951 priority
= attr
->values
[0].integer
;
5953 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
5956 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
5957 title
= attr
->values
[0].string
.text
;
5959 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5960 title
= "Untitled");
5962 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
5964 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
5966 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
5971 job
->attrs
= con
->request
;
5972 con
->request
= NULL
;
5975 * Copy the rest of the job info...
5978 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
5980 if (con
->username
[0])
5982 SetString(&job
->username
, con
->username
);
5983 save_auth_info(con
, job
->id
);
5985 else if (attr
!= NULL
)
5987 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
5988 attr
->values
[0].string
.text
);
5990 SetString(&job
->username
, attr
->values
[0].string
.text
);
5993 SetString(&job
->username
, "anonymous");
5996 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
5997 NULL
, job
->username
);
6000 attr
->group_tag
= IPP_TAG_JOB
;
6001 SetString(&attr
->name
, "job-originating-user-name");
6005 * Add remaining job attributes...
6008 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
6009 IPP_TAG_ZERO
)) != NULL
)
6012 * Request contains a job-originating-host-name attribute; validate it...
6015 if (attr
->value_tag
!= IPP_TAG_NAME
||
6016 attr
->num_values
!= 1 ||
6017 strcmp(con
->http
.hostname
, "localhost") != 0)
6020 * Can't override the value if we aren't connected via localhost.
6021 * Also, we can only have 1 value and it must be a name value.
6024 switch (attr
->value_tag
)
6026 case IPP_TAG_STRING
:
6027 case IPP_TAG_TEXTLANG
:
6028 case IPP_TAG_NAMELANG
:
6031 case IPP_TAG_KEYWORD
:
6033 case IPP_TAG_URISCHEME
:
6034 case IPP_TAG_CHARSET
:
6035 case IPP_TAG_LANGUAGE
:
6036 case IPP_TAG_MIMETYPE
:
6038 * Free old strings...
6041 for (i
= 0; i
< attr
->num_values
; i
++)
6043 free(attr
->values
[i
].string
.text
);
6044 attr
->values
[i
].string
.text
= NULL
;
6045 if (attr
->values
[i
].string
.charset
)
6047 free(attr
->values
[i
].string
.charset
);
6048 attr
->values
[i
].string
.charset
= NULL
;
6057 * Use the default connection hostname instead...
6060 attr
->value_tag
= IPP_TAG_NAME
;
6061 attr
->num_values
= 1;
6062 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
6065 attr
->group_tag
= IPP_TAG_JOB
;
6070 * No job-originating-host-name attribute, so use the hostname from
6074 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
6075 "job-originating-host-name", NULL
, con
->http
.hostname
);
6078 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
6079 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
6080 "job-state", IPP_JOB_PENDING
);
6081 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
6082 "job-media-sheets-completed", 0);
6083 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
6085 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
6088 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
6089 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
6092 if (stat(con
->filename
, &fileinfo
))
6095 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6097 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6098 attr
->values
[0].integer
+= kbytes
;
6100 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
6102 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
6103 "time-at-processing", 0);
6104 attr
->value_tag
= IPP_TAG_NOVALUE
;
6105 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
6106 "time-at-completed", 0);
6107 attr
->value_tag
= IPP_TAG_NOVALUE
;
6109 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6110 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6112 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
6113 "job-hold-until", NULL
, "no-hold");
6115 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
6116 !(printer
->type
& CUPS_PRINTER_REMOTE
))
6119 * Hold job until specified time...
6122 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
6123 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
6126 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
6130 * Add job sheets options...
6133 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
6135 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
6136 printer
->job_sheets
[0], printer
->job_sheets
[1]);
6138 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
6140 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
6141 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
6144 job
->job_sheets
= attr
;
6147 * Enforce classification level if set...
6152 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
6153 Classification
? Classification
: "(null)", ClassifyOverride
);
6155 if (ClassifyOverride
)
6157 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
6158 (attr
->num_values
== 1 ||
6159 strcmp(attr
->values
[1].string
.text
, "none") == 0))
6162 * Force the leading banner to have the classification on it...
6165 SetString(&attr
->values
[0].string
.text
, Classification
);
6167 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
6168 "job-sheets=\"%s,none\", "
6169 "job-originating-user-name=\"%s\"",
6170 job
->id
, Classification
,
6173 else if (attr
->num_values
== 2 &&
6174 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
6175 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
6176 strcmp(attr
->values
[1].string
.text
, "none") != 0)
6179 * Can't put two different security markings on the same document!
6182 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
6184 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
6185 "job-sheets=\"%s,%s\", "
6186 "job-originating-user-name=\"%s\"",
6187 job
->id
, attr
->values
[0].string
.text
,
6188 attr
->values
[1].string
.text
,
6191 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
6192 strcmp(attr
->values
[0].string
.text
, "none") &&
6193 (attr
->num_values
== 1 ||
6194 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
6195 strcmp(attr
->values
[1].string
.text
, "none"))))
6197 if (attr
->num_values
== 1)
6198 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
6199 "job-sheets=\"%s\", "
6200 "job-originating-user-name=\"%s\"",
6201 job
->id
, attr
->values
[0].string
.text
,
6204 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
6205 "job-sheets=\"%s,%s\", "
6206 "job-originating-user-name=\"%s\"",
6207 job
->id
, attr
->values
[0].string
.text
,
6208 attr
->values
[1].string
.text
,
6212 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
6213 (attr
->num_values
== 1 ||
6214 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
6217 * Force the banner to have the classification on it...
6220 if (attr
->num_values
> 1 &&
6221 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
6223 SetString(&(attr
->values
[0].string
.text
), Classification
);
6224 SetString(&(attr
->values
[1].string
.text
), Classification
);
6228 if (attr
->num_values
== 1 ||
6229 strcmp(attr
->values
[0].string
.text
, "none"))
6230 SetString(&(attr
->values
[0].string
.text
), Classification
);
6232 if (attr
->num_values
> 1 &&
6233 strcmp(attr
->values
[1].string
.text
, "none"))
6234 SetString(&(attr
->values
[1].string
.text
), Classification
);
6237 if (attr
->num_values
> 1)
6238 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
6239 "job-sheets=\"%s,%s\", "
6240 "job-originating-user-name=\"%s\"",
6241 job
->id
, attr
->values
[0].string
.text
,
6242 attr
->values
[1].string
.text
,
6245 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
6246 "job-sheets=\"%s\", "
6247 "job-originating-user-name=\"%s\"",
6248 job
->id
, Classification
,
6254 * Add the starting sheet...
6257 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
6259 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
6260 attr
->values
[0].string
.text
, job
->id
);
6262 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
6264 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6267 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
6271 * Add the job file...
6274 if (add_file(con
, job
, filetype
, compression
))
6277 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6279 rename(con
->filename
, filename
);
6280 ClearString(&con
->filename
);
6283 * See if we need to add the ending sheet...
6286 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6287 attr
->num_values
> 1)
6293 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
6294 attr
->values
[1].string
.text
, job
->id
);
6296 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6298 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6302 * Add any job subscriptions...
6305 add_job_subscriptions(con
, job
);
6308 * Set all but the first two attributes to the job attributes group...
6311 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
6312 attr
->group_tag
= IPP_TAG_JOB
;
6315 * Log and save the job...
6318 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
6319 job
->dest
, job
->username
);
6320 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, (int)job
->hold_until
);
6324 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
6327 * Start the job if possible... Since CheckJobs() can cancel a job if it
6328 * doesn't print, we need to re-find the job afterwards...
6335 job
= FindJob(jobid
);
6338 * Fill in the response info...
6341 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
6344 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
6346 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
6348 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
6349 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
6350 add_job_state_reasons(con
, job
);
6352 con
->response
->request
.status
.status_code
= IPP_OK
;
6357 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
6359 * This function only gets called when printing a single PostScript
6360 * file using the Print-Job operation. It doesn't work for Create-Job +
6361 * Send-File, since the job attributes need to be set at job creation
6362 * time for banners to work. The embedded PS job ticket stuff is here
6363 * only to allow the Windows printer driver for CUPS to pass in JCL
6364 * options and IPP attributes which otherwise would be lost.
6366 * The format of a PS job ticket is simple:
6368 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
6370 * %cupsJobTicket: attr1=value1
6371 * %cupsJobTicket: attr2=value2
6373 * %cupsJobTicket: attrN=valueN
6375 * Job ticket lines must appear immediately after the first line that
6376 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
6377 * looking for job ticket info when it finds a line that does not begin
6378 * with "%cupsJobTicket:".
6380 * The maximum length of a job ticket line, including the prefix, is
6381 * 255 characters to conform with the Adobe DSC.
6383 * Read-only attributes are rejected with a notice to the error log in
6384 * case a malicious user tries anything. Since the job ticket is read
6385 * prior to attribute validation in print_job(), job ticket attributes
6386 * will go through the same validation as IPP attributes...
6390 read_ps_job_ticket(client_t
*con
) /* I - Client connection */
6392 cups_file_t
*fp
; /* File to read from */
6393 char line
[256]; /* Line data */
6394 int num_options
; /* Number of options */
6395 cups_option_t
*options
; /* Options */
6396 ipp_t
*ticket
; /* New attributes */
6397 ipp_attribute_t
*attr
, /* Current attribute */
6398 *attr2
, /* Job attribute */
6399 *prev2
; /* Previous job attribute */
6403 * First open the print file...
6406 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
6408 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to open PostScript print file - %s",
6414 * Skip the first line...
6417 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
6419 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to read from PostScript print file - %s",
6425 if (strncmp(line
, "%!PS-Adobe-", 11) != 0)
6428 * Not a DSC-compliant file, so no job ticket info will be available...
6436 * Read job ticket info from the file...
6442 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
6445 * Stop at the first non-ticket line...
6448 if (strncmp(line
, "%cupsJobTicket:", 15) != 0)
6452 * Add the options to the option array...
6455 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
6459 * Done with the file; see if we have any options...
6464 if (num_options
== 0)
6468 * OK, convert the options to an attribute list, and apply them to
6473 cupsEncodeOptions(ticket
, num_options
, options
);
6476 * See what the user wants to change.
6479 for (attr
= ticket
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6481 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6484 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
6485 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
6486 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
6487 strcmp(attr
->name
, "job-k-octets") == 0 ||
6488 strcmp(attr
->name
, "job-id") == 0 ||
6489 strncmp(attr
->name
, "job-state", 9) == 0 ||
6490 strncmp(attr
->name
, "time-at-", 8) == 0)
6491 continue; /* Read-only attrs */
6493 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
6496 * Some other value; first free the old value...
6499 if (con
->request
->attrs
== attr2
)
6501 con
->request
->attrs
= attr2
->next
;
6506 for (prev2
= con
->request
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
6507 if (prev2
->next
== attr2
)
6509 prev2
->next
= attr2
->next
;
6514 if (con
->request
->last
== attr2
)
6515 con
->request
->last
= prev2
;
6517 _ipp_free_attr(attr2
);
6521 * Add new option by copying it...
6524 copy_attribute(con
->request
, attr
, 0);
6528 * Then free the attribute list and option array...
6532 cupsFreeOptions(num_options
, options
);
6537 * 'reject_jobs()' - Reject print jobs to a printer.
6541 reject_jobs(client_t
*con
, /* I - Client connection */
6542 ipp_attribute_t
*uri
) /* I - Printer or class URI */
6544 cups_ptype_t dtype
; /* Destination type (printer or class) */
6545 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6546 username
[HTTP_MAX_URI
], /* Username portion of URI */
6547 host
[HTTP_MAX_URI
], /* Host portion of URI */
6548 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6549 int port
; /* Port portion of URI */
6550 const char *name
; /* Printer name */
6551 printer_t
*printer
; /* Printer data */
6552 ipp_attribute_t
*attr
; /* printer-state-message text */
6555 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
6556 uri
->values
[0].string
.text
);
6559 * Was this operation called from the correct URI?
6562 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6564 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
6566 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6571 * Is the destination valid?
6574 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6576 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6582 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
6583 send_ipp_error(con
, IPP_NOT_FOUND
);
6591 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
6593 LogMessage(L_ERROR
, "reject_jobs: not authorized!");
6594 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6599 * Reject jobs sent to the printer...
6602 printer
->accepting
= 0;
6604 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
6605 IPP_TAG_TEXT
)) == NULL
)
6606 strcpy(printer
->state_message
, "Rejecting Jobs");
6608 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
6609 sizeof(printer
->state_message
));
6611 AddPrinterHistory(printer
);
6613 if (dtype
& CUPS_PRINTER_CLASS
)
6617 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
6624 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
6629 * Everything was ok, so return OK status...
6632 con
->response
->request
.status
.status_code
= IPP_OK
;
6637 * 'release_job()' - Release a held print job.
6641 release_job(client_t
*con
, /* I - Client connection */
6642 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6644 ipp_attribute_t
*attr
; /* Current attribute */
6645 int jobid
; /* Job ID */
6646 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6647 username
[HTTP_MAX_URI
], /* Username portion of URI */
6648 host
[HTTP_MAX_URI
], /* Host portion of URI */
6649 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6650 int port
; /* Port portion of URI */
6651 job_t
*job
; /* Job information */
6654 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6655 uri
->values
[0].string
.text
);
6658 * Verify that the POST operation was done to a valid URI.
6661 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6662 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6663 strncmp(con
->uri
, "/printers/", 10) != 0)
6665 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
6667 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6672 * See if we have a job URI or a printer URI...
6675 if (strcmp(uri
->name
, "printer-uri") == 0)
6678 * Got a printer URI; see if we also have a job-id attribute...
6681 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6683 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
6684 send_ipp_error(con
, IPP_BAD_REQUEST
);
6688 jobid
= attr
->values
[0].integer
;
6693 * Got a job URI; parse it to get the job ID...
6696 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6698 if (strncmp(resource
, "/jobs/", 6) != 0)
6704 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
6705 uri
->values
[0].string
.text
);
6706 send_ipp_error(con
, IPP_BAD_REQUEST
);
6710 jobid
= atoi(resource
+ 6);
6714 * See if the job exists...
6717 if ((job
= FindJob(jobid
)) == NULL
)
6720 * Nope - return a "not found" error...
6723 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
6724 send_ipp_error(con
, IPP_NOT_FOUND
);
6729 * See if job is "held"...
6732 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
6735 * Nope - return a "not possible" error...
6738 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
6739 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6744 * See if the job is owned by the requesting user...
6747 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6749 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
6750 username
, jobid
, job
->username
);
6751 send_ipp_error(con
, IPP_FORBIDDEN
);
6756 * Reset the job-hold-until value to "no-hold"...
6759 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6760 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6764 free(attr
->values
[0].string
.text
);
6765 attr
->value_tag
= IPP_TAG_KEYWORD
;
6766 attr
->values
[0].string
.text
= strdup("no-hold");
6770 * Release the job and return...
6775 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
6777 con
->response
->request
.status
.status_code
= IPP_OK
;
6782 * 'renew_subscription()' - Renew an existing subscription...
6786 renew_subscription(client_t
*con
, /* I - Client connection */
6787 int sub_id
) /* I - Subscription ID */
6793 * 'restart_job()' - Restart an old print job.
6797 restart_job(client_t
*con
, /* I - Client connection */
6798 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6800 ipp_attribute_t
*attr
; /* Current attribute */
6801 int jobid
; /* Job ID */
6802 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6803 username
[HTTP_MAX_URI
], /* Username portion of URI */
6804 host
[HTTP_MAX_URI
], /* Host portion of URI */
6805 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6806 int port
; /* Port portion of URI */
6807 job_t
*job
; /* Job information */
6810 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6811 uri
->values
[0].string
.text
);
6814 * Verify that the POST operation was done to a valid URI.
6817 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6818 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6819 strncmp(con
->uri
, "/printers/", 10) != 0)
6821 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
6823 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6828 * See if we have a job URI or a printer URI...
6831 if (strcmp(uri
->name
, "printer-uri") == 0)
6834 * Got a printer URI; see if we also have a job-id attribute...
6837 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6839 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
6840 send_ipp_error(con
, IPP_BAD_REQUEST
);
6844 jobid
= attr
->values
[0].integer
;
6849 * Got a job URI; parse it to get the job ID...
6852 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6854 if (strncmp(resource
, "/jobs/", 6) != 0)
6860 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
6861 uri
->values
[0].string
.text
);
6862 send_ipp_error(con
, IPP_BAD_REQUEST
);
6866 jobid
= atoi(resource
+ 6);
6870 * See if the job exists...
6873 if ((job
= FindJob(jobid
)) == NULL
)
6876 * Nope - return a "not found" error...
6879 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
6880 send_ipp_error(con
, IPP_NOT_FOUND
);
6885 * See if job is in any of the "completed" states...
6888 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
6891 * Nope - return a "not possible" error...
6894 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
6895 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6900 * See if we have retained the job files...
6903 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6906 * Nope - return a "not possible" error...
6909 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
6910 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6915 * See if the job is owned by the requesting user...
6918 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6920 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
6921 username
, jobid
, job
->username
);
6922 send_ipp_error(con
, IPP_FORBIDDEN
);
6927 * Restart the job and return...
6932 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
6934 con
->response
->request
.status
.status_code
= IPP_OK
;
6939 * 'save_auth_info()' - Save authentication information for a job.
6943 save_auth_info(client_t
*con
, /* I - Client connection */
6944 int job_id
) /* I - Job ID */
6946 int i
; /* Looping var */
6947 char filename
[1024]; /* Job authentication filename */
6948 cups_file_t
*fp
; /* Job authentication file */
6949 char line
[1024]; /* Line for file */
6953 * This function saves the in-memory authentication information for
6954 * a job so that it can be used to authenticate with a remote host.
6955 * The information is stored in a file that is readable only by the
6956 * root user. The username and password are Base-64 encoded, each
6957 * on a separate line, followed by random number (up to 1024) of
6958 * newlines to limit the amount of information that is exposed.
6960 * Because of the potential for exposing of authentication information,
6961 * this functionality is only enabled when running cupsd as root.
6963 * This caching only works for the Basic and BasicDigest authentication
6964 * types. Digest authentication cannot be cached this way, and in
6965 * the future Kerberos authentication may make all of this obsolete.
6967 * Authentication information is saved whenever an authenticated
6968 * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
6971 * This information is deleted after a job is completed or canceled,
6972 * so reprints may require subsequent re-authentication.
6979 * Create the authentication file and change permissions...
6982 snprintf(filename
, sizeof(filename
), "%s/a%05d", RequestRoot
, job_id
);
6983 if ((fp
= cupsFileOpen(filename
, "w")) == NULL
)
6985 LogMessage(L_ERROR
, "Unable to save authentication info to \"%s\" - %s",
6986 filename
, strerror(errno
));
6990 fchown(cupsFileNumber(fp
), 0, 0);
6991 fchmod(cupsFileNumber(fp
), 0400);
6994 * Write the authenticated username...
6997 httpEncode64_2(line
, sizeof(line
), con
->username
, strlen(con
->username
));
6998 cupsFilePrintf(fp
, "%s\n", line
);
7001 * Write the authenticated password...
7004 httpEncode64_2(line
, sizeof(line
), con
->password
, strlen(con
->password
));
7005 cupsFilePrintf(fp
, "%s\n", line
);
7008 * Write a random number of newlines to the end of the file...
7011 for (i
= (rand() % 1024); i
>= 0; i
--)
7012 cupsFilePutChar(fp
, '\n');
7015 * Close the file and return...
7023 * 'send_document()' - Send a file to a printer or class.
7027 send_document(client_t
*con
, /* I - Client connection */
7028 ipp_attribute_t
*uri
) /* I - Printer URI */
7030 ipp_attribute_t
*attr
; /* Current attribute */
7031 ipp_attribute_t
*format
; /* Document-format attribute */
7032 int jobid
; /* Job ID number */
7033 job_t
*job
; /* Current job */
7034 char job_uri
[HTTP_MAX_URI
],
7036 method
[HTTP_MAX_URI
],
7037 /* Method portion of URI */
7038 username
[HTTP_MAX_URI
],
7039 /* Username portion of URI */
7041 /* Host portion of URI */
7042 resource
[HTTP_MAX_URI
];
7043 /* Resource portion of URI */
7044 int port
; /* Port portion of URI */
7045 mime_type_t
*filetype
; /* Type of file */
7046 char super
[MIME_MAX_SUPER
],
7047 /* Supertype of file */
7048 type
[MIME_MAX_TYPE
],
7049 /* Subtype of file */
7050 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
7051 /* Textual name of mime type */
7052 char filename
[1024]; /* Job filename */
7053 printer_t
*printer
; /* Current printer */
7054 struct stat fileinfo
; /* File information */
7055 int kbytes
; /* Size of file */
7056 int compression
; /* Type of compression */
7059 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
7060 uri
->values
[0].string
.text
);
7063 * Verify that the POST operation was done to a valid URI.
7066 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
7067 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
7068 strncmp(con
->uri
, "/printers/", 10) != 0)
7070 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
7072 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7077 * See if we have a job URI or a printer URI...
7080 if (strcmp(uri
->name
, "printer-uri") == 0)
7083 * Got a printer URI; see if we also have a job-id attribute...
7086 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
7088 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
7089 send_ipp_error(con
, IPP_BAD_REQUEST
);
7093 jobid
= attr
->values
[0].integer
;
7098 * Got a job URI; parse it to get the job ID...
7101 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7103 if (strncmp(resource
, "/jobs/", 6) != 0)
7109 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
7110 uri
->values
[0].string
.text
);
7111 send_ipp_error(con
, IPP_BAD_REQUEST
);
7115 jobid
= atoi(resource
+ 6);
7119 * See if the job exists...
7122 if ((job
= FindJob(jobid
)) == NULL
)
7125 * Nope - return a "not found" error...
7128 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
7129 send_ipp_error(con
, IPP_NOT_FOUND
);
7134 * See if the job is owned by the requesting user...
7137 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7139 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
7140 username
, jobid
, job
->username
);
7141 send_ipp_error(con
, IPP_FORBIDDEN
);
7146 * OK, see if the client is sending the document compressed - CUPS
7147 * only supports "none" and "gzip".
7150 compression
= CUPS_FILE_NONE
;
7152 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
7154 if (strcmp(attr
->values
[0].string
.text
, "none")
7156 && strcmp(attr
->values
[0].string
.text
, "gzip")
7157 #endif /* HAVE_LIBZ */
7160 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
7161 attr
->values
[0].string
.text
);
7162 send_ipp_error(con
, IPP_ATTRIBUTES
);
7163 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7164 "compression", NULL
, attr
->values
[0].string
.text
);
7169 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
7170 compression
= CUPS_FILE_GZIP
;
7171 #endif /* HAVE_LIBZ */
7175 * Do we have a file to print?
7180 LogMessage(L_ERROR
, "send_document: No file!?!");
7181 send_ipp_error(con
, IPP_BAD_REQUEST
);
7186 * Is it a format we support?
7189 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
7192 * Grab format from client...
7195 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7197 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
7198 format
->values
[0].string
.text
);
7199 send_ipp_error(con
, IPP_BAD_REQUEST
);
7206 * No document format attribute? Auto-type it!
7209 strcpy(super
, "application");
7210 strcpy(type
, "octet-stream");
7213 if (strcmp(super
, "application") == 0 &&
7214 strcmp(type
, "octet-stream") == 0)
7217 * Auto-type the file...
7220 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
7222 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
7224 if (filetype
!= NULL
)
7227 * Replace the document-format attribute value with the auto-typed one.
7230 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
7235 free(format
->values
[0].string
.text
);
7236 format
->values
[0].string
.text
= strdup(mimetype
);
7239 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
7240 "document-format", NULL
, mimetype
);
7243 filetype
= mimeType(MimeDatabase
, super
, type
);
7246 filetype
= mimeType(MimeDatabase
, super
, type
);
7248 if (filetype
== NULL
)
7250 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
7252 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
7253 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
7256 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7257 "document-format", NULL
, format
->values
[0].string
.text
);
7262 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
7263 filetype
->super
, filetype
->type
);
7266 * Add the file to the job...
7269 if (add_file(con
, job
, filetype
, compression
))
7272 if (job
->dtype
& CUPS_PRINTER_CLASS
)
7273 printer
= FindClass(job
->dest
);
7275 printer
= FindPrinter(job
->dest
);
7277 if (stat(con
->filename
, &fileinfo
))
7280 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
7282 UpdateQuota(printer
, job
->username
, 0, kbytes
);
7284 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
7285 attr
->values
[0].integer
+= kbytes
;
7287 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
7289 rename(con
->filename
, filename
);
7291 ClearString(&con
->filename
);
7293 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
7294 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
7297 * Start the job if this is the last document...
7300 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
7301 attr
->values
[0].boolean
)
7304 * See if we need to add the ending sheet...
7307 if (printer
!= NULL
&&
7308 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
7309 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
7310 attr
->num_values
> 1)
7316 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
7317 attr
->values
[1].string
.text
, job
->id
);
7319 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
7321 UpdateQuota(printer
, job
->username
, 0, kbytes
);
7324 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
7325 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
7326 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
7328 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
7329 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
7331 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7332 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
7338 * Start the job if possible... Since CheckJobs() can cancel a job if it
7339 * doesn't print, we need to re-find the job afterwards...
7346 job
= FindJob(jobid
);
7350 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
7351 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
7353 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7355 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
7356 job
->hold_until
= time(NULL
) + 60;
7362 * Fill in the response info...
7365 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
7368 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
7371 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
7373 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
7374 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
7375 add_job_state_reasons(con
, job
);
7377 con
->response
->request
.status
.status_code
= IPP_OK
;
7382 * 'send_ipp_error()' - Send an error status back to the IPP client.
7386 send_ipp_error(client_t
*con
, /* I - Client connection */
7387 ipp_status_t status
) /* I - IPP status code */
7389 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
7392 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
7394 if (status
== IPP_NOT_AUTHORIZED
)
7397 * Send HTTP_UNAUTHORIZED response instead of IPP response, so that
7398 * the client will properly authenticate the request...
7401 SendError(con
, HTTP_UNAUTHORIZED
);
7403 ippDelete(con
->response
);
7404 con
->response
= NULL
;
7409 con
->response
->request
.status
.status_code
= status
;
7411 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
7412 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
7413 "attributes-charset", NULL
, DefaultCharset
);
7415 if (ippFindAttribute(con
->response
, "attributes-natural-language",
7416 IPP_TAG_ZERO
) == NULL
)
7417 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
7418 "attributes-natural-language", NULL
, DefaultLanguage
);
7423 * 'set_default()' - Set the default destination...
7427 set_default(client_t
*con
, /* I - Client connection */
7428 ipp_attribute_t
*uri
) /* I - Printer URI */
7430 cups_ptype_t dtype
; /* Destination type (printer or class) */
7431 char method
[HTTP_MAX_URI
],
7432 /* Method portion of URI */
7433 username
[HTTP_MAX_URI
],
7434 /* Username portion of URI */
7436 /* Host portion of URI */
7437 resource
[HTTP_MAX_URI
];
7438 /* Resource portion of URI */
7439 int port
; /* Port portion of URI */
7440 const char *name
; /* Printer name */
7441 printer_t
*printer
; /* Printer */
7444 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
7445 uri
->values
[0].string
.text
);
7448 * Was this operation called from the correct URI?
7451 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7453 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
7455 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7460 * Is the destination valid?
7463 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7465 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7471 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
7472 send_ipp_error(con
, IPP_NOT_FOUND
);
7480 if (!cupsdCheckPolicy(DefaultPolicyPtr
, con
, NULL
))
7482 LogMessage(L_ERROR
, "set_default: not authorized!");
7483 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7488 * Set it as the default...
7491 DefaultPrinter
= printer
;
7496 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
7500 * Everything was ok, so return OK status...
7503 con
->response
->request
.status
.status_code
= IPP_OK
;
7508 * 'set_job_attrs()' - Set job attributes.
7512 set_job_attrs(client_t
*con
, /* I - Client connection */
7513 ipp_attribute_t
*uri
) /* I - Job URI */
7515 ipp_attribute_t
*attr
, /* Current attribute */
7516 *attr2
, /* Job attribute */
7517 *prev2
; /* Previous job attribute */
7518 int jobid
; /* Job ID */
7519 job_t
*job
; /* Current job */
7520 char method
[HTTP_MAX_URI
],
7521 /* Method portion of URI */
7522 username
[HTTP_MAX_URI
],
7523 /* Username portion of URI */
7525 /* Host portion of URI */
7526 resource
[HTTP_MAX_URI
];
7527 /* Resource portion of URI */
7528 int port
; /* Port portion of URI */
7531 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
7532 uri
->values
[0].string
.text
);
7535 * Start with "everything is OK" status...
7538 con
->response
->request
.status
.status_code
= IPP_OK
;
7541 * See if we have a job URI or a printer URI...
7544 if (strcmp(uri
->name
, "printer-uri") == 0)
7547 * Got a printer URI; see if we also have a job-id attribute...
7550 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
7552 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
7553 send_ipp_error(con
, IPP_BAD_REQUEST
);
7557 jobid
= attr
->values
[0].integer
;
7562 * Got a job URI; parse it to get the job ID...
7565 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7567 if (strncmp(resource
, "/jobs/", 6) != 0)
7573 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
7574 uri
->values
[0].string
.text
);
7575 send_ipp_error(con
, IPP_BAD_REQUEST
);
7579 jobid
= atoi(resource
+ 6);
7583 * See if the job exists...
7586 if ((job
= FindJob(jobid
)) == NULL
)
7589 * Nope - return a "not found" error...
7592 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
7593 send_ipp_error(con
, IPP_NOT_FOUND
);
7598 * See if the job has been completed...
7601 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
7604 * Return a "not-possible" error...
7607 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
7608 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7613 * See if the job is owned by the requesting user...
7616 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7618 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
7619 username
, jobid
, job
->username
);
7620 send_ipp_error(con
, IPP_FORBIDDEN
);
7625 * See what the user wants to change.
7628 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
7630 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
7633 if (!strcmp(attr
->name
, "attributes-charset") ||
7634 !strcmp(attr
->name
, "attributes-natural-language") ||
7635 !strcmp(attr
->name
, "document-compression") ||
7636 !strcmp(attr
->name
, "document-format") ||
7637 !strcmp(attr
->name
, "job-detailed-status-messages") ||
7638 !strcmp(attr
->name
, "job-document-access-errors") ||
7639 !strcmp(attr
->name
, "job-id") ||
7640 !strcmp(attr
->name
, "job-k-octets") ||
7641 !strcmp(attr
->name
, "job-originating-host-name") ||
7642 !strcmp(attr
->name
, "job-originating-user-name") ||
7643 !strcmp(attr
->name
, "job-printer-up-time") ||
7644 !strcmp(attr
->name
, "job-printer-uri") ||
7645 !strcmp(attr
->name
, "job-sheets") ||
7646 !strcmp(attr
->name
, "job-state-message") ||
7647 !strcmp(attr
->name
, "job-state-reasons") ||
7648 !strcmp(attr
->name
, "job-uri") ||
7649 !strcmp(attr
->name
, "number-of-documents") ||
7650 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
7651 !strcmp(attr
->name
, "output-device-assigned") ||
7652 !strncmp(attr
->name
, "date-time-at-", 13) ||
7653 !strncmp(attr
->name
, "job-impressions", 15) ||
7654 !strncmp(attr
->name
, "job-k-octets", 12) ||
7655 !strncmp(attr
->name
, "job-media-sheets", 16) ||
7656 !strncmp(attr
->name
, "time-at-", 8))
7662 send_ipp_error(con
, IPP_ATTRIBUTES_NOT_SETTABLE
);
7664 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7665 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7670 if (!strcmp(attr
->name
, "job-priority"))
7673 * Change the job priority...
7676 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
7678 send_ipp_error(con
, IPP_REQUEST_VALUE
);
7680 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7681 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7683 else if (job
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
7685 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7688 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7689 SetJobPriority(jobid
, attr
->values
[0].integer
);
7691 else if (!strcmp(attr
->name
, "job-state"))
7694 * Change the job state...
7697 if (attr
->value_tag
!= IPP_TAG_ENUM
)
7699 send_ipp_error(con
, IPP_REQUEST_VALUE
);
7701 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7702 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7706 switch (attr
->values
[0].integer
)
7708 case IPP_JOB_PENDING
:
7710 if (job
->state
->values
[0].integer
> IPP_JOB_HELD
)
7712 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7715 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7716 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7719 case IPP_JOB_PROCESSING
:
7720 case IPP_JOB_STOPPED
:
7721 if (job
->state
->values
[0].integer
!= attr
->values
[0].integer
)
7723 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7728 case IPP_JOB_CANCELLED
:
7729 case IPP_JOB_ABORTED
:
7730 case IPP_JOB_COMPLETED
:
7731 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
)
7733 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7736 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7738 CancelJob(job
->id
, 0);
7742 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7750 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
7752 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
7755 * Some other value; first free the old value...
7758 if (job
->attrs
->attrs
== attr2
)
7760 job
->attrs
->attrs
= attr2
->next
;
7765 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
7766 if (prev2
->next
== attr2
)
7768 prev2
->next
= attr2
->next
;
7773 if (job
->attrs
->last
== attr2
)
7774 job
->attrs
->last
= prev2
;
7776 _ipp_free_attr(attr2
);
7779 * Then copy the attribute...
7782 copy_attribute(job
->attrs
, attr
, 0);
7785 * See if the job-name or job-hold-until is being changed.
7788 if (strcmp(attr
->name
, "job-hold-until") == 0)
7790 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
7792 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7793 ReleaseJob(job
->id
);
7798 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
7801 * Delete the attribute...
7804 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
7806 prev2
= attr2
, attr2
= attr2
->next
)
7807 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
7813 prev2
->next
= attr2
->next
;
7815 job
->attrs
->attrs
= attr2
->next
;
7817 if (attr2
== job
->attrs
->last
)
7818 job
->attrs
->last
= prev2
;
7820 _ipp_free_attr(attr2
);
7826 * Add new option by copying it...
7829 copy_attribute(job
->attrs
, attr
, 0);
7840 * Start jobs if possible...
7848 * 'start_printer()' - Start a printer.
7852 start_printer(client_t
*con
, /* I - Client connection */
7853 ipp_attribute_t
*uri
) /* I - Printer URI */
7855 cups_ptype_t dtype
; /* Destination type (printer or class) */
7856 char method
[HTTP_MAX_URI
],
7857 /* Method portion of URI */
7858 username
[HTTP_MAX_URI
],
7859 /* Username portion of URI */
7861 /* Host portion of URI */
7862 resource
[HTTP_MAX_URI
];
7863 /* Resource portion of URI */
7864 int port
; /* Port portion of URI */
7865 const char *name
; /* Printer name */
7866 printer_t
*printer
; /* Printer data */
7869 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7870 uri
->values
[0].string
.text
);
7873 * Was this operation called from the correct URI?
7876 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7878 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
7880 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7885 * Is the destination valid?
7888 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7890 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7896 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
7897 send_ipp_error(con
, IPP_NOT_FOUND
);
7905 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7907 LogMessage(L_ERROR
, "start_printer: not authorized!");
7908 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7913 * Start the printer...
7916 printer
->state_message
[0] = '\0';
7918 StartPrinter(printer
, 1);
7920 if (dtype
& CUPS_PRINTER_CLASS
)
7921 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
7923 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
7929 * Everything was ok, so return OK status...
7932 con
->response
->request
.status
.status_code
= IPP_OK
;
7937 * 'stop_printer()' - Stop a printer.
7941 stop_printer(client_t
*con
, /* I - Client connection */
7942 ipp_attribute_t
*uri
) /* I - Printer URI */
7944 cups_ptype_t dtype
; /* Destination type (printer or class) */
7945 char method
[HTTP_MAX_URI
],
7946 /* Method portion of URI */
7947 username
[HTTP_MAX_URI
],
7948 /* Username portion of URI */
7950 /* Host portion of URI */
7951 resource
[HTTP_MAX_URI
];
7952 /* Resource portion of URI */
7953 int port
; /* Port portion of URI */
7954 const char *name
; /* Printer name */
7955 printer_t
*printer
; /* Printer data */
7956 ipp_attribute_t
*attr
; /* printer-state-message attribute */
7959 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7960 uri
->values
[0].string
.text
);
7963 * Was this operation called from the correct URI?
7966 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7968 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
7970 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7975 * Is the destination valid?
7978 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7980 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7986 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
7987 send_ipp_error(con
, IPP_NOT_FOUND
);
7995 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7997 LogMessage(L_ERROR
, "stop_printer: not authorized!");
7998 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
8003 * Stop the printer...
8006 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
8007 IPP_TAG_TEXT
)) == NULL
)
8008 strcpy(printer
->state_message
, "Paused");
8011 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
8012 sizeof(printer
->state_message
));
8015 StopPrinter(printer
, 1);
8017 if (dtype
& CUPS_PRINTER_CLASS
)
8018 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
8021 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
8025 * Everything was ok, so return OK status...
8028 con
->response
->request
.status
.status_code
= IPP_OK
;
8033 * 'user_allowed()' - See if a user is allowed to print to a queue.
8036 static int /* O - 0 if not allowed, 1 if allowed */
8037 user_allowed(printer_t
*p
, /* I - Printer or class */
8038 const char *username
) /* I - Username */
8040 int i
; /* Looping var */
8041 struct passwd
*pw
; /* User password data */
8044 if (p
->num_users
== 0)
8047 if (!strcmp(username
, "root"))
8050 pw
= getpwnam(username
);
8053 for (i
= 0; i
< p
->num_users
; i
++)
8055 if (p
->users
[i
][0] == '@')
8058 * Check group membership...
8061 if (cupsdCheckGroup(username
, pw
, p
->users
[i
] + 1))
8064 else if (!strcasecmp(username
, p
->users
[i
]))
8068 return ((i
< p
->num_users
) != p
->deny_users
);
8073 * 'validate_job()' - Validate printer options and destination.
8077 validate_job(client_t
*con
, /* I - Client connection */
8078 ipp_attribute_t
*uri
) /* I - Printer URI */
8080 ipp_attribute_t
*attr
; /* Current attribute */
8081 ipp_attribute_t
*format
; /* Document-format attribute */
8082 cups_ptype_t dtype
; /* Destination type (printer or class) */
8083 char method
[HTTP_MAX_URI
],
8084 /* Method portion of URI */
8085 username
[HTTP_MAX_URI
],
8086 /* Username portion of URI */
8088 /* Host portion of URI */
8089 resource
[HTTP_MAX_URI
];
8090 /* Resource portion of URI */
8091 int port
; /* Port portion of URI */
8092 char super
[MIME_MAX_SUPER
],
8093 /* Supertype of file */
8094 type
[MIME_MAX_TYPE
];
8095 /* Subtype of file */
8096 printer_t
*printer
; /* Printer */
8099 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
8100 uri
->values
[0].string
.text
);
8103 * Verify that the POST operation was done to a valid URI.
8106 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
8107 strncmp(con
->uri
, "/printers/", 10) != 0)
8109 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
8111 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
8116 * OK, see if the client is sending the document compressed - CUPS
8117 * doesn't support compression yet...
8120 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
8121 strcmp(attr
->values
[0].string
.text
, "none") == 0)
8123 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
8124 attr
->values
[0].string
.text
);
8125 send_ipp_error(con
, IPP_ATTRIBUTES
);
8126 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
8127 "compression", NULL
, attr
->values
[0].string
.text
);
8132 * Is it a format we support?
8135 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
8137 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
8139 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
8140 format
->values
[0].string
.text
);
8141 send_ipp_error(con
, IPP_BAD_REQUEST
);
8145 if ((strcmp(super
, "application") != 0 ||
8146 strcmp(type
, "octet-stream") != 0) &&
8147 mimeType(MimeDatabase
, super
, type
) == NULL
)
8149 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
8150 format
->values
[0].string
.text
);
8151 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
8152 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
8153 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
8154 "document-format", NULL
, format
->values
[0].string
.text
);
8160 * Is the destination valid?
8163 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
8165 if (ValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
8171 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
8172 send_ipp_error(con
, IPP_NOT_FOUND
);
8180 if (!cupsdCheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
8182 LogMessage(L_ERROR
, "validate_job: not authorized!");
8183 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
8188 * Everything was ok, so return OK status...
8191 con
->response
->request
.status
.status_code
= IPP_OK
;
8196 * 'validate_name()' - Make sure the printer name only contains valid chars.
8199 static int /* O - 0 if name is no good, 1 if name is good */
8200 validate_name(const char *name
) /* I - Name to check */
8202 const char *ptr
; /* Pointer into name */
8206 * Scan the whole name...
8209 for (ptr
= name
; *ptr
; ptr
++)
8210 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
8214 * All the characters are good; validate the length, too...
8217 return ((ptr
- name
) < 128);
8222 * 'validate_user()' - Validate the user for the request.
8225 static int /* O - 1 if permitted, 0 otherwise */
8226 validate_user(job_t
*job
, /* I - Job */
8227 client_t
*con
, /* I - Client connection */
8228 const char *owner
, /* I - Owner of job/resource */
8229 char *username
, /* O - Authenticated username */
8230 int userlen
) /* I - Length of username */
8232 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
8233 printer_t
*printer
; /* Printer for job */
8236 LogMessage(L_DEBUG2
, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=%d)\n",
8237 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
8244 if (!con
|| !owner
|| !username
|| userlen
<= 0)
8248 * Get the best authenticated username that is available.
8251 if (con
->username
[0])
8252 strlcpy(username
, con
->username
, userlen
);
8253 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
8254 strlcpy(username
, attr
->values
[0].string
.text
, userlen
);
8256 strlcpy(username
, "anonymous", userlen
);
8259 * Check the username against the owner...
8262 if (job
->dtype
& CUPS_PRINTER_CLASS
)
8263 printer
= FindClass(job
->dest
);
8265 printer
= FindPrinter(job
->dest
);
8268 return (cupsdCheckPolicy(printer
->op_policy_ptr
, con
, owner
));
8270 return (cupsdCheckPolicy(DefaultPolicyPtr
, con
, owner
));