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 * cancel_all_jobs() - Cancel all print jobs.
38 * cancel_job() - Cancel a print job.
39 * cancel_subscription() - Cancel a subscription.
40 * check_quotas() - Check quotas for a printer and user.
41 * copy_attribute() - Copy a single attribute.
42 * copy_attrs() - Copy attributes from one request to another.
43 * copy_banner() - Copy a banner file to the requests directory
44 * for the specified job.
45 * copy_file() - Copy a PPD file or interface script...
46 * copy_model() - Copy a PPD model file, substituting default
48 * create_job() - Print a file to a printer or class.
49 * create_subscription() - Create a notification subscription.
50 * delete_printer() - Remove a printer or class from the system.
51 * get_default() - Get the default destination.
52 * get_devices() - Get the list of available devices on the
54 * get_jobs() - Get a list of jobs for the specified printer.
55 * get_job_attrs() - Get job attributes.
56 * get_notifications() - Get events for a subscription.
57 * get_ppds() - Get the list of PPD files on the local
59 * get_printer_attrs() - Get printer attributes.
60 * get_printers() - Get a list of printers.
61 * get_subscription_attrs() - Get subscription attributes.
62 * get_subscriptions() - Get subscriptions.
63 * hold_job() - Hold a print job.
64 * move_job() - Move a job to a new destination.
65 * ppd_add_default() - Add a PPD default choice.
66 * ppd_parse_line() - Parse a PPD default line.
67 * print_job() - Print a file to a printer or class.
68 * read_ps_line() - Read a line from a PS file...
69 * read_ps_job_ticket() - Reads a job ticket embedded in a PS file.
70 * reject_jobs() - Reject print jobs to a printer.
71 * release_job() - Release a held print job.
72 * restart_job() - Restart an old print job.
73 * send_document() - Send a file to a printer or class.
74 * send_ipp_error() - Send an error status back to the IPP client.
75 * set_default() - Set the default destination...
76 * set_job_attrs() - Set job attributes.
77 * start_printer() - Start a printer.
78 * stop_printer() - Stop a printer.
79 * user_allowed() - See if a user is allowed to print to a queue.
80 * validate_job() - Validate printer options and destination.
81 * validate_name() - Make sure the printer name only contains
83 * validate_user() - Validate the user for the request.
87 * 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 cancel_all_jobs(client_t
*con
, ipp_attribute_t
*uri
);
124 static void cancel_job(client_t
*con
, ipp_attribute_t
*uri
);
125 static void cancel_subscription(client_t
*con
, int id
);
126 static int check_quotas(client_t
*con
, printer_t
*p
);
127 static ipp_attribute_t
*copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
129 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, ipp_attribute_t
*req
,
130 ipp_tag_t group
, int quickcopy
);
131 static int copy_banner(client_t
*con
, job_t
*job
, const char *name
);
132 static int copy_file(const char *from
, const char *to
);
133 static int copy_model(const char *from
, const char *to
);
134 static void create_job(client_t
*con
, ipp_attribute_t
*uri
);
135 static void create_subscription(client_t
*con
, ipp_attribute_t
*uri
);
136 static void delete_printer(client_t
*con
, ipp_attribute_t
*uri
);
137 static void get_default(client_t
*con
);
138 static void get_devices(client_t
*con
);
139 static void get_jobs(client_t
*con
, ipp_attribute_t
*uri
);
140 static void get_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
141 static void get_notifications(client_t
*con
, int id
);
142 static void get_ppds(client_t
*con
);
143 static void get_printers(client_t
*con
, int type
);
144 static void get_printer_attrs(client_t
*con
, ipp_attribute_t
*uri
);
145 static void get_subscription_attrs(client_t
*con
, int sub_id
);
146 static void get_subscriptions(client_t
*con
, ipp_attribute_t
*uri
);
147 static void hold_job(client_t
*con
, ipp_attribute_t
*uri
);
148 static void move_job(client_t
*con
, ipp_attribute_t
*uri
);
149 static int ppd_add_default(const char *option
, const char *choice
,
150 int num_defaults
, ppd_default_t
**defaults
);
151 static int ppd_parse_line(const char *line
, char *option
, int olen
,
152 char *choice
, int clen
);
153 static void print_job(client_t
*con
, ipp_attribute_t
*uri
);
154 static void read_ps_job_ticket(client_t
*con
);
155 static void reject_jobs(client_t
*con
, ipp_attribute_t
*uri
);
156 static void release_job(client_t
*con
, ipp_attribute_t
*uri
);
157 static void renew_subscription(client_t
*con
, int sub_id
);
158 static void restart_job(client_t
*con
, ipp_attribute_t
*uri
);
159 static void send_document(client_t
*con
, ipp_attribute_t
*uri
);
160 static void send_ipp_error(client_t
*con
, ipp_status_t status
);
161 static void set_default(client_t
*con
, ipp_attribute_t
*uri
);
162 static void set_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
163 static void start_printer(client_t
*con
, ipp_attribute_t
*uri
);
164 static void stop_printer(client_t
*con
, ipp_attribute_t
*uri
);
165 static int user_allowed(printer_t
*p
, const char *username
);
166 static void validate_job(client_t
*con
, ipp_attribute_t
*uri
);
167 static int validate_name(const char *name
);
168 static int validate_user(job_t
*job
, client_t
*con
,
169 const char *owner
, char *username
,
174 * 'ProcessIPPRequest()' - Process an incoming IPP request...
177 int /* O - 1 on success, 0 on failure */
178 ProcessIPPRequest(client_t
*con
) /* I - Client connection */
180 ipp_tag_t group
; /* Current group tag */
181 ipp_attribute_t
*attr
; /* Current attribute */
182 ipp_attribute_t
*charset
; /* Character set attribute */
183 ipp_attribute_t
*language
; /* Language attribute */
184 ipp_attribute_t
*uri
; /* Printer URI attribute */
185 ipp_attribute_t
*username
; /* requesting-user-name attr */
186 int sub_id
; /* Subscription ID */
189 LogMessage(L_DEBUG2
, "ProcessIPPRequest(%p[%d]): operation_id = %04x",
190 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
193 * First build an empty response message for this request...
196 con
->response
= ippNew();
198 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
199 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
200 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
203 * Then validate the request header and required attributes...
206 if (con
->request
->request
.any
.version
[0] != 1)
209 * Return an error, since we only support IPP 1.x.
212 LogMessage(L_ERROR
, "ProcessIPPRequest: bad request version (%d.%d)!",
213 con
->request
->request
.any
.version
[0],
214 con
->request
->request
.any
.version
[1]);
216 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
217 "%04X %s Bad request version (%d.%d)",
218 IPP_VERSION_NOT_SUPPORTED
, con
->http
.hostname
,
219 con
->request
->request
.any
.version
[0],
220 con
->request
->request
.any
.version
[1]);
222 send_ipp_error(con
, IPP_VERSION_NOT_SUPPORTED
);
224 else if (con
->request
->attrs
== NULL
)
226 LogMessage(L_ERROR
, "ProcessIPPRequest: no attributes in request!");
228 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
229 "%04X %s No attributes in request",
230 IPP_BAD_REQUEST
, con
->http
.hostname
);
232 send_ipp_error(con
, IPP_BAD_REQUEST
);
237 * Make sure that the attributes are provided in the correct order and
238 * don't repeat groups...
241 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
244 if (attr
->group_tag
< group
)
247 * Out of order; return an error...
250 LogMessage(L_ERROR
, "ProcessIPPRequest: attribute groups are out of order!");
252 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
253 "%04X %s Attribute groups are out of order",
254 IPP_BAD_REQUEST
, con
->http
.hostname
);
256 send_ipp_error(con
, IPP_BAD_REQUEST
);
260 group
= attr
->group_tag
;
265 * Then make sure that the first three attributes are:
268 * attributes-natural-language
269 * printer-uri/job-uri
272 attr
= con
->request
->attrs
;
273 if (attr
&& !strcmp(attr
->name
, "attributes-charset") &&
274 attr
->value_tag
== IPP_TAG_CHARSET
)
282 if (attr
&& !strcmp(attr
->name
, "attributes-natural-language") &&
283 attr
->value_tag
== IPP_TAG_LANGUAGE
)
288 if ((attr
= ippFindAttribute(con
->request
, "printer-uri", IPP_TAG_URI
)) != NULL
)
290 else if ((attr
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
)) != NULL
)
296 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
297 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
299 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
300 "attributes-charset", NULL
, DefaultCharset
);
303 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
304 "attributes-natural-language", NULL
,
305 language
->values
[0].string
.text
);
307 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
308 "attributes-natural-language", NULL
, DefaultLanguage
);
310 if (charset
== NULL
|| language
== NULL
||
312 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
313 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
314 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
315 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
316 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
319 * Return an error, since attributes-charset,
320 * attributes-natural-language, and printer-uri/job-uri are required
321 * for all operations.
326 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-charset attribute!");
328 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
329 "%04X %s Missing attributes-charset attribute",
330 IPP_BAD_REQUEST
, con
->http
.hostname
);
335 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-natural-language attribute!");
337 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
338 "%04X %s Missing attributes-natural-language attribute",
339 IPP_BAD_REQUEST
, con
->http
.hostname
);
344 LogMessage(L_ERROR
, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
346 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
347 "%04X %s Missing printer-uri or job-uri attribute",
348 IPP_BAD_REQUEST
, con
->http
.hostname
);
351 LogMessage(L_DEBUG
, "Request attributes follow...");
353 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
354 LogMessage(L_DEBUG
, "attr \"%s\": group_tag = %x, value_tag = %x",
355 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
358 LogMessage(L_DEBUG
, "End of attributes...");
360 send_ipp_error(con
, IPP_BAD_REQUEST
);
365 * OK, all the checks pass so far; make sure requesting-user-name is
366 * not "root" from a remote host...
369 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name",
370 IPP_TAG_NAME
)) != NULL
)
373 * Check for root user...
376 if (strcmp(username
->values
[0].string
.text
, "root") == 0 &&
377 strcasecmp(con
->http
.hostname
, "localhost") != 0 &&
378 strcmp(con
->username
, "root") != 0)
381 * Remote unauthenticated user masquerading as local root...
384 SetString(&(username
->values
[0].string
.text
), RemoteRoot
);
388 if ((attr
= ippFindAttribute(con
->request
, "notify-subscription-id",
389 IPP_TAG_INTEGER
)) != NULL
)
390 sub_id
= attr
->values
[0].integer
;
395 * Then try processing the operation...
399 LogMessage(L_DEBUG2
, "ProcessIPPRequest: URI=\"%s\"",
400 uri
->values
[0].string
.text
);
402 switch (con
->request
->request
.op
.operation_id
)
408 case IPP_VALIDATE_JOB
:
409 validate_job(con
, uri
);
412 case IPP_CREATE_JOB
:
413 create_job(con
, uri
);
416 case IPP_SEND_DOCUMENT
:
417 send_document(con
, uri
);
420 case IPP_CANCEL_JOB
:
421 cancel_job(con
, uri
);
424 case IPP_GET_JOB_ATTRIBUTES
:
425 get_job_attrs(con
, uri
);
432 case IPP_GET_PRINTER_ATTRIBUTES
:
433 get_printer_attrs(con
, uri
);
440 case IPP_RELEASE_JOB
:
441 release_job(con
, uri
);
444 case IPP_RESTART_JOB
:
445 restart_job(con
, uri
);
448 case IPP_PAUSE_PRINTER
:
449 stop_printer(con
, uri
);
452 case IPP_RESUME_PRINTER
:
453 start_printer(con
, uri
);
456 case IPP_PURGE_JOBS
:
457 cancel_all_jobs(con
, uri
);
460 case IPP_SET_JOB_ATTRIBUTES
:
461 set_job_attrs(con
, uri
);
464 case CUPS_GET_DEFAULT
:
468 case CUPS_GET_PRINTERS
:
469 get_printers(con
, 0);
472 case CUPS_GET_CLASSES
:
473 get_printers(con
, CUPS_PRINTER_CLASS
);
476 case CUPS_ADD_PRINTER
:
477 add_printer(con
, uri
);
480 case CUPS_DELETE_PRINTER
:
481 delete_printer(con
, uri
);
484 case CUPS_ADD_CLASS
:
488 case CUPS_DELETE_CLASS
:
489 delete_printer(con
, uri
);
492 case CUPS_ACCEPT_JOBS
:
493 case IPP_ENABLE_PRINTER
:
494 accept_jobs(con
, uri
);
497 case CUPS_REJECT_JOBS
:
498 case IPP_DISABLE_PRINTER
:
499 reject_jobs(con
, uri
);
502 case CUPS_SET_DEFAULT
:
503 set_default(con
, uri
);
506 case CUPS_GET_DEVICES
:
518 case IPP_CREATE_PRINTER_SUBSCRIPTION
:
519 case IPP_CREATE_JOB_SUBSCRIPTION
:
520 create_subscription(con
, uri
);
523 case IPP_GET_SUBSCRIPTION_ATTRIBUTES
:
524 get_subscription_attrs(con
, sub_id
);
527 case IPP_GET_SUBSCRIPTIONS
:
528 get_subscriptions(con
, uri
);
531 case IPP_RENEW_SUBSCRIPTION
:
532 renew_subscription(con
, sub_id
);
535 case IPP_CANCEL_SUBSCRIPTION
:
536 cancel_subscription(con
, sub_id
);
539 case IPP_GET_NOTIFICATIONS
:
540 get_notifications(con
, sub_id
);
544 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
545 "%04X %s Operation %04X (%s) not supported",
546 IPP_OPERATION_NOT_SUPPORTED
, con
->http
.hostname
,
547 con
->request
->request
.op
.operation_id
,
548 ippOpString(con
->request
->request
.op
.operation_id
));
550 send_ipp_error(con
, IPP_OPERATION_NOT_SUPPORTED
);
560 * Sending data from the scheduler...
563 LogMessage(L_DEBUG
, "ProcessIPPRequest: %d status_code=%x (%s)",
564 con
->http
.fd
, con
->response
->request
.status
.status_code
,
565 ippErrorString(con
->response
->request
.status
.status_code
));
567 if (SendHeader(con
, HTTP_OK
, "application/ipp"))
569 if (con
->http
.version
== HTTP_1_1
)
571 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
573 httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n");
577 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
578 con
->http
.data_remaining
= ippLength(con
->response
);
580 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
581 con
->http
.data_remaining
);
584 LogMessage(L_DEBUG2
, "ProcessIPPRequest: Adding fd %d to OutputSet...",
587 FD_SET(con
->http
.fd
, OutputSet
);
590 * Tell the caller the response header was sent successfully...
598 * Tell the caller the response header could not be sent...
607 * Sending data from a subprocess like cups-deviced; tell the caller
608 * everything is A-OK so far...
617 * 'accept_jobs()' - Accept print jobs to a printer.
621 accept_jobs(client_t
*con
, /* I - Client connection */
622 ipp_attribute_t
*uri
) /* I - Printer or class URI */
624 cups_ptype_t dtype
; /* Destination type (printer or class) */
625 char method
[HTTP_MAX_URI
], /* Method portion of URI */
626 username
[HTTP_MAX_URI
], /* Username portion of URI */
627 host
[HTTP_MAX_URI
], /* Host portion of URI */
628 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
629 int port
; /* Port portion of URI */
630 const char *name
; /* Printer name */
631 printer_t
*printer
; /* Printer data */
634 LogMessage(L_DEBUG2
, "accept_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
635 uri
->values
[0].string
.text
);
638 * Was this operation called from the correct URI?
641 if (strncmp(con
->uri
, "/admin/", 7) != 0)
643 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
645 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
650 * Is the destination valid?
653 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
655 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
661 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
662 send_ipp_error(con
, IPP_NOT_FOUND
);
670 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
672 LogMessage(L_ERROR
, "accept_jobs: not authorized!");
673 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
678 * Accept jobs sent to the printer...
681 printer
->accepting
= 1;
682 printer
->state_message
[0] = '\0';
684 AddPrinterHistory(printer
);
686 if (dtype
& CUPS_PRINTER_CLASS
)
691 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
695 * Everything was ok, so return OK status...
698 con
->response
->request
.status
.status_code
= IPP_OK
;
703 * 'add_class()' - Add a class to the system.
707 add_class(client_t
*con
, /* I - Client connection */
708 ipp_attribute_t
*uri
) /* I - URI of class */
710 int i
; /* Looping var */
711 char method
[HTTP_MAX_URI
], /* Method portion of URI */
712 username
[HTTP_MAX_URI
], /* Username portion of URI */
713 host
[HTTP_MAX_URI
], /* Host portion of URI */
714 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
715 int port
; /* Port portion of URI */
716 printer_t
*pclass
, /* Class */
717 *member
; /* Member printer/class */
718 cups_ptype_t dtype
; /* Destination type */
719 const char *dest
; /* Printer or class name */
720 ipp_attribute_t
*attr
; /* Printer attribute */
721 int modify
; /* Non-zero if we just modified */
724 LogMessage(L_DEBUG2
, "add_class(%p[%d], %s)\n", con
, con
->http
.fd
,
725 uri
->values
[0].string
.text
);
728 * Was this operation called from the correct URI?
731 if (strncmp(con
->uri
, "/admin/", 7) != 0)
733 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
735 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
740 * Do we have a valid URI?
743 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
745 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
748 * No, return an error...
751 send_ipp_error(con
, IPP_BAD_REQUEST
);
756 * Do we have a valid printer name?
759 if (!validate_name(resource
+ 9))
762 * No, return an error...
765 send_ipp_error(con
, IPP_BAD_REQUEST
);
773 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
775 LogMessage(L_ERROR
, "add_class: not authorized!");
776 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
781 * See if the class already exists; if not, create a new class...
784 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
787 * Class doesn't exist; see if we have a printer of the same name...
790 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
791 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
794 * Yes, return an error...
797 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
802 * No, add the pclass...
805 pclass
= AddClass(resource
+ 9);
808 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
811 * Rename the implicit class to "AnyClass" or remove it...
814 if (ImplicitAnyClasses
)
816 SetStringf(&pclass
->name
, "Any%s", resource
+ 9);
820 DeletePrinter(pclass
, 1);
823 * Add the class as a new local class...
826 pclass
= AddClass(resource
+ 9);
829 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
832 * Rename the remote class to "Class"...
835 DeletePrinterFilters(pclass
);
836 SetStringf(&pclass
->name
, "%s@%s", resource
+ 9, pclass
->hostname
);
837 SetPrinterAttrs(pclass
);
841 * Add the class as a new local class...
844 pclass
= AddClass(resource
+ 9);
851 * Look for attributes and copy them over as needed...
854 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
855 SetString(&pclass
->location
, attr
->values
[0].string
.text
);
857 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
858 SetString(&pclass
->info
, attr
->values
[0].string
.text
);
860 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
862 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
863 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
865 pclass
->accepting
= attr
->values
[0].boolean
;
866 AddPrinterHistory(pclass
);
869 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared", IPP_TAG_BOOLEAN
)) != NULL
)
871 LogMessage(L_INFO
, "Setting %s printer-is-shared to %d (was %d.)",
872 pclass
->name
, attr
->values
[0].boolean
, pclass
->shared
);
874 pclass
->shared
= attr
->values
[0].boolean
;
877 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
879 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
880 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
882 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
883 pclass
->name
, attr
->values
[0].integer
);
884 send_ipp_error(con
, IPP_BAD_REQUEST
);
888 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
889 attr
->values
[0].integer
, pclass
->state
);
891 SetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
893 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
895 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
896 sizeof(pclass
->state_message
));
897 AddPrinterHistory(pclass
);
899 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
902 SetString(&pclass
->job_sheets
[0], attr
->values
[0].string
.text
);
903 if (attr
->num_values
> 1)
904 SetString(&pclass
->job_sheets
[1], attr
->values
[1].string
.text
);
906 SetString(&pclass
->job_sheets
[1], "none");
908 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
909 IPP_TAG_ZERO
)) != NULL
)
911 FreePrinterUsers(pclass
);
913 pclass
->deny_users
= 0;
914 if (attr
->value_tag
== IPP_TAG_NAME
&&
915 (attr
->num_values
> 1 ||
916 strcmp(attr
->values
[0].string
.text
, "all") != 0))
917 for (i
= 0; i
< attr
->num_values
; i
++)
918 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
920 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
921 IPP_TAG_ZERO
)) != NULL
)
923 FreePrinterUsers(pclass
);
925 pclass
->deny_users
= 1;
926 if (attr
->value_tag
== IPP_TAG_NAME
&&
927 (attr
->num_values
> 1 ||
928 strcmp(attr
->values
[0].string
.text
, "none") != 0))
929 for (i
= 0; i
< attr
->num_values
; i
++)
930 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
932 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
933 IPP_TAG_INTEGER
)) != NULL
)
935 LogMessage(L_DEBUG
, "add_class: Setting job-quota-period to %d...",
936 attr
->values
[0].integer
);
938 pclass
->quota_period
= attr
->values
[0].integer
;
940 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
941 IPP_TAG_INTEGER
)) != NULL
)
943 LogMessage(L_DEBUG
, "add_class: Setting job-k-limit to %d...",
944 attr
->values
[0].integer
);
946 pclass
->k_limit
= attr
->values
[0].integer
;
948 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
949 IPP_TAG_INTEGER
)) != NULL
)
951 LogMessage(L_DEBUG
, "add_class: Setting job-page-limit to %d...",
952 attr
->values
[0].integer
);
954 pclass
->page_limit
= attr
->values
[0].integer
;
956 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
958 policy_t
*p
; /* Policy */
961 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
963 LogMessage(L_DEBUG
, "add_class: Setting printer-op-policy to \"%s\"...",
964 attr
->values
[0].string
.text
);
965 SetString(&pclass
->op_policy
, attr
->values
[0].string
.text
);
966 pclass
->op_policy_ptr
= p
;
970 LogMessage(L_ERROR
, "add_class: Unknown printer-op-policy \"%s\"...",
971 attr
->values
[0].string
.text
);
972 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
976 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
978 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
979 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
980 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
982 LogMessage(L_ERROR
, "add_class: Unknown printer-error-policy \"%s\"...",
983 attr
->values
[0].string
.text
);
984 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
988 LogMessage(L_DEBUG
, "add_class: Setting printer-error-policy to \"%s\"...",
989 attr
->values
[0].string
.text
);
990 SetString(&pclass
->error_policy
, attr
->values
[0].string
.text
);
992 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
995 * Clear the printer array as needed...
998 if (pclass
->num_printers
> 0)
1000 free(pclass
->printers
);
1001 pclass
->num_printers
= 0;
1005 * Add each printer or class that is listed...
1008 for (i
= 0; i
< attr
->num_values
; i
++)
1011 * Search for the printer or class URI...
1014 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
1017 if ((dest
= ValidateDest(host
, resource
, &dtype
, &member
)) == NULL
)
1023 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
1024 send_ipp_error(con
, IPP_NOT_FOUND
);
1029 * Add it to the class...
1032 AddPrinterToClass(pclass
, member
);
1037 * Update the printer class attributes and return...
1040 SetPrinterAttrs(pclass
);
1048 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1049 "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1052 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1057 AddPrinterHistory(pclass
);
1059 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1060 "New class \'%s\' added by \'%s\'.", pclass
->name
,
1063 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
1067 con
->response
->request
.status
.status_code
= IPP_OK
;
1072 * 'add_file()' - Add a file to a job.
1075 static int /* O - 0 on success, -1 on error */
1076 add_file(client_t
*con
, /* I - Connection to client */
1077 job_t
*job
, /* I - Job to add to */
1078 mime_type_t
*filetype
, /* I - Type of file */
1079 int compression
) /* I - Compression */
1081 mime_type_t
**filetypes
; /* New filetypes array... */
1082 int *compressions
; /* New compressions array... */
1085 LogMessage(L_DEBUG2
, "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)\n",
1086 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1090 * Add the file to the job...
1093 if (job
->num_files
== 0)
1095 compressions
= (int *)malloc(sizeof(int));
1096 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1100 compressions
= (int *)realloc(job
->compressions
,
1101 (job
->num_files
+ 1) * sizeof(int));
1102 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1103 (job
->num_files
+ 1) *
1104 sizeof(mime_type_t
*));
1107 if (compressions
== NULL
|| filetypes
== NULL
)
1109 CancelJob(job
->id
, 1);
1110 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
1111 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1115 job
->compressions
= compressions
;
1116 job
->compressions
[job
->num_files
] = compression
;
1117 job
->filetypes
= filetypes
;
1118 job
->filetypes
[job
->num_files
] = filetype
;
1127 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1128 * upon the job and printer state...
1132 add_job_state_reasons(client_t
*con
, /* I - Client connection */
1133 job_t
*job
) /* I - Job info */
1135 printer_t
*dest
; /* Destination printer */
1138 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
1141 switch (job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
)
1143 case IPP_JOB_PENDING
:
1144 if (job
->dtype
& CUPS_PRINTER_CLASS
)
1145 dest
= FindClass(job
->dest
);
1147 dest
= FindPrinter(job
->dest
);
1149 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
1150 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1151 "job-state-reasons", NULL
, "printer-stopped");
1153 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1154 "job-state-reasons", NULL
, "none");
1158 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
1159 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
1160 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1161 "job-state-reasons", NULL
, "job-hold-until-specified");
1163 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1164 "job-state-reasons", NULL
, "job-incoming");
1167 case IPP_JOB_PROCESSING
:
1168 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1169 "job-state-reasons", NULL
, "job-printing");
1172 case IPP_JOB_STOPPED
:
1173 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1174 "job-state-reasons", NULL
, "job-stopped");
1177 case IPP_JOB_CANCELLED
:
1178 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1179 "job-state-reasons", NULL
, "job-canceled-by-user");
1182 case IPP_JOB_ABORTED
:
1183 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1184 "job-state-reasons", NULL
, "aborted-by-system");
1187 case IPP_JOB_COMPLETED
:
1188 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1189 "job-state-reasons", NULL
, "job-completed-successfully");
1196 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1200 add_job_subscriptions(client_t
*con
, /* I - Client connection */
1201 job_t
*job
) /* I - Newly created job */
1203 int i
; /* Looping var */
1204 ipp_attribute_t
*prev
, /* Previous attribute */
1205 *next
, /* Next attribute */
1206 *attr
; /* Current attribute */
1207 cupsd_subscription_t
*sub
; /* Subscription object */
1208 const char *recipient
, /* notify-recipient-uri */
1209 *pullmethod
; /* notify-pull-method */
1210 ipp_attribute_t
*user_data
; /* notify-user-data */
1211 int interval
; /* notify-time-interval */
1212 unsigned mask
; /* notify-events */
1216 * Find the first subscription group attribute; return if we have
1220 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; prev
= attr
, attr
= attr
->next
)
1221 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1228 * Process the subscription attributes in the request...
1237 mask
= CUPSD_EVENT_NONE
;
1239 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1241 if (!strcmp(attr
->name
, "notify-recipient") &&
1242 attr
->value_tag
== IPP_TAG_URI
)
1243 recipient
= attr
->values
[0].string
.text
;
1244 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1245 attr
->value_tag
== IPP_TAG_KEYWORD
)
1246 pullmethod
= attr
->values
[0].string
.text
;
1247 else if (!strcmp(attr
->name
, "notify-charset") &&
1248 attr
->value_tag
== IPP_TAG_CHARSET
&&
1249 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1251 send_ipp_error(con
, IPP_CHARSET
);
1254 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1255 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
1256 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
))
1258 send_ipp_error(con
, IPP_CHARSET
);
1261 else if (!strcmp(attr
->name
, "notify-user-data") &&
1262 attr
->value_tag
== IPP_TAG_STRING
)
1264 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1266 send_ipp_error(con
, IPP_REQUEST_VALUE
);
1272 else if (!strcmp(attr
->name
, "notify-events") &&
1273 attr
->value_tag
== IPP_TAG_KEYWORD
)
1275 for (i
= 0; i
< attr
->num_values
; i
++)
1276 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1278 else if (!strcmp(attr
->name
, "notify-lease-time"))
1280 send_ipp_error(con
, IPP_BAD_REQUEST
);
1283 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1284 attr
->value_tag
== IPP_TAG_INTEGER
)
1285 interval
= attr
->values
[0].integer
;
1290 if (!recipient
&& !pullmethod
)
1293 if (mask
== CUPSD_EVENT_NONE
)
1294 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1296 sub
= cupsdAddSubscription(mask
, FindDest(job
->dest
), job
, recipient
);
1298 sub
->interval
= interval
;
1300 SetString(&sub
->owner
, job
->username
);
1304 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1305 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1306 sub
->user_data_len
);
1314 * Remove all of the subscription attributes from the job request...
1317 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1321 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1322 attr
->group_tag
== IPP_TAG_ZERO
)
1325 * Free and remove this attribute...
1328 _ipp_free_attr(attr
);
1333 job
->attrs
->attrs
= next
;
1339 job
->attrs
->last
= prev
;
1340 job
->attrs
->current
= prev
;
1345 * 'add_printer()' - Add a printer to the system.
1349 add_printer(client_t
*con
, /* I - Client connection */
1350 ipp_attribute_t
*uri
) /* I - URI of printer */
1352 int i
; /* Looping var */
1353 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1354 username
[HTTP_MAX_URI
], /* Username portion of URI */
1355 host
[HTTP_MAX_URI
], /* Host portion of URI */
1356 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1357 int port
; /* Port portion of URI */
1358 printer_t
*printer
; /* Printer/class */
1359 ipp_attribute_t
*attr
; /* Printer attribute */
1360 cups_file_t
*fp
; /* Script/PPD file */
1361 char line
[1024]; /* Line from file... */
1362 char srcfile
[1024], /* Source Script/PPD file */
1363 dstfile
[1024]; /* Destination Script/PPD file */
1364 int modify
; /* Non-zero if we are modifying */
1367 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
1368 uri
->values
[0].string
.text
);
1371 * Was this operation called from the correct URI?
1374 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1376 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
1378 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1383 * Do we have a valid URI?
1386 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1388 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1391 * No, return an error...
1394 LogMessage(L_ERROR
, "add_printer: bad printer URI \"%s\"!",
1395 uri
->values
[0].string
.text
);
1396 send_ipp_error(con
, IPP_BAD_REQUEST
);
1401 * Do we have a valid printer name?
1404 if (!validate_name(resource
+ 10))
1407 * No, return an error...
1410 send_ipp_error(con
, IPP_BAD_REQUEST
);
1418 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
1420 LogMessage(L_ERROR
, "add_printer: not authorized!");
1421 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1426 * See if the printer already exists; if not, create a new printer...
1429 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1432 * Printer doesn't exist; see if we have a class of the same name...
1435 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1436 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1439 * Yes, return an error...
1442 LogMessage(L_ERROR
, "add_printer: \"%s\" already exists as a class!",
1444 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1449 * No, add the printer...
1452 printer
= AddPrinter(resource
+ 10);
1455 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1458 * Rename the implicit printer to "AnyPrinter" or delete it...
1461 if (ImplicitAnyClasses
)
1463 SetStringf(&printer
->name
, "Any%s", resource
+ 10);
1467 DeletePrinter(printer
, 1);
1470 * Add the printer as a new local printer...
1473 printer
= AddPrinter(resource
+ 10);
1476 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1479 * Rename the remote printer to "Printer@server"...
1482 DeletePrinterFilters(printer
);
1483 SetStringf(&printer
->name
, "%s@%s", resource
+ 10, printer
->hostname
);
1484 SetPrinterAttrs(printer
);
1488 * Add the printer as a new local printer...
1491 printer
= AddPrinter(resource
+ 10);
1498 * Look for attributes and copy them over as needed...
1501 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1502 SetString(&printer
->location
, attr
->values
[0].string
.text
);
1504 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1505 SetString(&printer
->info
, attr
->values
[0].string
.text
);
1507 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1510 * Do we have a valid device URI?
1513 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1516 if (!strcmp(method
, "file"))
1519 * See if the administrator has enabled file devices...
1522 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
1525 * File devices are disabled and the URL is not file:/dev/null...
1528 LogMessage(L_ERROR
, "add_printer: File device URIs have been disabled! "
1529 "To enable, see the FileDevice directive in cupsd.conf.");
1530 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1537 * See if the backend exists and is executable...
1540 snprintf(srcfile
, sizeof(srcfile
), "%s/backend/%s", ServerBin
, method
);
1541 if (access(srcfile
, X_OK
))
1544 * Could not find device in list!
1547 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1548 attr
->values
[0].string
.text
);
1549 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1554 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1556 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
, sizeof(line
)),
1557 cupsdSanitizeURI(printer
->device_uri
, resource
, sizeof(resource
)));
1559 SetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
1562 if ((attr
= ippFindAttribute(con
->request
, "port-monitor", IPP_TAG_KEYWORD
)) != NULL
)
1564 ipp_attribute_t
*supported
; /* port-monitor-supported attribute */
1567 supported
= ippFindAttribute(printer
->attrs
, "port-monitor-supported",
1569 for (i
= 0; i
< supported
->num_values
; i
++)
1570 if (!strcmp(supported
->values
[i
].string
.text
,
1571 attr
->values
[0].string
.text
))
1574 if (i
>= supported
->num_values
)
1576 LogMessage(L_ERROR
, "add_printer: bad port-monitor attribute \'%s\'!",
1577 attr
->values
[0].string
.text
);
1578 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1582 LogMessage(L_INFO
, "Setting %s port-monitor to \"%s\" (was \"%s\".)",
1583 printer
->name
, attr
->values
[0].string
.text
,
1584 printer
->port_monitor
);
1586 if (strcmp(attr
->values
[0].string
.text
, "none"))
1587 SetString(&printer
->port_monitor
, attr
->values
[0].string
.text
);
1589 ClearString(&printer
->port_monitor
);
1592 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1594 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1595 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1597 printer
->accepting
= attr
->values
[0].boolean
;
1598 AddPrinterHistory(printer
);
1601 if ((attr
= ippFindAttribute(con
->request
, "printer-is-shared", IPP_TAG_BOOLEAN
)) != NULL
)
1603 LogMessage(L_INFO
, "Setting %s printer-is-shared to %d (was %d.)",
1604 printer
->name
, attr
->values
[0].boolean
, printer
->shared
);
1606 printer
->shared
= attr
->values
[0].boolean
;
1609 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1611 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1612 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1614 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
1615 printer
->name
, attr
->values
[0].integer
);
1616 send_ipp_error(con
, IPP_BAD_REQUEST
);
1620 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1621 attr
->values
[0].integer
, printer
->state
);
1623 SetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1625 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1627 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
1628 sizeof(printer
->state_message
));
1629 AddPrinterHistory(printer
);
1631 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1634 SetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
1635 if (attr
->num_values
> 1)
1636 SetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
1638 SetString(&printer
->job_sheets
[1], "none");
1640 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1641 IPP_TAG_ZERO
)) != NULL
)
1643 FreePrinterUsers(printer
);
1645 printer
->deny_users
= 0;
1646 if (attr
->value_tag
== IPP_TAG_NAME
&&
1647 (attr
->num_values
> 1 ||
1648 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1649 for (i
= 0; i
< attr
->num_values
; i
++)
1650 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1652 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1653 IPP_TAG_ZERO
)) != NULL
)
1655 FreePrinterUsers(printer
);
1657 printer
->deny_users
= 1;
1658 if (attr
->value_tag
== IPP_TAG_NAME
&&
1659 (attr
->num_values
> 1 ||
1660 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1661 for (i
= 0; i
< attr
->num_values
; i
++)
1662 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1664 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1665 IPP_TAG_INTEGER
)) != NULL
)
1667 LogMessage(L_DEBUG
, "add_printer: Setting job-quota-period to %d...",
1668 attr
->values
[0].integer
);
1669 FreeQuotas(printer
);
1670 printer
->quota_period
= attr
->values
[0].integer
;
1672 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1673 IPP_TAG_INTEGER
)) != NULL
)
1675 LogMessage(L_DEBUG
, "add_printer: Setting job-k-limit to %d...",
1676 attr
->values
[0].integer
);
1677 FreeQuotas(printer
);
1678 printer
->k_limit
= attr
->values
[0].integer
;
1680 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1681 IPP_TAG_INTEGER
)) != NULL
)
1683 LogMessage(L_DEBUG
, "add_printer: Setting job-page-limit to %d...",
1684 attr
->values
[0].integer
);
1685 FreeQuotas(printer
);
1686 printer
->page_limit
= attr
->values
[0].integer
;
1688 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
1690 policy_t
*p
; /* Policy */
1693 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
1695 LogMessage(L_DEBUG
, "add_printer: Setting printer-op-policy to \"%s\"...",
1696 attr
->values
[0].string
.text
);
1697 SetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
1698 printer
->op_policy_ptr
= p
;
1702 LogMessage(L_ERROR
, "add_printer: Unknown printer-op-policy \"%s\"...",
1703 attr
->values
[0].string
.text
);
1704 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1708 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
1710 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
1711 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
1712 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
1714 LogMessage(L_ERROR
, "add_printer: Unknown printer-error-policy \"%s\"...",
1715 attr
->values
[0].string
.text
);
1716 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1720 LogMessage(L_DEBUG
, "add_printer: Setting printer-error-policy to \"%s\"...",
1721 attr
->values
[0].string
.text
);
1722 SetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
1726 * See if we have all required attributes...
1729 if (!printer
->device_uri
)
1730 SetString(&printer
->device_uri
, "file:/dev/null");
1733 * See if we have an interface script or PPD file attached to the request...
1738 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
1740 if ((fp
= cupsFileOpen(srcfile
, "rb")) != NULL
)
1743 * Yes; get the first line from it...
1747 cupsFileGets(fp
, line
, sizeof(line
));
1751 * Then see what kind of file it is...
1754 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1757 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1760 * The new file is a PPD file, so remove any old interface script
1761 * that might be lying around...
1769 * This must be an interface script, so move the file over to the
1770 * interfaces directory and make it executable...
1773 if (copy_file(srcfile
, dstfile
))
1775 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1776 srcfile
, dstfile
, strerror(errno
));
1777 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1782 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1783 chmod(dstfile
, 0755);
1787 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1790 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1793 * The new file is a PPD file, so move the file over to the
1794 * ppd directory and make it readable by all...
1797 if (copy_file(srcfile
, dstfile
))
1799 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1800 srcfile
, dstfile
, strerror(errno
));
1801 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1806 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1807 chmod(dstfile
, 0644);
1813 * This must be an interface script, so remove any old PPD file that
1814 * may be lying around...
1821 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1823 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1826 * Raw driver, remove any existing PPD or interface script files.
1829 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1833 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1843 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1844 attr
->values
[0].string
.text
);
1846 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1850 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1853 if (copy_model(srcfile
, dstfile
))
1855 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1856 srcfile
, dstfile
, strerror(errno
));
1857 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1862 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1863 chmod(dstfile
, 0644);
1869 * Make this printer the default if there is none...
1872 if (DefaultPrinter
== NULL
)
1873 DefaultPrinter
= printer
;
1876 * Update the printer attributes and return...
1879 SetPrinterAttrs(printer
);
1882 if (printer
->job
!= NULL
)
1887 * Stop the current job and then restart it below...
1890 job
= (job_t
*)printer
->job
;
1892 StopJob(job
->id
, 1);
1893 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1902 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
1903 "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1906 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1911 AddPrinterHistory(printer
);
1913 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
1914 "New printer \'%s\' added by \'%s\'.", printer
->name
,
1917 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1921 con
->response
->request
.status
.status_code
= IPP_OK
;
1926 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1927 * based upon the printer state...
1931 add_printer_state_reasons(
1932 client_t
*con
, /* I - Client connection */
1933 printer_t
*p
) /* I - Printer info */
1935 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1936 con
, con
->http
.fd
, p
, p
->name
);
1938 if (p
->num_reasons
== 0)
1939 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1940 "printer-state-reasons", NULL
,
1941 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
1943 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1944 "printer-state-reasons", p
->num_reasons
, NULL
,
1945 (const char * const *)p
->reasons
);
1950 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1951 * the specified printer or class.
1955 add_queued_job_count(client_t
*con
, /* I - Client connection */
1956 printer_t
*p
) /* I - Printer or class */
1958 int count
; /* Number of jobs on destination */
1961 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1962 con
, con
->http
.fd
, p
, p
->name
);
1964 count
= GetPrinterJobCount(p
->name
);
1966 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1967 "queued-job-count", count
);
1972 * 'cancel_all_jobs()' - Cancel all print jobs.
1976 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1977 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1979 const char *dest
; /* Destination */
1980 cups_ptype_t dtype
; /* Destination type */
1981 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1982 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
1983 host
[HTTP_MAX_URI
], /* Host portion of URI */
1984 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1985 int port
; /* Port portion of URI */
1986 ipp_attribute_t
*attr
; /* Attribute in request */
1987 const char *username
; /* Username */
1988 int purge
; /* Purge? */
1989 printer_t
*printer
; /* Printer */
1992 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
1993 uri
->values
[0].string
.text
);
1996 * Was this operation called from the correct URI?
1999 if (strncmp(con
->uri
, "/admin/", 7) &&
2000 strncmp(con
->uri
, "/jobs/", 7))
2002 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
2004 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2009 * See if we have a printer URI...
2012 if (strcmp(uri
->name
, "printer-uri"))
2014 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
2015 uri
->name
, uri
->values
[0].string
.text
);
2016 send_ipp_error(con
, IPP_BAD_REQUEST
);
2021 * Get the username (if any) for the jobs we want to cancel (only if
2022 * "my-jobs" is specified...
2025 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
2026 attr
->values
[0].boolean
)
2028 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
2029 username
= attr
->values
[0].string
.text
;
2032 LogMessage(L_ERROR
, "cancel_all_jobs: missing requesting-user-name attribute!");
2033 send_ipp_error(con
, IPP_BAD_REQUEST
);
2041 (username
&& con
->username
[0] && strcmp(username
, con
->username
))) &&
2042 strncmp(con
->uri
, "/admin/", 7))
2044 LogMessage(L_ERROR
, "cancel_all_jobs: only administrators can cancel "
2045 "other users\' jobs!");
2046 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2051 * Look for the "purge-jobs" attribute...
2054 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
2055 purge
= attr
->values
[0].boolean
;
2060 * And if the destination is valid...
2063 httpSeparate(uri
->values
[0].string
.text
, method
, userpass
, host
, &port
,
2066 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2072 if (strcmp(resource
, "/printers/") != 0)
2074 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
2075 send_ipp_error(con
, IPP_NOT_FOUND
);
2083 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
2085 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2086 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2091 * Cancel all jobs on all printers...
2094 CancelJobs(NULL
, username
, purge
);
2096 LogMessage(L_INFO
, "All jobs were %s by \'%s\'.",
2097 purge
? "purged" : "cancelled", con
->username
);
2105 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
2107 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2108 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2113 * Cancel all of the jobs on the named printer...
2116 CancelJobs(dest
, username
, purge
);
2118 LogMessage(L_INFO
, "All jobs on \'%s\' were %s by \'%s\'.", dest
,
2119 purge
? "purged" : "cancelled", con
->username
);
2122 con
->response
->request
.status
.status_code
= IPP_OK
;
2127 * 'cancel_job()' - Cancel a print job.
2131 cancel_job(client_t
*con
, /* I - Client connection */
2132 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2134 ipp_attribute_t
*attr
; /* Current attribute */
2135 int jobid
; /* Job ID */
2136 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2137 username
[HTTP_MAX_URI
], /* Username portion of URI */
2138 host
[HTTP_MAX_URI
], /* Host portion of URI */
2139 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2140 int port
; /* Port portion of URI */
2141 job_t
*job
; /* Job information */
2142 const char *dest
; /* Destination */
2143 cups_ptype_t dtype
; /* Destination type (printer or class) */
2144 printer_t
*printer
; /* Printer data */
2147 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2148 uri
->values
[0].string
.text
);
2151 * Verify that the POST operation was done to a valid URI.
2154 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2155 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
2156 strncmp(con
->uri
, "/printers/", 10) != 0)
2158 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
2160 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2165 * See if we have a job URI or a printer URI...
2168 if (strcmp(uri
->name
, "printer-uri") == 0)
2171 * Got a printer URI; see if we also have a job-id attribute...
2174 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2176 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
2177 send_ipp_error(con
, IPP_BAD_REQUEST
);
2181 if ((jobid
= attr
->values
[0].integer
) == 0)
2184 * Find the current job on the specified printer...
2187 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2189 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2195 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
2196 send_ipp_error(con
, IPP_NOT_FOUND
);
2201 * See if the printer is currently printing a job...
2205 jobid
= ((job_t
*)printer
->job
)->id
;
2209 * No, see if there are any pending jobs...
2212 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
2213 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
2214 strcasecmp(job
->dest
, dest
) == 0)
2221 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
2222 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2231 * Got a job URI; parse it to get the job ID...
2234 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2236 if (strncmp(resource
, "/jobs/", 6) != 0)
2242 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
2243 uri
->values
[0].string
.text
);
2244 send_ipp_error(con
, IPP_BAD_REQUEST
);
2248 jobid
= atoi(resource
+ 6);
2252 * See if the job exists...
2255 if ((job
= FindJob(jobid
)) == NULL
)
2258 * Nope - return a "not found" error...
2261 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
2262 send_ipp_error(con
, IPP_NOT_FOUND
);
2267 * See if the job is owned by the requesting user...
2270 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2272 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
2273 username
, jobid
, job
->username
);
2274 send_ipp_error(con
, IPP_FORBIDDEN
);
2279 * See if the job is already completed, cancelled, or aborted; if so,
2280 * we can't cancel...
2283 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
2285 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
2287 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
2288 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
2290 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2295 * Cancel the job and return...
2298 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED
, job
->printer
, job
,
2299 "Job cancelled by \'%s\'.", username
);
2301 CancelJob(jobid
, 0);
2304 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
2306 con
->response
->request
.status
.status_code
= IPP_OK
;
2311 * 'cancel_subscription()' - Cancel a subscription.
2315 cancel_subscription(client_t
*con
, /* I - Client connection */
2316 int sub_id
) /* I - Subscription ID */
2322 * 'check_quotas()' - Check quotas for a printer and user.
2325 static int /* O - 1 if OK, 0 if not */
2326 check_quotas(client_t
*con
, /* I - Client connection */
2327 printer_t
*p
) /* I - Printer or class */
2329 int i
, j
; /* Looping vars */
2330 ipp_attribute_t
*attr
; /* Current attribute */
2331 char username
[33]; /* Username */
2332 quota_t
*q
; /* Quota data */
2333 struct passwd
*pw
; /* User password data */
2334 struct group
*grp
; /* Group data */
2337 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
2338 con
, con
->http
.fd
, p
, p
->name
);
2344 if (con
== NULL
|| p
== NULL
)
2348 * Figure out who is printing...
2351 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
2353 if (con
->username
[0])
2354 strlcpy(username
, con
->username
, sizeof(username
));
2355 else if (attr
!= NULL
)
2357 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
2358 attr
->values
[0].string
.text
);
2360 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
2363 strcpy(username
, "anonymous");
2366 * Check global active job limits for printers and users...
2369 if (MaxJobsPerPrinter
)
2372 * Check if there are too many pending jobs on this printer...
2375 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
2377 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
2385 * Check if there are too many pending jobs for this user...
2388 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
2390 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
2396 * Check against users...
2399 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
2404 pw
= getpwnam(username
);
2407 for (i
= 0; i
< p
->num_users
; i
++)
2408 if (p
->users
[i
][0] == '@')
2411 * Check group membership...
2414 grp
= getgrnam(p
->users
[i
] + 1);
2420 * Check primary group...
2423 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
2427 * Check usernames in group...
2430 for (j
= 0; grp
->gr_mem
[j
]; j
++)
2431 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
2438 else if (!strcasecmp(username
, p
->users
[i
]))
2441 if ((i
< p
->num_users
) == p
->deny_users
)
2443 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
2453 if (p
->k_limit
|| p
->page_limit
)
2455 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
2457 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
2462 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
2463 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
2465 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
2472 * If we have gotten this far, we're done!
2480 * 'copy_attribute()' - Copy a single attribute.
2483 static ipp_attribute_t
* /* O - New attribute */
2485 ipp_t
*to
, /* O - Destination request/response */
2486 ipp_attribute_t
*attr
, /* I - Attribute to copy */
2487 int quickcopy
) /* I - Do a quick copy? */
2489 int i
; /* Looping var */
2490 ipp_attribute_t
*toattr
; /* Destination attribute */
2493 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
2494 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
2497 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2500 toattr
= ippAddSeparator(to
);
2503 case IPP_TAG_INTEGER
:
2505 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2506 attr
->name
, attr
->num_values
, NULL
);
2508 for (i
= 0; i
< attr
->num_values
; i
++)
2509 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
2512 case IPP_TAG_BOOLEAN
:
2513 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
2514 attr
->num_values
, NULL
);
2516 for (i
= 0; i
< attr
->num_values
; i
++)
2517 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
2520 case IPP_TAG_STRING
:
2523 case IPP_TAG_KEYWORD
:
2525 case IPP_TAG_URISCHEME
:
2526 case IPP_TAG_CHARSET
:
2527 case IPP_TAG_LANGUAGE
:
2528 case IPP_TAG_MIMETYPE
:
2529 toattr
= ippAddStrings(to
, attr
->group_tag
,
2530 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2531 attr
->name
, attr
->num_values
, NULL
, NULL
);
2535 for (i
= 0; i
< attr
->num_values
; i
++)
2536 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2540 for (i
= 0; i
< attr
->num_values
; i
++)
2541 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2546 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
2547 attr
->values
[0].date
);
2550 case IPP_TAG_RESOLUTION
:
2551 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
2552 attr
->num_values
, IPP_RES_PER_INCH
,
2555 for (i
= 0; i
< attr
->num_values
; i
++)
2557 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
2558 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
2559 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
2563 case IPP_TAG_RANGE
:
2564 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
2565 attr
->num_values
, NULL
, NULL
);
2567 for (i
= 0; i
< attr
->num_values
; i
++)
2569 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
2570 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
2574 case IPP_TAG_TEXTLANG
:
2575 case IPP_TAG_NAMELANG
:
2576 toattr
= ippAddStrings(to
, attr
->group_tag
,
2577 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2578 attr
->name
, attr
->num_values
, NULL
, NULL
);
2582 for (i
= 0; i
< attr
->num_values
; i
++)
2584 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
2585 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2590 for (i
= 0; i
< attr
->num_values
; i
++)
2593 toattr
->values
[i
].string
.charset
=
2594 strdup(attr
->values
[i
].string
.charset
);
2596 toattr
->values
[i
].string
.charset
=
2597 toattr
->values
[0].string
.charset
;
2599 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2604 case IPP_TAG_BEGIN_COLLECTION
:
2605 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
2606 attr
->num_values
, NULL
);
2608 for (i
= 0; i
< attr
->num_values
; i
++)
2610 toattr
->values
[i
].collection
= ippNew();
2611 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
2612 NULL
, IPP_TAG_ZERO
, 0);
2617 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2618 attr
->name
, attr
->num_values
, NULL
);
2620 for (i
= 0; i
< attr
->num_values
; i
++)
2622 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
2624 if (toattr
->values
[i
].unknown
.length
> 0)
2626 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
2627 toattr
->values
[i
].unknown
.length
= 0;
2629 memcpy(toattr
->values
[i
].unknown
.data
,
2630 attr
->values
[i
].unknown
.data
,
2631 toattr
->values
[i
].unknown
.length
);
2634 break; /* anti-compiler-warning-code */
2642 * 'copy_attrs()' - Copy attributes from one request to another.
2646 copy_attrs(ipp_t
*to
, /* I - Destination request */
2647 ipp_t
*from
, /* I - Source request */
2648 ipp_attribute_t
*req
, /* I - Requested attributes */
2649 ipp_tag_t group
, /* I - Group to copy */
2650 int quickcopy
) /* I - Do a quick copy? */
2652 int i
; /* Looping var */
2653 ipp_attribute_t
*fromattr
; /* Source attribute */
2656 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2658 if (to
== NULL
|| from
== NULL
)
2661 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2662 req
= NULL
; /* "all" means no filter... */
2664 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2667 * Filter attributes as needed...
2670 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2671 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2674 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2676 for (i
= 0; i
< req
->num_values
; i
++)
2677 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2680 if (i
== req
->num_values
)
2684 copy_attribute(to
, fromattr
, quickcopy
);
2690 * 'copy_banner()' - Copy a banner file to the requests directory for the
2694 static int /* O - Size of banner file in kbytes */
2695 copy_banner(client_t
*con
, /* I - Client connection */
2696 job_t
*job
, /* I - Job information */
2697 const char *name
) /* I - Name of banner */
2699 int i
; /* Looping var */
2700 int kbytes
; /* Size of banner file in kbytes */
2701 char filename
[1024]; /* Job filename */
2702 banner_t
*banner
; /* Pointer to banner */
2703 cups_file_t
*in
; /* Input file */
2704 cups_file_t
*out
; /* Output file */
2705 int ch
; /* Character from file */
2706 char attrname
[255], /* Name of attribute */
2707 *s
; /* Pointer into name */
2708 ipp_attribute_t
*attr
; /* Attribute */
2711 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2712 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2715 * Find the banner; return if not found or "none"...
2719 strcmp(name
, "none") == 0 ||
2720 (banner
= FindBanner(name
)) == NULL
)
2724 * Open the banner and job files...
2727 if (add_file(con
, job
, banner
->filetype
, 0))
2730 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2732 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
2734 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2735 filename
, strerror(errno
));
2740 fchmod(cupsFileNumber(out
), 0640);
2741 fchown(cupsFileNumber(out
), RunUser
, Group
);
2746 * Try the localized banner file under the subdirectory...
2749 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2750 con
->language
->language
, name
);
2752 if (access(filename
, 0) && con
->language
->language
[2])
2755 * Wasn't able to find "ll_CC" locale file; try the non-national
2756 * localization banner directory.
2759 attrname
[0] = con
->language
->language
[0];
2760 attrname
[1] = con
->language
->language
[1];
2763 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2767 if (access(filename
, 0))
2770 * Use the non-localized banner file.
2773 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2779 * Use the non-localized banner file.
2782 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2785 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
2789 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2790 filename
, strerror(errno
));
2796 * Parse the file to the end...
2799 while ((ch
= cupsFileGetChar(in
)) != EOF
)
2803 * Get an attribute name...
2806 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
2807 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
2809 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2819 * Ignore { followed by stuff that is not an attribute name...
2822 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
2827 * See if it is defined...
2830 if (attrname
[0] == '?')
2835 if (strcmp(s
, "printer-name") == 0)
2837 cupsFilePuts(out
, job
->dest
);
2840 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2843 * See if we have a leading question mark...
2846 if (attrname
[0] != '?')
2849 * Nope, write to file as-is; probably a PostScript procedure...
2852 cupsFilePrintf(out
, "{%s}", attrname
);
2859 * Output value(s)...
2862 for (i
= 0; i
< attr
->num_values
; i
++)
2865 cupsFilePutChar(out
, ',');
2867 switch (attr
->value_tag
)
2869 case IPP_TAG_INTEGER
:
2871 if (strncmp(s
, "time-at-", 8) == 0)
2872 cupsFilePuts(out
, GetDateTime(attr
->values
[i
].integer
));
2874 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
2877 case IPP_TAG_BOOLEAN
:
2878 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
2881 case IPP_TAG_NOVALUE
:
2882 cupsFilePuts(out
, "novalue");
2885 case IPP_TAG_RANGE
:
2886 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2887 attr
->values
[i
].range
.upper
);
2890 case IPP_TAG_RESOLUTION
:
2891 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2892 attr
->values
[i
].resolution
.yres
,
2893 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2898 case IPP_TAG_STRING
:
2901 case IPP_TAG_KEYWORD
:
2902 case IPP_TAG_CHARSET
:
2903 case IPP_TAG_LANGUAGE
:
2904 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2907 * Need to quote strings for PS banners...
2912 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2914 if (*p
== '(' || *p
== ')' || *p
== '\\')
2916 cupsFilePutChar(out
, '\\');
2917 cupsFilePutChar(out
, *p
);
2919 else if (*p
< 32 || *p
> 126)
2920 cupsFilePrintf(out
, "\\%03o", *p
& 255);
2922 cupsFilePutChar(out
, *p
);
2926 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
2930 break; /* anti-compiler-warning-code */
2934 else if (ch
== '\\') /* Quoted char */
2936 ch
= cupsFileGetChar(in
);
2938 if (ch
!= '{') /* Only do special handling for \{ */
2939 cupsFilePutChar(out
, '\\');
2941 cupsFilePutChar(out
, ch
);
2944 cupsFilePutChar(out
, ch
);
2948 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
2950 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2951 attr
->values
[0].integer
+= kbytes
;
2960 * 'copy_file()' - Copy a PPD file or interface script...
2963 static int /* O - 0 = success, -1 = error */
2964 copy_file(const char *from
, /* I - Source file */
2965 const char *to
) /* I - Destination file */
2967 cups_file_t
*src
, /* Source file */
2968 *dst
; /* Destination file */
2969 int bytes
; /* Bytes to read/write */
2970 char buffer
[2048]; /* Copy buffer */
2973 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
2976 * Open the source and destination file for a copy...
2979 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
2982 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
2989 * Copy the source file to the destination...
2992 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
2993 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
3001 * Close both files and return...
3006 return (cupsFileClose(dst
));
3011 * 'copy_model()' - Copy a PPD model file, substituting default values
3015 static int /* O - 0 = success, -1 = error */
3016 copy_model(const char *from
, /* I - Source file */
3017 const char *to
) /* I - Destination file */
3019 cups_file_t
*src
, /* Source file */
3020 *dst
; /* Destination file */
3021 char buffer
[2048]; /* Copy buffer */
3022 int i
; /* Looping var */
3023 char option
[PPD_MAX_NAME
], /* Option name */
3024 choice
[PPD_MAX_NAME
]; /* Choice name */
3025 int num_defaults
; /* Number of default options */
3026 ppd_default_t
*defaults
; /* Default options */
3027 char cups_protocol
[PPD_MAX_LINE
];
3028 /* cupsProtocol attribute */
3029 #ifdef HAVE_LIBPAPER
3030 char *paper_result
; /* Paper size name from libpaper */
3031 char system_paper
[64]; /* Paper size name buffer */
3032 #endif /* HAVE_LIBPAPER */
3035 LogMessage(L_DEBUG2
, "copy_model(\"%s\", \"%s\")\n", from
, to
);
3038 * Open the destination (if possible) and set the default options...
3043 cups_protocol
[0] = '\0';
3045 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
3048 * Read all of the default lines from the old PPD...
3051 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)) != NULL
)
3052 if (!strncmp(buffer
, "*Default", 8))
3055 * Add the default option...
3058 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3059 choice
, sizeof(choice
)))
3060 num_defaults
= ppd_add_default(option
, choice
, num_defaults
,
3063 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
3064 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
3068 #ifdef HAVE_LIBPAPER
3069 else if ((paper_result
= systempapername()) != NULL
)
3072 * Set the default media sizes from the systemwide default...
3075 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
3076 system_paper
[0] = toupper(system_paper
[0] & 255);
3078 num_defaults
= ppd_add_default("PageSize", system_paper
,
3079 num_defaults
, &defaults
);
3080 num_defaults
= ppd_add_default("PageRegion", system_paper
,
3081 num_defaults
, &defaults
);
3082 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
3083 num_defaults
, &defaults
);
3084 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
3085 num_defaults
, &defaults
);
3087 #endif /* HAVE_LIBPAPER */
3091 * Add the default media sizes...
3093 * Note: These values are generally not valid for large-format devices
3094 * like plotters, however it is probably safe to say that those
3095 * users will configure the media size after initially adding
3096 * the device anyways...
3099 if (!DefaultLanguage
||
3100 !strcasecmp(DefaultLanguage
, "C") ||
3101 !strcasecmp(DefaultLanguage
, "POSIX") ||
3102 !strcasecmp(DefaultLanguage
, "en") ||
3103 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
3104 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
3105 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
3108 * These are the only locales that will default to "letter" size...
3111 num_defaults
= ppd_add_default("PageSize", "Letter", num_defaults
,
3113 num_defaults
= ppd_add_default("PageRegion", "Letter", num_defaults
,
3115 num_defaults
= ppd_add_default("PaperDimension", "Letter", num_defaults
,
3117 num_defaults
= ppd_add_default("ImageableArea", "Letter", num_defaults
,
3123 * The rest default to "a4" size...
3126 num_defaults
= ppd_add_default("PageSize", "A4", num_defaults
,
3128 num_defaults
= ppd_add_default("PageRegion", "A4", num_defaults
,
3130 num_defaults
= ppd_add_default("PaperDimension", "A4", num_defaults
,
3132 num_defaults
= ppd_add_default("ImageableArea", "A4", num_defaults
,
3138 * Open the source and destination file for a copy...
3141 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3143 if (num_defaults
> 0)
3149 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3151 if (num_defaults
> 0)
3159 * Copy the source file to the destination...
3162 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3164 if (!strncmp(buffer
, "*Default", 8))
3167 * Check for an previous default option choice...
3170 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3171 choice
, sizeof(choice
)))
3173 for (i
= 0; i
< num_defaults
; i
++)
3174 if (!strcmp(option
, defaults
[i
].option
))
3177 * Substitute the previous choice...
3180 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
,
3181 defaults
[i
].choice
);
3187 cupsFilePrintf(dst
, "%s\n", buffer
);
3190 if (cups_protocol
[0])
3191 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
3193 if (num_defaults
> 0)
3197 * Close both files and return...
3202 return (cupsFileClose(dst
));
3207 * 'create_job()' - Print a file to a printer or class.
3211 create_job(client_t
*con
, /* I - Client connection */
3212 ipp_attribute_t
*uri
) /* I - Printer URI */
3214 ipp_attribute_t
*attr
; /* Current attribute */
3215 const char *dest
; /* Destination */
3216 cups_ptype_t dtype
; /* Destination type (printer or class) */
3217 int priority
; /* Job priority */
3218 char *title
; /* Job name/title */
3219 job_t
*job
; /* Current job */
3220 char job_uri
[HTTP_MAX_URI
], /* Job URI */
3221 method
[HTTP_MAX_URI
], /* Method portion of URI */
3222 username
[HTTP_MAX_URI
], /* Username portion of URI */
3223 host
[HTTP_MAX_URI
], /* Host portion of URI */
3224 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3225 int port
; /* Port portion of URI */
3226 printer_t
*printer
; /* Printer data */
3227 int kbytes
; /* Size of print file */
3228 int i
; /* Looping var */
3229 int lowerpagerange
; /* Page range bound */
3232 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3233 uri
->values
[0].string
.text
);
3236 * Verify that the POST operation was done to a valid URI.
3239 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3240 strncmp(con
->uri
, "/printers/", 10) != 0)
3242 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
3244 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3249 * Is the destination valid?
3252 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3254 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3260 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
3261 send_ipp_error(con
, IPP_NOT_FOUND
);
3266 * Check remote printing to non-shared printer...
3269 if (!printer
->shared
&&
3270 strcasecmp(con
->http
.hostname
, "localhost") &&
3271 strcasecmp(con
->http
.hostname
, ServerName
))
3273 LogMessage(L_ERROR
, "print_job: printer not shared!");
3274 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3282 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3284 LogMessage(L_ERROR
, "create_job: not authorized!");
3285 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3290 * See if the printer is accepting jobs...
3293 if (!printer
->accepting
)
3295 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
3297 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3302 * Validate job template attributes; for now just copies and page-ranges...
3305 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
3307 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
3309 LogMessage(L_INFO
, "create_job: bad copies value %d.",
3310 attr
->values
[0].integer
);
3311 send_ipp_error(con
, IPP_BAD_REQUEST
);
3316 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
3318 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
3320 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
3321 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3323 LogMessage(L_ERROR
, "create_job: bad page-ranges values %d-%d.",
3324 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3325 send_ipp_error(con
, IPP_BAD_REQUEST
);
3329 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
3334 * Make sure we aren't over our limit...
3337 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3340 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3342 LogMessage(L_INFO
, "create_job: too many jobs.");
3343 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3347 if (!check_quotas(con
, printer
))
3349 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3354 * Create the job and set things up...
3357 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3358 priority
= attr
->values
[0].integer
;
3360 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3363 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3364 title
= attr
->values
[0].string
.text
;
3366 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3367 title
= "Untitled");
3369 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3371 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
3373 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3378 job
->attrs
= con
->request
;
3379 con
->request
= NULL
;
3381 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3383 if (con
->username
[0])
3384 SetString(&job
->username
, con
->username
);
3385 else if (attr
!= NULL
)
3387 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
3388 attr
->values
[0].string
.text
);
3390 SetString(&job
->username
, attr
->values
[0].string
.text
);
3393 SetString(&job
->username
, "anonymous");
3396 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3397 NULL
, job
->username
);
3400 attr
->group_tag
= IPP_TAG_JOB
;
3401 SetString(&attr
->name
, "job-originating-user-name");
3404 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
3405 IPP_TAG_ZERO
)) != NULL
)
3408 * Request contains a job-originating-host-name attribute; validate it...
3411 if (attr
->value_tag
!= IPP_TAG_NAME
||
3412 attr
->num_values
!= 1 ||
3413 strcmp(con
->http
.hostname
, "localhost") != 0)
3416 * Can't override the value if we aren't connected via localhost.
3417 * Also, we can only have 1 value and it must be a name value.
3420 switch (attr
->value_tag
)
3422 case IPP_TAG_STRING
:
3423 case IPP_TAG_TEXTLANG
:
3424 case IPP_TAG_NAMELANG
:
3427 case IPP_TAG_KEYWORD
:
3429 case IPP_TAG_URISCHEME
:
3430 case IPP_TAG_CHARSET
:
3431 case IPP_TAG_LANGUAGE
:
3432 case IPP_TAG_MIMETYPE
:
3434 * Free old strings...
3437 for (i
= 0; i
< attr
->num_values
; i
++)
3439 free(attr
->values
[i
].string
.text
);
3440 attr
->values
[i
].string
.text
= NULL
;
3441 if (attr
->values
[i
].string
.charset
)
3443 free(attr
->values
[i
].string
.charset
);
3444 attr
->values
[i
].string
.charset
= NULL
;
3453 * Use the default connection hostname instead...
3456 attr
->value_tag
= IPP_TAG_NAME
;
3457 attr
->num_values
= 1;
3458 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
3461 attr
->group_tag
= IPP_TAG_JOB
;
3466 * No job-originating-host-name attribute, so use the hostname from
3470 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3471 "job-originating-host-name", NULL
, con
->http
.hostname
);
3474 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3476 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3477 "time-at-processing", 0);
3478 attr
->value_tag
= IPP_TAG_NOVALUE
;
3479 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3480 "time-at-completed", 0);
3481 attr
->value_tag
= IPP_TAG_NOVALUE
;
3484 * Add remaining job attributes...
3487 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3488 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3489 "job-state", IPP_JOB_STOPPED
);
3490 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3491 "job-media-sheets-completed", 0);
3492 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3494 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3497 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3498 attr
->values
[0].integer
= 0;
3500 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3503 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3504 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3506 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
3507 "job-hold-until", NULL
, "no-hold");
3508 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
3509 !(printer
->type
& CUPS_PRINTER_REMOTE
))
3512 * Hold job until specified time...
3515 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3518 job
->hold_until
= time(NULL
) + 60;
3520 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
3522 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
3526 * Add job sheets options...
3529 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
3531 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
3532 printer
->job_sheets
[0], printer
->job_sheets
[1]);
3534 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
3536 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
3537 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
3540 job
->job_sheets
= attr
;
3543 * Enforce classification level if set...
3548 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
3549 Classification
? Classification
: "(null)", ClassifyOverride
);
3551 if (ClassifyOverride
)
3553 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
3554 (attr
->num_values
== 1 ||
3555 strcmp(attr
->values
[1].string
.text
, "none") == 0))
3558 * Force the leading banner to have the classification on it...
3561 SetString(&attr
->values
[0].string
.text
, Classification
);
3563 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3564 "job-sheets=\"%s,none\", "
3565 "job-originating-user-name=\"%s\"",
3566 job
->id
, Classification
,
3569 else if (attr
->num_values
== 2 &&
3570 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
3571 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
3572 strcmp(attr
->values
[1].string
.text
, "none") != 0)
3575 * Can't put two different security markings on the same document!
3578 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
3580 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3581 "job-sheets=\"%s,%s\", "
3582 "job-originating-user-name=\"%s\"",
3583 job
->id
, attr
->values
[0].string
.text
,
3584 attr
->values
[1].string
.text
,
3587 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
3588 strcmp(attr
->values
[0].string
.text
, "none") &&
3589 (attr
->num_values
== 1 ||
3590 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
3591 strcmp(attr
->values
[1].string
.text
, "none"))))
3593 if (attr
->num_values
== 1)
3594 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3595 "job-sheets=\"%s\", "
3596 "job-originating-user-name=\"%s\"",
3597 job
->id
, attr
->values
[0].string
.text
,
3600 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3601 "job-sheets=\"%s,%s\",fffff "
3602 "job-originating-user-name=\"%s\"",
3603 job
->id
, attr
->values
[0].string
.text
,
3604 attr
->values
[1].string
.text
,
3608 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
3609 (attr
->num_values
== 1 ||
3610 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
3613 * Force the banner to have the classification on it...
3616 if (attr
->num_values
> 1 &&
3617 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
3619 SetString(&(attr
->values
[0].string
.text
), Classification
);
3620 SetString(&(attr
->values
[1].string
.text
), Classification
);
3624 if (attr
->num_values
== 1 ||
3625 strcmp(attr
->values
[0].string
.text
, "none"))
3626 SetString(&(attr
->values
[0].string
.text
), Classification
);
3628 if (attr
->num_values
> 1 &&
3629 strcmp(attr
->values
[1].string
.text
, "none"))
3630 SetString(&(attr
->values
[1].string
.text
), Classification
);
3633 if (attr
->num_values
> 1)
3634 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3635 "job-sheets=\"%s,%s\", "
3636 "job-originating-user-name=\"%s\"",
3637 job
->id
, attr
->values
[0].string
.text
,
3638 attr
->values
[1].string
.text
,
3641 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3642 "job-sheets=\"%s\", "
3643 "job-originating-user-name=\"%s\"",
3644 job
->id
, Classification
,
3650 * See if we need to add the starting sheet...
3653 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
3655 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
3656 attr
->values
[0].string
.text
, job
->id
);
3658 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
3660 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3663 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
3667 * Add any job subscriptions...
3670 add_job_subscriptions(con
, job
);
3673 * Set all but the first two attributes to the job attributes group...
3676 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
3677 attr
->group_tag
= IPP_TAG_JOB
;
3680 * Save and log the job...
3685 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
3686 job
->dest
, job
->username
);
3688 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
3691 * Fill in the response info...
3694 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3695 LocalPort
, job
->id
);
3697 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
3699 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3701 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
3702 job
->state
->values
[0].integer
);
3704 con
->response
->request
.status
.status_code
= IPP_OK
;
3709 * 'create_subscription()' - Create a notification subscription.
3713 create_subscription(
3714 client_t
*con
, /* I - Client connection */
3715 ipp_attribute_t
*uri
) /* I - Printer URI */
3721 * 'delete_printer()' - Remove a printer or class from the system.
3725 delete_printer(client_t
*con
, /* I - Client connection */
3726 ipp_attribute_t
*uri
) /* I - URI of printer or class */
3728 const char *dest
; /* Destination */
3729 cups_ptype_t dtype
; /* Destination type (printer or class) */
3730 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3731 username
[HTTP_MAX_URI
], /* Username portion of URI */
3732 host
[HTTP_MAX_URI
], /* Host portion of URI */
3733 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3734 int port
; /* Port portion of URI */
3735 printer_t
*printer
; /* Printer/class */
3736 char filename
[1024]; /* Script/PPD filename */
3739 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
3740 uri
->values
[0].string
.text
);
3743 * Was this operation called from the correct URI?
3746 if (strncmp(con
->uri
, "/admin/", 7) != 0)
3748 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
3750 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3755 * Do we have a valid URI?
3758 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3760 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3766 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
3767 send_ipp_error(con
, IPP_NOT_FOUND
);
3775 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3777 LogMessage(L_ERROR
, "delete_printer: not authorized!");
3778 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3783 * Remove old jobs...
3786 CancelJobs(dest
, NULL
, 1);
3789 * Remove old subscriptions and send a "deleted printer" event...
3792 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
3793 "%s \'%s\' deleted by \'%s\'.",
3794 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
3795 dest
, con
->username
);
3797 cupsdExpireSubscriptions(printer
, NULL
);
3800 * Remove any old PPD or script files...
3803 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
3806 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
3809 if (dtype
& CUPS_PRINTER_CLASS
)
3811 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
3814 DeletePrinter(printer
, 0);
3819 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
3822 DeletePrinter(printer
, 0);
3827 * Return with no errors...
3830 con
->response
->request
.status
.status_code
= IPP_OK
;
3835 * 'get_default()' - Get the default destination.
3839 get_default(client_t
*con
) /* I - Client connection */
3841 int i
; /* Looping var */
3842 ipp_attribute_t
*requested
, /* requested-attributes */
3843 *history
; /* History collection */
3844 int need_history
; /* Need to send history collection? */
3847 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
3853 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3855 LogMessage(L_ERROR
, "get_default: not authorized!");
3856 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3860 if (DefaultPrinter
!= NULL
)
3862 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3865 copy_attrs(con
->response
, DefaultPrinter
->attrs
, requested
, IPP_TAG_ZERO
, 0);
3866 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
3870 if (MaxPrinterHistory
> 0 && DefaultPrinter
->num_history
> 0 && requested
)
3872 for (i
= 0; i
< requested
->num_values
; i
++)
3873 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
3874 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
3883 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
3884 "printer-state-history",
3885 DefaultPrinter
->num_history
, NULL
);
3887 for (i
= 0; i
< DefaultPrinter
->num_history
; i
++)
3888 copy_attrs(history
->values
[i
].collection
= ippNew(),
3889 DefaultPrinter
->history
[i
],
3890 NULL
, IPP_TAG_ZERO
, 0);
3893 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
3896 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
3901 * 'get_devices()' - Get the list of available devices on the local system.
3905 get_devices(client_t
*con
) /* I - Client connection */
3907 int i
; /* Looping var */
3908 ipp_attribute_t
*limit
, /* Limit attribute */
3909 *requested
; /* requested-attributes attribute */
3910 char command
[1024], /* cups-deviced command */
3911 options
[1024], /* Options to pass to command */
3912 attrs
[1024], /* String for requested attributes */
3913 *aptr
; /* Pointer into string */
3914 int alen
; /* Length of attribute value */
3917 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
3923 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3925 LogMessage(L_ERROR
, "get_devices: not authorized!");
3926 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3931 * Run cups-deviced command with the given options...
3934 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
3935 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3940 for (i
= 0, aptr
= attrs
; i
< requested
->num_values
; i
++)
3943 * Check that we have enough room...
3946 alen
= strlen(requested
->values
[i
].string
.text
);
3947 if (alen
> (sizeof(attrs
) - (aptr
- attrs
) - 2))
3951 * Put commas between values...
3958 * Add the value to the end of the string...
3961 strcpy(aptr
, requested
->values
[i
].string
.text
);
3966 * If we have more attribute names than will fit, default to "all"...
3969 if (i
< requested
->num_values
)
3970 strcpy(attrs
, "all");
3973 strcpy(attrs
, "all");
3975 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
3976 snprintf(options
, sizeof(options
),
3977 "cups-deviced %d+%d+requested-attributes=%s",
3978 con
->request
->request
.op
.request_id
,
3979 limit
? limit
->values
[0].integer
: 0,
3982 if (SendCommand(con
, command
, options
, 1))
3985 * Command started successfully, don't send an IPP response here...
3988 ippDelete(con
->response
);
3989 con
->response
= NULL
;
3994 * Command failed, return "internal error" so the user knows something
3998 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
4004 * 'get_jobs()' - Get a list of jobs for the specified printer.
4008 get_jobs(client_t
*con
, /* I - Client connection */
4009 ipp_attribute_t
*uri
) /* I - Printer URI */
4011 ipp_attribute_t
*attr
, /* Current attribute */
4012 *requested
; /* Requested attributes */
4013 const char *dest
; /* Destination */
4014 cups_ptype_t dtype
; /* Destination type (printer or class) */
4015 cups_ptype_t dmask
; /* Destination type mask */
4016 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4017 username
[HTTP_MAX_URI
], /* Username portion of URI */
4018 host
[HTTP_MAX_URI
], /* Host portion of URI */
4019 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4020 int port
; /* Port portion of URI */
4021 int completed
; /* Completed jobs? */
4022 int limit
; /* Maximum number of jobs to return */
4023 int count
; /* Number of jobs that match */
4024 job_t
*job
; /* Current job pointer */
4025 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4026 printer_t
*printer
; /* Printer */
4029 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
4030 uri
->values
[0].string
.text
);
4033 * Is the destination valid?
4036 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4038 if (strcmp(resource
, "/") == 0 ||
4039 (strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6))
4042 dtype
= (cups_ptype_t
)0;
4043 dmask
= (cups_ptype_t
)0;
4046 else if (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10)
4049 dtype
= (cups_ptype_t
)0;
4050 dmask
= CUPS_PRINTER_CLASS
;
4053 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
4056 dtype
= CUPS_PRINTER_CLASS
;
4057 dmask
= CUPS_PRINTER_CLASS
;
4060 else if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4066 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
4067 send_ipp_error(con
, IPP_NOT_FOUND
);
4071 dmask
= CUPS_PRINTER_CLASS
;
4079 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4081 LogMessage(L_ERROR
, "get_jobs: not authorized!");
4082 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4086 else if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4088 LogMessage(L_ERROR
, "get_jobs: not authorized!");
4089 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4094 * See if the "which-jobs" attribute have been specified...
4097 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
4098 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
4104 * See if they want to limit the number of jobs reported...
4107 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4108 limit
= attr
->values
[0].integer
;
4113 * See if we only want to see jobs for a specific user...
4116 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
4117 attr
->values
[0].boolean
)
4119 if (con
->username
[0])
4120 strlcpy(username
, con
->username
, sizeof(username
));
4121 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4122 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
4124 strcpy(username
, "anonymous");
4129 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4133 * OK, build a list of jobs for this printer...
4136 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
4139 * Filter out jobs that don't match...
4142 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
4144 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0) &&
4145 (job
->printer
== NULL
|| dest
== NULL
||
4146 strcmp(job
->printer
->name
, dest
) != 0))
4148 if ((job
->dtype
& dmask
) != dtype
&&
4149 (job
->printer
== NULL
|| (job
->printer
->type
& dmask
) != dtype
))
4151 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
4154 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
4156 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4161 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
4164 * Send the requested attributes for each job...
4167 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4168 LocalPort
, job
->id
);
4170 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4171 "job-more-info", NULL
, job_uri
);
4173 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4174 "job-uri", NULL
, job_uri
);
4176 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4177 "job-printer-up-time", time(NULL
));
4180 * Copy the job attributes to the response using the requested-attributes
4181 * attribute that may be provided by the client.
4184 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4186 add_job_state_reasons(con
, job
);
4188 ippAddSeparator(con
->response
);
4191 if (requested
!= NULL
)
4192 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4194 con
->response
->request
.status
.status_code
= IPP_OK
;
4199 * 'get_job_attrs()' - Get job attributes.
4203 get_job_attrs(client_t
*con
, /* I - Client connection */
4204 ipp_attribute_t
*uri
) /* I - Job URI */
4206 ipp_attribute_t
*attr
, /* Current attribute */
4207 *requested
; /* Requested attributes */
4208 int jobid
; /* Job ID */
4209 job_t
*job
; /* Current job */
4210 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4211 username
[HTTP_MAX_URI
], /* Username portion of URI */
4212 host
[HTTP_MAX_URI
], /* Host portion of URI */
4213 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4214 int port
; /* Port portion of URI */
4215 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4218 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4219 uri
->values
[0].string
.text
);
4222 * See if we have a job URI or a printer URI...
4225 if (strcmp(uri
->name
, "printer-uri") == 0)
4228 * Got a printer URI; see if we also have a job-id attribute...
4231 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4233 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
4234 send_ipp_error(con
, IPP_BAD_REQUEST
);
4238 jobid
= attr
->values
[0].integer
;
4243 * Got a job URI; parse it to get the job ID...
4246 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4248 if (strncmp(resource
, "/jobs/", 6) != 0)
4254 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
4255 uri
->values
[0].string
.text
);
4256 send_ipp_error(con
, IPP_BAD_REQUEST
);
4260 jobid
= atoi(resource
+ 6);
4264 * See if the job exists...
4267 if ((job
= FindJob(jobid
)) == NULL
)
4270 * Nope - return a "not found" error...
4273 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
4274 send_ipp_error(con
, IPP_NOT_FOUND
);
4282 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4284 LogMessage(L_ERROR
, "get_job_attrs: not authorized!");
4285 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4290 * Put out the standard attributes...
4293 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
4294 ServerName
, LocalPort
, job
->id
);
4296 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4298 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4299 "job-more-info", NULL
, job_uri
);
4301 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4302 "job-uri", NULL
, job_uri
);
4304 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4305 "job-printer-up-time", time(NULL
));
4308 * Copy the job attributes to the response using the requested-attributes
4309 * attribute that may be provided by the client.
4312 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4315 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4317 add_job_state_reasons(con
, job
);
4319 if (requested
!= NULL
)
4320 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4322 con
->response
->request
.status
.status_code
= IPP_OK
;
4327 * 'get_notifications()' - Get events for a subscription.
4331 get_notifications(client_t
*con
, /* I - Client connection */
4332 int id
) /* I - Subscription ID */
4338 * 'get_ppds()' - Get the list of PPD files on the local system.
4342 get_ppds(client_t
*con
) /* I - Client connection */
4344 int i
; /* Looping var */
4345 ipp_attribute_t
*limit
, /* Limit attribute */
4346 *make
, /* ppd-make attribute */
4347 *requested
; /* requested-attributes attribute */
4348 char command
[1024], /* cups-deviced command */
4349 options
[1024], /* Options to pass to command */
4350 attrs
[1024], /* String for requested attributes */
4351 *aptr
; /* Pointer into string */
4352 int alen
; /* Length of attribute value */
4355 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
4361 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4363 LogMessage(L_ERROR
, "get_ppds: not authorized!");
4364 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4369 * Run cups-driverd command with the given options...
4372 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
4373 make
= ippFindAttribute(con
->request
, "ppd-make", IPP_TAG_KEYWORD
);
4374 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4379 for (i
= 0, aptr
= attrs
; i
< requested
->num_values
; i
++)
4382 * Check that we have enough room...
4385 alen
= strlen(requested
->values
[i
].string
.text
);
4386 if (alen
> (sizeof(attrs
) - (aptr
- attrs
) - 2))
4390 * Put commas between values...
4397 * Add the value to the end of the string...
4400 strcpy(aptr
, requested
->values
[i
].string
.text
);
4405 * If we have more attribute names than will fit, default to "all"...
4408 if (i
< requested
->num_values
)
4409 strcpy(attrs
, "all");
4412 strcpy(attrs
, "all");
4414 snprintf(command
, sizeof(command
), "%s/daemon/cups-driverd", ServerBin
);
4415 snprintf(options
, sizeof(options
),
4416 "cups-driverd %d+%d+requested-attributes=%s%s%s",
4417 con
->request
->request
.op
.request_id
,
4418 limit
? limit
->values
[0].integer
: 0,
4420 make
? " ppd-make=" : "",
4421 make
? make
->values
[0].string
.text
: "");
4423 if (SendCommand(con
, command
, options
, 0))
4426 * Command started successfully, don't send an IPP response here...
4429 ippDelete(con
->response
);
4430 con
->response
= NULL
;
4435 * Command failed, return "internal error" so the user knows something
4439 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
4445 * 'get_printer_attrs()' - Get printer attributes.
4449 get_printer_attrs(client_t
*con
, /* I - Client connection */
4450 ipp_attribute_t
*uri
) /* I - Printer URI */
4452 const char *dest
; /* Destination */
4453 cups_ptype_t dtype
; /* Destination type (printer or class) */
4454 char method
[HTTP_MAX_URI
],
4455 /* Method portion of URI */
4456 username
[HTTP_MAX_URI
],
4457 /* Username portion of URI */
4459 /* Host portion of URI */
4460 resource
[HTTP_MAX_URI
];
4461 /* Resource portion of URI */
4462 int port
; /* Port portion of URI */
4463 printer_t
*printer
; /* Printer/class */
4464 time_t curtime
; /* Current time */
4465 int i
; /* Looping var */
4466 ipp_attribute_t
*requested
, /* requested-attributes */
4467 *history
; /* History collection */
4468 int need_history
; /* Need to send history collection? */
4471 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4472 uri
->values
[0].string
.text
);
4475 * Is the destination valid?
4478 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4480 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4486 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
4487 send_ipp_error(con
, IPP_NOT_FOUND
);
4495 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4497 LogMessage(L_ERROR
, "get_printer_attrs: not authorized!");
4498 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4502 curtime
= time(NULL
);
4505 * Copy the printer attributes to the response using requested-attributes
4506 * and document-format attributes that may be provided by the client.
4509 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4512 add_printer_state_reasons(con
, printer
);
4514 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4515 "printer-state-message", NULL
, printer
->state_message
);
4517 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4518 printer
->accepting
);
4519 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
4522 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4523 "printer-up-time", curtime
);
4524 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4525 "printer-state-time", printer
->state_time
);
4526 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4527 ippTimeToDate(curtime
));
4529 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4530 "printer-error-policy", NULL
, printer
->op_policy
);
4531 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4532 "printer-op-policy", NULL
, printer
->op_policy
);
4534 add_queued_job_count(con
, printer
);
4536 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4539 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4540 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4544 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 && requested
)
4546 for (i
= 0; i
< requested
->num_values
; i
++)
4547 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4548 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4557 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4558 "printer-state-history",
4559 printer
->num_history
, NULL
);
4561 for (i
= 0; i
< printer
->num_history
; i
++)
4562 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4563 NULL
, IPP_TAG_ZERO
, 0);
4566 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4571 * 'get_printers()' - Get a list of printers or classes.
4575 get_printers(client_t
*con
, /* I - Client connection */
4576 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
4578 int i
; /* Looping var */
4579 ipp_attribute_t
*requested
, /* requested-attributes */
4580 *history
, /* History collection */
4581 *attr
; /* Current attribute */
4582 int need_history
; /* Need to send history collection? */
4583 int limit
; /* Maximum number of printers to return */
4584 int count
; /* Number of printers that match */
4585 printer_t
*printer
; /* Current printer pointer */
4586 time_t curtime
; /* Current time */
4587 int printer_type
, /* printer-type attribute */
4588 printer_mask
; /* printer-type-mask attribute */
4589 char *location
; /* Location string */
4590 char name
[IPP_MAX_NAME
], /* Printer name */
4591 *nameptr
; /* Pointer into name */
4592 printer_t
*iclass
; /* Implicit class */
4593 const char *username
; /* Current user */
4596 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
4602 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4604 LogMessage(L_ERROR
, "get_printers: not authorized!");
4605 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4610 * See if they want to limit the number of printers reported...
4613 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4614 limit
= attr
->values
[0].integer
;
4619 * Support filtering...
4622 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
4623 printer_type
= attr
->values
[0].integer
;
4627 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
4628 printer_mask
= attr
->values
[0].integer
;
4632 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
4633 location
= attr
->values
[0].string
.text
;
4637 if (con
->username
[0])
4638 username
= con
->username
;
4639 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4640 username
= attr
->values
[0].string
.text
;
4644 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4649 if (MaxPrinterHistory
> 0 && requested
)
4651 for (i
= 0; i
< requested
->num_values
; i
++)
4652 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4653 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4661 * OK, build a list of printers for this printer...
4664 curtime
= time(NULL
);
4666 for (count
= 0, printer
= Printers
;
4667 count
< limit
&& printer
!= NULL
;
4668 printer
= printer
->next
)
4669 if ((!type
|| (printer
->type
& CUPS_PRINTER_CLASS
) == type
) &&
4670 (printer
->type
& printer_mask
) == printer_type
&&
4671 (location
== NULL
|| printer
->location
== NULL
||
4672 !strcasecmp(printer
->location
, location
)))
4675 * If HideImplicitMembers is enabled, see if this printer or class
4676 * is a member of an implicit class...
4679 if (ImplicitClasses
&& HideImplicitMembers
&&
4680 (printer
->type
& CUPS_PRINTER_REMOTE
))
4683 * Make a copy of the printer name...
4686 strlcpy(name
, printer
->name
, sizeof(name
));
4688 if ((nameptr
= strchr(name
, '@')) != NULL
)
4691 * Strip trailing @server...
4697 * Find the core printer, if any...
4700 if ((iclass
= FindPrinter(name
)) != NULL
&&
4701 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
4707 * If a username is specified, see if it is allowed or denied
4711 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
4715 * Add the group separator as needed...
4719 ippAddSeparator(con
->response
);
4724 * Send the following attributes for each printer:
4727 * printer-state-message
4728 * printer-is-accepting-jobs
4731 * printer-state-time
4732 * + all printer attributes
4735 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
4736 "printer-state", printer
->state
);
4738 add_printer_state_reasons(con
, printer
);
4740 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4741 "printer-state-message", NULL
, printer
->state_message
);
4743 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4744 printer
->accepting
);
4745 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-shared",
4748 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4749 "printer-up-time", curtime
);
4750 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4751 "printer-state-time", printer
->state_time
);
4752 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4753 ippTimeToDate(curtime
));
4755 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4756 "printer-error-policy", NULL
, printer
->op_policy
);
4757 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4758 "printer-op-policy", NULL
, printer
->op_policy
);
4760 add_queued_job_count(con
, printer
);
4762 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4764 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
,
4767 if (need_history
&& printer
->num_history
> 0)
4769 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4770 "printer-state-history",
4771 printer
->num_history
, NULL
);
4773 for (i
= 0; i
< printer
->num_history
; i
++)
4774 copy_attrs(history
->values
[i
].collection
= ippNew(),
4775 printer
->history
[i
], NULL
, IPP_TAG_ZERO
, 0);
4779 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4784 * 'get_subscription_attrs()' - Get subscription attributes.
4788 get_subscription_attrs(client_t
*con
, /* I - Client connection */
4789 int sub_id
) /* I - Subscription ID */
4795 * 'get_subscriptions()' - Get subscriptions.
4799 get_subscriptions(client_t
*con
, /* I - Client connection */
4800 ipp_attribute_t
*uri
) /* I - Printer URI */
4806 * 'hold_job()' - Hold a print job.
4810 hold_job(client_t
*con
, /* I - Client connection */
4811 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4813 ipp_attribute_t
*attr
, /* Current job-hold-until */
4814 *newattr
; /* New job-hold-until */
4815 int jobid
; /* Job ID */
4816 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4817 username
[HTTP_MAX_URI
], /* Username portion of URI */
4818 host
[HTTP_MAX_URI
], /* Host portion of URI */
4819 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4820 int port
; /* Port portion of URI */
4821 job_t
*job
; /* Job information */
4824 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4825 uri
->values
[0].string
.text
);
4828 * Verify that the POST operation was done to a valid URI.
4831 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4832 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4833 strncmp(con
->uri
, "/printers/", 10) != 0)
4835 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
4837 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4842 * See if we have a job URI or a printer URI...
4845 if (strcmp(uri
->name
, "printer-uri") == 0)
4848 * Got a printer URI; see if we also have a job-id attribute...
4851 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4853 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
4854 send_ipp_error(con
, IPP_BAD_REQUEST
);
4858 jobid
= attr
->values
[0].integer
;
4863 * Got a job URI; parse it to get the job ID...
4866 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4868 if (strncmp(resource
, "/jobs/", 6) != 0)
4874 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
4875 uri
->values
[0].string
.text
);
4876 send_ipp_error(con
, IPP_BAD_REQUEST
);
4880 jobid
= atoi(resource
+ 6);
4884 * See if the job exists...
4887 if ((job
= FindJob(jobid
)) == NULL
)
4890 * Nope - return a "not found" error...
4893 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
4894 send_ipp_error(con
, IPP_NOT_FOUND
);
4899 * See if the job is owned by the requesting user...
4902 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4904 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
4905 username
, jobid
, job
->username
);
4906 send_ipp_error(con
, IPP_FORBIDDEN
);
4911 * Hold the job and return...
4916 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4917 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
4919 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4920 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4925 * Free the old hold value and copy the new one over...
4928 free(attr
->values
[0].string
.text
);
4930 if (newattr
!= NULL
)
4932 attr
->value_tag
= newattr
->value_tag
;
4933 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
4937 attr
->value_tag
= IPP_TAG_KEYWORD
;
4938 attr
->values
[0].string
.text
= strdup("indefinite");
4942 * Hold job until specified time...
4945 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4948 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
4950 con
->response
->request
.status
.status_code
= IPP_OK
;
4955 * 'move_job()' - Move a job to a new destination.
4959 move_job(client_t
*con
, /* I - Client connection */
4960 ipp_attribute_t
*uri
) /* I - Job URI */
4962 ipp_attribute_t
*attr
; /* Current attribute */
4963 int jobid
; /* Job ID */
4964 job_t
*job
; /* Current job */
4965 const char *dest
; /* Destination */
4966 cups_ptype_t dtype
; /* Destination type (printer or class) */
4967 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4968 username
[HTTP_MAX_URI
], /* Username portion of URI */
4969 host
[HTTP_MAX_URI
], /* Host portion of URI */
4970 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4971 int port
; /* Port portion of URI */
4972 printer_t
*printer
; /* Printer */
4975 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4976 uri
->values
[0].string
.text
);
4979 * See if we have a job URI or a printer URI...
4982 if (strcmp(uri
->name
, "printer-uri") == 0)
4985 * Got a printer URI; see if we also have a job-id attribute...
4988 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4990 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
4991 send_ipp_error(con
, IPP_BAD_REQUEST
);
4995 jobid
= attr
->values
[0].integer
;
5000 * Got a job URI; parse it to get the job ID...
5003 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5005 if (strncmp(resource
, "/jobs/", 6) != 0)
5011 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
5012 uri
->values
[0].string
.text
);
5013 send_ipp_error(con
, IPP_BAD_REQUEST
);
5017 jobid
= atoi(resource
+ 6);
5021 * See if the job exists...
5024 if ((job
= FindJob(jobid
)) == NULL
)
5027 * Nope - return a "not found" error...
5030 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
5031 send_ipp_error(con
, IPP_NOT_FOUND
);
5036 * See if the job has been completed...
5039 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
5042 * Return a "not-possible" error...
5045 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
5046 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5051 * See if the job is owned by the requesting user...
5054 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
5056 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
5057 username
, jobid
, job
->username
);
5058 send_ipp_error(con
, IPP_FORBIDDEN
);
5062 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
5065 * Need job-printer-uri...
5068 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
5069 send_ipp_error(con
, IPP_BAD_REQUEST
);
5074 * Get the new printer or class...
5077 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
5079 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5085 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
5086 send_ipp_error(con
, IPP_NOT_FOUND
);
5094 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5096 LogMessage(L_ERROR
, "move_job: not authorized!");
5097 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5102 * Move the job to a different printer or class...
5105 MoveJob(jobid
, dest
);
5108 * Start jobs if possible...
5114 * Return with "everything is OK" status...
5117 con
->response
->request
.status
.status_code
= IPP_OK
;
5122 * 'ppd_add_default()' - Add a PPD default choice.
5125 static int /* O - Number of defaults */
5127 const char *option
, /* I - Option name */
5128 const char *choice
, /* I - Choice name */
5129 int num_defaults
, /* I - Number of defaults */
5130 ppd_default_t
**defaults
) /* IO - Defaults */
5132 int i
; /* Looping var */
5133 ppd_default_t
*temp
; /* Temporary defaults array */
5137 * First check if the option already has a default value; the PPD spec
5138 * says that the first one is used...
5141 for (i
= 0, temp
= *defaults
; i
< num_defaults
; i
++)
5142 if (!strcmp(option
, temp
[i
].option
))
5143 return (num_defaults
);
5146 * Now add the option...
5149 if (num_defaults
== 0)
5150 temp
= malloc(sizeof(ppd_default_t
));
5152 temp
= realloc(*defaults
, (num_defaults
+ 1) * sizeof(ppd_default_t
));
5156 LogMessage(L_ERROR
, "ppd_add_default: Unable to add default value for \"%s\" - %s",
5157 option
, strerror(errno
));
5158 return (num_defaults
);
5162 temp
+= num_defaults
;
5164 strlcpy(temp
->option
, option
, sizeof(temp
->option
));
5165 strlcpy(temp
->choice
, choice
, sizeof(temp
->choice
));
5167 return (num_defaults
+ 1);
5172 * 'ppd_parse_line()' - Parse a PPD default line.
5175 static int /* O - 0 on success, -1 on failure */
5176 ppd_parse_line(const char *line
, /* I - Line */
5177 char *option
, /* O - Option name */
5178 int olen
, /* I - Size of option name */
5179 char *choice
, /* O - Choice name */
5180 int clen
) /* I - Size of choice name */
5183 * Verify this is a default option line...
5186 if (strncmp(line
, "*Default", 8))
5190 * Read the option name...
5193 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
5203 * Skip everything else up to the colon (:)...
5206 while (*line
&& *line
!= ':')
5215 * Now grab the option choice, skipping leading whitespace...
5218 while (isspace(*line
& 255))
5221 for (clen
--; isalnum(*line
& 255); line
++)
5231 * Return with no errors...
5239 * 'print_job()' - Print a file to a printer or class.
5243 print_job(client_t
*con
, /* I - Client connection */
5244 ipp_attribute_t
*uri
) /* I - Printer URI */
5246 ipp_attribute_t
*attr
; /* Current attribute */
5247 ipp_attribute_t
*format
; /* Document-format attribute */
5248 const char *dest
; /* Destination */
5249 cups_ptype_t dtype
; /* Destination type (printer or class) */
5250 int priority
; /* Job priority */
5251 char *title
; /* Job name/title */
5252 job_t
*job
; /* Current job */
5253 int jobid
; /* Job ID number */
5254 char job_uri
[HTTP_MAX_URI
], /* Job URI */
5255 method
[HTTP_MAX_URI
], /* Method portion of URI */
5256 username
[HTTP_MAX_URI
], /* Username portion of URI */
5257 host
[HTTP_MAX_URI
], /* Host portion of URI */
5258 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5259 filename
[1024]; /* Job filename */
5260 int port
; /* Port portion of URI */
5261 mime_type_t
*filetype
; /* Type of file */
5262 char super
[MIME_MAX_SUPER
], /* Supertype of file */
5263 type
[MIME_MAX_TYPE
], /* Subtype of file */
5264 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
5265 /* Textual name of mime type */
5266 printer_t
*printer
; /* Printer data */
5267 struct stat fileinfo
; /* File information */
5268 int kbytes
; /* Size of file */
5269 int i
; /* Looping var */
5270 int lowerpagerange
; /* Page range bound */
5271 int compression
; /* Document compression */
5274 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5275 uri
->values
[0].string
.text
);
5278 * Verify that the POST operation was done to a valid URI.
5281 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5282 strncmp(con
->uri
, "/printers/", 10) != 0)
5284 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
5286 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5291 * Validate job template attributes; for now just copies and page-ranges...
5294 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
5296 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
5298 LogMessage(L_INFO
, "print_job: bad copies value %d.",
5299 attr
->values
[0].integer
);
5300 send_ipp_error(con
, IPP_BAD_REQUEST
);
5305 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
5307 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
5309 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
5310 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5312 LogMessage(L_ERROR
, "print_job: bad page-ranges values %d-%d.",
5313 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
5314 send_ipp_error(con
, IPP_BAD_REQUEST
);
5318 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
5323 * OK, see if the client is sending the document compressed - CUPS
5324 * only supports "none" and "gzip".
5327 compression
= CUPS_FILE_NONE
;
5329 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
5331 if (strcmp(attr
->values
[0].string
.text
, "none")
5333 && strcmp(attr
->values
[0].string
.text
, "gzip")
5334 #endif /* HAVE_LIBZ */
5337 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
5338 attr
->values
[0].string
.text
);
5339 send_ipp_error(con
, IPP_ATTRIBUTES
);
5340 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5341 "compression", NULL
, attr
->values
[0].string
.text
);
5346 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
5347 compression
= CUPS_FILE_GZIP
;
5348 #endif /* HAVE_LIBZ */
5352 * Do we have a file to print?
5357 LogMessage(L_ERROR
, "print_job: No file!?!");
5358 send_ipp_error(con
, IPP_BAD_REQUEST
);
5363 * Is it a format we support?
5366 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5369 * Grab format from client...
5372 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5374 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
5375 format
->values
[0].string
.text
);
5376 send_ipp_error(con
, IPP_BAD_REQUEST
);
5383 * No document format attribute? Auto-type it!
5386 strcpy(super
, "application");
5387 strcpy(type
, "octet-stream");
5390 if (strcmp(super
, "application") == 0 &&
5391 strcmp(type
, "octet-stream") == 0)
5394 * Auto-type the file...
5397 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
5399 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
5401 if (filetype
!= NULL
)
5404 * Replace the document-format attribute value with the auto-typed one.
5407 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
5412 free(format
->values
[0].string
.text
);
5413 format
->values
[0].string
.text
= strdup(mimetype
);
5416 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
5417 "document-format", NULL
, mimetype
);
5420 filetype
= mimeType(MimeDatabase
, super
, type
);
5423 filetype
= mimeType(MimeDatabase
, super
, type
);
5425 if (filetype
== NULL
)
5427 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
5429 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
5430 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5433 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5434 "document-format", NULL
, format
->values
[0].string
.text
);
5439 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
5440 filetype
->super
, filetype
->type
);
5443 * Read any embedded job ticket info from PS files...
5446 if (strcasecmp(filetype
->super
, "application") == 0 &&
5447 strcasecmp(filetype
->type
, "postscript") == 0)
5448 read_ps_job_ticket(con
);
5451 * Is the destination valid?
5454 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5456 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5462 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
5463 send_ipp_error(con
, IPP_NOT_FOUND
);
5468 * Check remote printing to non-shared printer...
5471 if (!printer
->shared
&&
5472 strcasecmp(con
->http
.hostname
, "localhost") &&
5473 strcasecmp(con
->http
.hostname
, ServerName
))
5475 LogMessage(L_ERROR
, "print_job: printer not shared!");
5476 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5484 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5486 LogMessage(L_ERROR
, "print_job: not authorized!");
5487 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5492 * See if the printer is accepting jobs...
5495 if (!printer
->accepting
)
5497 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
5499 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
5504 * Make sure we aren't over our limit...
5507 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5510 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5512 LogMessage(L_INFO
, "print_job: too many jobs - %d jobs, max jobs is %d.",
5514 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5518 if (!check_quotas(con
, printer
))
5520 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5525 * Create the job and set things up...
5528 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
5529 priority
= attr
->values
[0].integer
;
5531 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
5534 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
5535 title
= attr
->values
[0].string
.text
;
5537 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5538 title
= "Untitled");
5540 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
5542 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
5544 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
5549 job
->attrs
= con
->request
;
5550 con
->request
= NULL
;
5553 * Copy the rest of the job info...
5556 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
5558 if (con
->username
[0])
5559 SetString(&job
->username
, con
->username
);
5560 else if (attr
!= NULL
)
5562 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
5563 attr
->values
[0].string
.text
);
5565 SetString(&job
->username
, attr
->values
[0].string
.text
);
5568 SetString(&job
->username
, "anonymous");
5571 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
5572 NULL
, job
->username
);
5575 attr
->group_tag
= IPP_TAG_JOB
;
5576 SetString(&attr
->name
, "job-originating-user-name");
5580 * Add remaining job attributes...
5583 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
5584 IPP_TAG_ZERO
)) != NULL
)
5587 * Request contains a job-originating-host-name attribute; validate it...
5590 if (attr
->value_tag
!= IPP_TAG_NAME
||
5591 attr
->num_values
!= 1 ||
5592 strcmp(con
->http
.hostname
, "localhost") != 0)
5595 * Can't override the value if we aren't connected via localhost.
5596 * Also, we can only have 1 value and it must be a name value.
5599 switch (attr
->value_tag
)
5601 case IPP_TAG_STRING
:
5602 case IPP_TAG_TEXTLANG
:
5603 case IPP_TAG_NAMELANG
:
5606 case IPP_TAG_KEYWORD
:
5608 case IPP_TAG_URISCHEME
:
5609 case IPP_TAG_CHARSET
:
5610 case IPP_TAG_LANGUAGE
:
5611 case IPP_TAG_MIMETYPE
:
5613 * Free old strings...
5616 for (i
= 0; i
< attr
->num_values
; i
++)
5618 free(attr
->values
[i
].string
.text
);
5619 attr
->values
[i
].string
.text
= NULL
;
5620 if (attr
->values
[i
].string
.charset
)
5622 free(attr
->values
[i
].string
.charset
);
5623 attr
->values
[i
].string
.charset
= NULL
;
5632 * Use the default connection hostname instead...
5635 attr
->value_tag
= IPP_TAG_NAME
;
5636 attr
->num_values
= 1;
5637 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
5640 attr
->group_tag
= IPP_TAG_JOB
;
5645 * No job-originating-host-name attribute, so use the hostname from
5649 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
5650 "job-originating-host-name", NULL
, con
->http
.hostname
);
5653 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
5654 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
5655 "job-state", IPP_JOB_PENDING
);
5656 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5657 "job-media-sheets-completed", 0);
5658 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
5660 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5663 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
5664 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5667 if (stat(con
->filename
, &fileinfo
))
5670 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
5672 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5673 attr
->values
[0].integer
+= kbytes
;
5675 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
5677 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5678 "time-at-processing", 0);
5679 attr
->value_tag
= IPP_TAG_NOVALUE
;
5680 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5681 "time-at-completed", 0);
5682 attr
->value_tag
= IPP_TAG_NOVALUE
;
5684 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5685 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
5687 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
5688 "job-hold-until", NULL
, "no-hold");
5690 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
5691 !(printer
->type
& CUPS_PRINTER_REMOTE
))
5694 * Hold job until specified time...
5697 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
5698 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5701 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
5705 * Add job sheets options...
5708 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
5710 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
5711 printer
->job_sheets
[0], printer
->job_sheets
[1]);
5713 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
5715 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
5716 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
5719 job
->job_sheets
= attr
;
5722 * Enforce classification level if set...
5727 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
5728 Classification
? Classification
: "(null)", ClassifyOverride
);
5730 if (ClassifyOverride
)
5732 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
5733 (attr
->num_values
== 1 ||
5734 strcmp(attr
->values
[1].string
.text
, "none") == 0))
5737 * Force the leading banner to have the classification on it...
5740 SetString(&attr
->values
[0].string
.text
, Classification
);
5742 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5743 "job-sheets=\"%s,none\", "
5744 "job-originating-user-name=\"%s\"",
5745 job
->id
, Classification
,
5748 else if (attr
->num_values
== 2 &&
5749 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
5750 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
5751 strcmp(attr
->values
[1].string
.text
, "none") != 0)
5754 * Can't put two different security markings on the same document!
5757 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
5759 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5760 "job-sheets=\"%s,%s\", "
5761 "job-originating-user-name=\"%s\"",
5762 job
->id
, attr
->values
[0].string
.text
,
5763 attr
->values
[1].string
.text
,
5766 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
5767 strcmp(attr
->values
[0].string
.text
, "none") &&
5768 (attr
->num_values
== 1 ||
5769 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
5770 strcmp(attr
->values
[1].string
.text
, "none"))))
5772 if (attr
->num_values
== 1)
5773 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5774 "job-sheets=\"%s\", "
5775 "job-originating-user-name=\"%s\"",
5776 job
->id
, attr
->values
[0].string
.text
,
5779 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5780 "job-sheets=\"%s,%s\", "
5781 "job-originating-user-name=\"%s\"",
5782 job
->id
, attr
->values
[0].string
.text
,
5783 attr
->values
[1].string
.text
,
5787 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
5788 (attr
->num_values
== 1 ||
5789 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
5792 * Force the banner to have the classification on it...
5795 if (attr
->num_values
> 1 &&
5796 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
5798 SetString(&(attr
->values
[0].string
.text
), Classification
);
5799 SetString(&(attr
->values
[1].string
.text
), Classification
);
5803 if (attr
->num_values
== 1 ||
5804 strcmp(attr
->values
[0].string
.text
, "none"))
5805 SetString(&(attr
->values
[0].string
.text
), Classification
);
5807 if (attr
->num_values
> 1 &&
5808 strcmp(attr
->values
[1].string
.text
, "none"))
5809 SetString(&(attr
->values
[1].string
.text
), Classification
);
5812 if (attr
->num_values
> 1)
5813 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5814 "job-sheets=\"%s,%s\", "
5815 "job-originating-user-name=\"%s\"",
5816 job
->id
, attr
->values
[0].string
.text
,
5817 attr
->values
[1].string
.text
,
5820 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5821 "job-sheets=\"%s\", "
5822 "job-originating-user-name=\"%s\"",
5823 job
->id
, Classification
,
5829 * Add the starting sheet...
5832 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
5834 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
5835 attr
->values
[0].string
.text
, job
->id
);
5837 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
5839 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5842 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
5846 * Add the job file...
5849 if (add_file(con
, job
, filetype
, compression
))
5852 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
5854 rename(con
->filename
, filename
);
5855 ClearString(&con
->filename
);
5858 * See if we need to add the ending sheet...
5861 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
5862 attr
->num_values
> 1)
5868 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
5869 attr
->values
[1].string
.text
, job
->id
);
5871 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
5873 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5877 * Add any job subscriptions...
5880 add_job_subscriptions(con
, job
);
5883 * Set all but the first two attributes to the job attributes group...
5886 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
5887 attr
->group_tag
= IPP_TAG_JOB
;
5890 * Log and save the job...
5893 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
5894 job
->dest
, job
->username
);
5895 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, (int)job
->hold_until
);
5899 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
5902 * Start the job if possible... Since CheckJobs() can cancel a job if it
5903 * doesn't print, we need to re-find the job afterwards...
5910 job
= FindJob(jobid
);
5913 * Fill in the response info...
5916 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
5919 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
5921 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
5923 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
5924 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
5925 add_job_state_reasons(con
, job
);
5927 con
->response
->request
.status
.status_code
= IPP_OK
;
5932 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
5934 * This function only gets called when printing a single PostScript
5935 * file using the Print-Job operation. It doesn't work for Create-Job +
5936 * Send-File, since the job attributes need to be set at job creation
5937 * time for banners to work. The embedded PS job ticket stuff is here
5938 * only to allow the Windows printer driver for CUPS to pass in JCL
5939 * options and IPP attributes which otherwise would be lost.
5941 * The format of a PS job ticket is simple:
5943 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
5945 * %cupsJobTicket: attr1=value1
5946 * %cupsJobTicket: attr2=value2
5948 * %cupsJobTicket: attrN=valueN
5950 * Job ticket lines must appear immediately after the first line that
5951 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
5952 * looking for job ticket info when it finds a line that does not begin
5953 * with "%cupsJobTicket:".
5955 * The maximum length of a job ticket line, including the prefix, is
5956 * 255 characters to conform with the Adobe DSC.
5958 * Read-only attributes are rejected with a notice to the error log in
5959 * case a malicious user tries anything. Since the job ticket is read
5960 * prior to attribute validation in print_job(), job ticket attributes
5961 * will go through the same validation as IPP attributes...
5965 read_ps_job_ticket(client_t
*con
) /* I - Client connection */
5967 cups_file_t
*fp
; /* File to read from */
5968 char line
[256]; /* Line data */
5969 int num_options
; /* Number of options */
5970 cups_option_t
*options
; /* Options */
5971 ipp_t
*ticket
; /* New attributes */
5972 ipp_attribute_t
*attr
, /* Current attribute */
5973 *attr2
, /* Job attribute */
5974 *prev2
; /* Previous job attribute */
5978 * First open the print file...
5981 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
5983 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to open PostScript print file - %s",
5989 * Skip the first line...
5992 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
5994 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to read from PostScript print file - %s",
6000 if (strncmp(line
, "%!PS-Adobe-", 11) != 0)
6003 * Not a DSC-compliant file, so no job ticket info will be available...
6011 * Read job ticket info from the file...
6017 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
6020 * Stop at the first non-ticket line...
6023 if (strncmp(line
, "%cupsJobTicket:", 15) != 0)
6027 * Add the options to the option array...
6030 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
6034 * Done with the file; see if we have any options...
6039 if (num_options
== 0)
6043 * OK, convert the options to an attribute list, and apply them to
6048 cupsEncodeOptions(ticket
, num_options
, options
);
6051 * See what the user wants to change.
6054 for (attr
= ticket
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6056 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6059 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
6060 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
6061 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
6062 strcmp(attr
->name
, "job-k-octets") == 0 ||
6063 strcmp(attr
->name
, "job-id") == 0 ||
6064 strncmp(attr
->name
, "job-state", 9) == 0 ||
6065 strncmp(attr
->name
, "time-at-", 8) == 0)
6066 continue; /* Read-only attrs */
6068 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
6071 * Some other value; first free the old value...
6074 if (con
->request
->attrs
== attr2
)
6076 con
->request
->attrs
= attr2
->next
;
6081 for (prev2
= con
->request
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
6082 if (prev2
->next
== attr2
)
6084 prev2
->next
= attr2
->next
;
6089 if (con
->request
->last
== attr2
)
6090 con
->request
->last
= prev2
;
6092 _ipp_free_attr(attr2
);
6096 * Add new option by copying it...
6099 copy_attribute(con
->request
, attr
, 0);
6103 * Then free the attribute list and option array...
6107 cupsFreeOptions(num_options
, options
);
6112 * 'reject_jobs()' - Reject print jobs to a printer.
6116 reject_jobs(client_t
*con
, /* I - Client connection */
6117 ipp_attribute_t
*uri
) /* I - Printer or class URI */
6119 cups_ptype_t dtype
; /* Destination type (printer or class) */
6120 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6121 username
[HTTP_MAX_URI
], /* Username portion of URI */
6122 host
[HTTP_MAX_URI
], /* Host portion of URI */
6123 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6124 int port
; /* Port portion of URI */
6125 const char *name
; /* Printer name */
6126 printer_t
*printer
; /* Printer data */
6127 ipp_attribute_t
*attr
; /* printer-state-message text */
6130 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
6131 uri
->values
[0].string
.text
);
6134 * Was this operation called from the correct URI?
6137 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6139 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
6141 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6146 * Is the destination valid?
6149 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6151 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6157 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
6158 send_ipp_error(con
, IPP_NOT_FOUND
);
6166 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
6168 LogMessage(L_ERROR
, "reject_jobs: not authorized!");
6169 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6174 * Reject jobs sent to the printer...
6177 printer
->accepting
= 0;
6179 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
6180 IPP_TAG_TEXT
)) == NULL
)
6181 strcpy(printer
->state_message
, "Rejecting Jobs");
6183 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
6184 sizeof(printer
->state_message
));
6186 AddPrinterHistory(printer
);
6188 if (dtype
& CUPS_PRINTER_CLASS
)
6192 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
6199 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
6204 * Everything was ok, so return OK status...
6207 con
->response
->request
.status
.status_code
= IPP_OK
;
6212 * 'release_job()' - Release a held print job.
6216 release_job(client_t
*con
, /* I - Client connection */
6217 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6219 ipp_attribute_t
*attr
; /* Current attribute */
6220 int jobid
; /* Job ID */
6221 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6222 username
[HTTP_MAX_URI
], /* Username portion of URI */
6223 host
[HTTP_MAX_URI
], /* Host portion of URI */
6224 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6225 int port
; /* Port portion of URI */
6226 job_t
*job
; /* Job information */
6229 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6230 uri
->values
[0].string
.text
);
6233 * Verify that the POST operation was done to a valid URI.
6236 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6237 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6238 strncmp(con
->uri
, "/printers/", 10) != 0)
6240 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
6242 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6247 * See if we have a job URI or a printer URI...
6250 if (strcmp(uri
->name
, "printer-uri") == 0)
6253 * Got a printer URI; see if we also have a job-id attribute...
6256 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6258 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
6259 send_ipp_error(con
, IPP_BAD_REQUEST
);
6263 jobid
= attr
->values
[0].integer
;
6268 * Got a job URI; parse it to get the job ID...
6271 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6273 if (strncmp(resource
, "/jobs/", 6) != 0)
6279 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
6280 uri
->values
[0].string
.text
);
6281 send_ipp_error(con
, IPP_BAD_REQUEST
);
6285 jobid
= atoi(resource
+ 6);
6289 * See if the job exists...
6292 if ((job
= FindJob(jobid
)) == NULL
)
6295 * Nope - return a "not found" error...
6298 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
6299 send_ipp_error(con
, IPP_NOT_FOUND
);
6304 * See if job is "held"...
6307 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
6310 * Nope - return a "not possible" error...
6313 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
6314 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6319 * See if the job is owned by the requesting user...
6322 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6324 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
6325 username
, jobid
, job
->username
);
6326 send_ipp_error(con
, IPP_FORBIDDEN
);
6331 * Reset the job-hold-until value to "no-hold"...
6334 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6335 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6339 free(attr
->values
[0].string
.text
);
6340 attr
->value_tag
= IPP_TAG_KEYWORD
;
6341 attr
->values
[0].string
.text
= strdup("no-hold");
6345 * Release the job and return...
6350 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
6352 con
->response
->request
.status
.status_code
= IPP_OK
;
6357 * 'renew_subscription()' - Renew an existing subscription...
6361 renew_subscription(client_t
*con
, /* I - Client connection */
6362 int sub_id
) /* I - Subscription ID */
6368 * 'restart_job()' - Restart an old print job.
6372 restart_job(client_t
*con
, /* I - Client connection */
6373 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6375 ipp_attribute_t
*attr
; /* Current attribute */
6376 int jobid
; /* Job ID */
6377 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6378 username
[HTTP_MAX_URI
], /* Username portion of URI */
6379 host
[HTTP_MAX_URI
], /* Host portion of URI */
6380 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6381 int port
; /* Port portion of URI */
6382 job_t
*job
; /* Job information */
6385 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6386 uri
->values
[0].string
.text
);
6389 * Verify that the POST operation was done to a valid URI.
6392 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6393 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6394 strncmp(con
->uri
, "/printers/", 10) != 0)
6396 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
6398 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6403 * See if we have a job URI or a printer URI...
6406 if (strcmp(uri
->name
, "printer-uri") == 0)
6409 * Got a printer URI; see if we also have a job-id attribute...
6412 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6414 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
6415 send_ipp_error(con
, IPP_BAD_REQUEST
);
6419 jobid
= attr
->values
[0].integer
;
6424 * Got a job URI; parse it to get the job ID...
6427 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6429 if (strncmp(resource
, "/jobs/", 6) != 0)
6435 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
6436 uri
->values
[0].string
.text
);
6437 send_ipp_error(con
, IPP_BAD_REQUEST
);
6441 jobid
= atoi(resource
+ 6);
6445 * See if the job exists...
6448 if ((job
= FindJob(jobid
)) == NULL
)
6451 * Nope - return a "not found" error...
6454 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
6455 send_ipp_error(con
, IPP_NOT_FOUND
);
6460 * See if job is in any of the "completed" states...
6463 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
6466 * Nope - return a "not possible" error...
6469 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
6470 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6475 * See if we have retained the job files...
6478 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6481 * Nope - return a "not possible" error...
6484 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
6485 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6490 * See if the job is owned by the requesting user...
6493 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6495 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
6496 username
, jobid
, job
->username
);
6497 send_ipp_error(con
, IPP_FORBIDDEN
);
6502 * Restart the job and return...
6507 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
6509 con
->response
->request
.status
.status_code
= IPP_OK
;
6514 * 'send_document()' - Send a file to a printer or class.
6518 send_document(client_t
*con
, /* I - Client connection */
6519 ipp_attribute_t
*uri
) /* I - Printer URI */
6521 ipp_attribute_t
*attr
; /* Current attribute */
6522 ipp_attribute_t
*format
; /* Document-format attribute */
6523 int jobid
; /* Job ID number */
6524 job_t
*job
; /* Current job */
6525 char job_uri
[HTTP_MAX_URI
],
6527 method
[HTTP_MAX_URI
],
6528 /* Method portion of URI */
6529 username
[HTTP_MAX_URI
],
6530 /* Username portion of URI */
6532 /* Host portion of URI */
6533 resource
[HTTP_MAX_URI
];
6534 /* Resource portion of URI */
6535 int port
; /* Port portion of URI */
6536 mime_type_t
*filetype
; /* Type of file */
6537 char super
[MIME_MAX_SUPER
],
6538 /* Supertype of file */
6539 type
[MIME_MAX_TYPE
],
6540 /* Subtype of file */
6541 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
6542 /* Textual name of mime type */
6543 char filename
[1024]; /* Job filename */
6544 printer_t
*printer
; /* Current printer */
6545 struct stat fileinfo
; /* File information */
6546 int kbytes
; /* Size of file */
6547 int compression
; /* Type of compression */
6550 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
6551 uri
->values
[0].string
.text
);
6554 * Verify that the POST operation was done to a valid URI.
6557 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6558 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
6559 strncmp(con
->uri
, "/printers/", 10) != 0)
6561 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
6563 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6568 * See if we have a job URI or a printer URI...
6571 if (strcmp(uri
->name
, "printer-uri") == 0)
6574 * Got a printer URI; see if we also have a job-id attribute...
6577 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6579 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
6580 send_ipp_error(con
, IPP_BAD_REQUEST
);
6584 jobid
= attr
->values
[0].integer
;
6589 * Got a job URI; parse it to get the job ID...
6592 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6594 if (strncmp(resource
, "/jobs/", 6) != 0)
6600 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
6601 uri
->values
[0].string
.text
);
6602 send_ipp_error(con
, IPP_BAD_REQUEST
);
6606 jobid
= atoi(resource
+ 6);
6610 * See if the job exists...
6613 if ((job
= FindJob(jobid
)) == NULL
)
6616 * Nope - return a "not found" error...
6619 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
6620 send_ipp_error(con
, IPP_NOT_FOUND
);
6625 * See if the job is owned by the requesting user...
6628 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6630 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
6631 username
, jobid
, job
->username
);
6632 send_ipp_error(con
, IPP_FORBIDDEN
);
6637 * OK, see if the client is sending the document compressed - CUPS
6638 * only supports "none" and "gzip".
6641 compression
= CUPS_FILE_NONE
;
6643 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
6645 if (strcmp(attr
->values
[0].string
.text
, "none")
6647 && strcmp(attr
->values
[0].string
.text
, "gzip")
6648 #endif /* HAVE_LIBZ */
6651 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
6652 attr
->values
[0].string
.text
);
6653 send_ipp_error(con
, IPP_ATTRIBUTES
);
6654 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
6655 "compression", NULL
, attr
->values
[0].string
.text
);
6660 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
6661 compression
= CUPS_FILE_GZIP
;
6662 #endif /* HAVE_LIBZ */
6666 * Do we have a file to print?
6671 LogMessage(L_ERROR
, "send_document: No file!?!");
6672 send_ipp_error(con
, IPP_BAD_REQUEST
);
6677 * Is it a format we support?
6680 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
6683 * Grab format from client...
6686 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
6688 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
6689 format
->values
[0].string
.text
);
6690 send_ipp_error(con
, IPP_BAD_REQUEST
);
6697 * No document format attribute? Auto-type it!
6700 strcpy(super
, "application");
6701 strcpy(type
, "octet-stream");
6704 if (strcmp(super
, "application") == 0 &&
6705 strcmp(type
, "octet-stream") == 0)
6708 * Auto-type the file...
6711 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
6713 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
6715 if (filetype
!= NULL
)
6718 * Replace the document-format attribute value with the auto-typed one.
6721 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
6726 free(format
->values
[0].string
.text
);
6727 format
->values
[0].string
.text
= strdup(mimetype
);
6730 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
6731 "document-format", NULL
, mimetype
);
6734 filetype
= mimeType(MimeDatabase
, super
, type
);
6737 filetype
= mimeType(MimeDatabase
, super
, type
);
6739 if (filetype
== NULL
)
6741 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
6743 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
6744 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
6747 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
6748 "document-format", NULL
, format
->values
[0].string
.text
);
6753 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
6754 filetype
->super
, filetype
->type
);
6757 * Add the file to the job...
6760 if (add_file(con
, job
, filetype
, compression
))
6763 if (job
->dtype
& CUPS_PRINTER_CLASS
)
6764 printer
= FindClass(job
->dest
);
6766 printer
= FindPrinter(job
->dest
);
6768 if (stat(con
->filename
, &fileinfo
))
6771 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6773 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6775 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
6776 attr
->values
[0].integer
+= kbytes
;
6778 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6780 rename(con
->filename
, filename
);
6782 ClearString(&con
->filename
);
6784 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
6785 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
6788 * Start the job if this is the last document...
6791 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
6792 attr
->values
[0].boolean
)
6795 * See if we need to add the ending sheet...
6798 if (printer
!= NULL
&&
6799 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6800 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
6801 attr
->num_values
> 1)
6807 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
6808 attr
->values
[1].string
.text
, job
->id
);
6810 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6812 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6815 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
6816 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6817 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
6819 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6820 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6822 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6823 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6829 * Start the job if possible... Since CheckJobs() can cancel a job if it
6830 * doesn't print, we need to re-find the job afterwards...
6837 job
= FindJob(jobid
);
6841 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6842 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6844 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6846 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
6847 job
->hold_until
= time(NULL
) + 60;
6853 * Fill in the response info...
6856 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
6859 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
6862 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
6864 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
6865 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
6866 add_job_state_reasons(con
, job
);
6868 con
->response
->request
.status
.status_code
= IPP_OK
;
6873 * 'send_ipp_error()' - Send an error status back to the IPP client.
6877 send_ipp_error(client_t
*con
, /* I - Client connection */
6878 ipp_status_t status
) /* I - IPP status code */
6880 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
6883 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
6885 if (status
== IPP_NOT_AUTHORIZED
)
6888 * Send HTTP_UNAUTHORIZED response instead of IPP response, so that
6889 * the client will properly authenticate the request...
6892 SendError(con
, HTTP_UNAUTHORIZED
);
6894 ippDelete(con
->response
);
6895 con
->response
= NULL
;
6900 con
->response
->request
.status
.status_code
= status
;
6902 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
6903 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
6904 "attributes-charset", NULL
, DefaultCharset
);
6906 if (ippFindAttribute(con
->response
, "attributes-natural-language",
6907 IPP_TAG_ZERO
) == NULL
)
6908 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
6909 "attributes-natural-language", NULL
, DefaultLanguage
);
6914 * 'set_default()' - Set the default destination...
6918 set_default(client_t
*con
, /* I - Client connection */
6919 ipp_attribute_t
*uri
) /* I - Printer URI */
6921 cups_ptype_t dtype
; /* Destination type (printer or class) */
6922 char method
[HTTP_MAX_URI
],
6923 /* Method portion of URI */
6924 username
[HTTP_MAX_URI
],
6925 /* Username portion of URI */
6927 /* Host portion of URI */
6928 resource
[HTTP_MAX_URI
];
6929 /* Resource portion of URI */
6930 int port
; /* Port portion of URI */
6931 const char *name
; /* Printer name */
6932 printer_t
*printer
; /* Printer */
6935 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
6936 uri
->values
[0].string
.text
);
6939 * Was this operation called from the correct URI?
6942 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6944 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
6946 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6951 * Is the destination valid?
6954 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6956 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6962 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
6963 send_ipp_error(con
, IPP_NOT_FOUND
);
6971 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
6973 LogMessage(L_ERROR
, "set_default: not authorized!");
6974 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6979 * Set it as the default...
6982 DefaultPrinter
= printer
;
6987 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
6991 * Everything was ok, so return OK status...
6994 con
->response
->request
.status
.status_code
= IPP_OK
;
6999 * 'set_job_attrs()' - Set job attributes.
7003 set_job_attrs(client_t
*con
, /* I - Client connection */
7004 ipp_attribute_t
*uri
) /* I - Job URI */
7006 ipp_attribute_t
*attr
, /* Current attribute */
7007 *attr2
, /* Job attribute */
7008 *prev2
; /* Previous job attribute */
7009 int jobid
; /* Job ID */
7010 job_t
*job
; /* Current job */
7011 char method
[HTTP_MAX_URI
],
7012 /* Method portion of URI */
7013 username
[HTTP_MAX_URI
],
7014 /* Username portion of URI */
7016 /* Host portion of URI */
7017 resource
[HTTP_MAX_URI
];
7018 /* Resource portion of URI */
7019 int port
; /* Port portion of URI */
7022 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
7023 uri
->values
[0].string
.text
);
7026 * Start with "everything is OK" status...
7029 con
->response
->request
.status
.status_code
= IPP_OK
;
7032 * See if we have a job URI or a printer URI...
7035 if (strcmp(uri
->name
, "printer-uri") == 0)
7038 * Got a printer URI; see if we also have a job-id attribute...
7041 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
7043 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
7044 send_ipp_error(con
, IPP_BAD_REQUEST
);
7048 jobid
= attr
->values
[0].integer
;
7053 * Got a job URI; parse it to get the job ID...
7056 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7058 if (strncmp(resource
, "/jobs/", 6) != 0)
7064 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
7065 uri
->values
[0].string
.text
);
7066 send_ipp_error(con
, IPP_BAD_REQUEST
);
7070 jobid
= atoi(resource
+ 6);
7074 * See if the job exists...
7077 if ((job
= FindJob(jobid
)) == NULL
)
7080 * Nope - return a "not found" error...
7083 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
7084 send_ipp_error(con
, IPP_NOT_FOUND
);
7089 * See if the job has been completed...
7092 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
7095 * Return a "not-possible" error...
7098 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
7099 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7104 * See if the job is owned by the requesting user...
7107 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
7109 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
7110 username
, jobid
, job
->username
);
7111 send_ipp_error(con
, IPP_FORBIDDEN
);
7116 * See what the user wants to change.
7119 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
7121 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
7124 if (!strcmp(attr
->name
, "attributes-charset") ||
7125 !strcmp(attr
->name
, "attributes-natural-language") ||
7126 !strcmp(attr
->name
, "document-compression") ||
7127 !strcmp(attr
->name
, "document-format") ||
7128 !strcmp(attr
->name
, "job-detailed-status-messages") ||
7129 !strcmp(attr
->name
, "job-document-access-errors") ||
7130 !strcmp(attr
->name
, "job-id") ||
7131 !strcmp(attr
->name
, "job-k-octets") ||
7132 !strcmp(attr
->name
, "job-originating-host-name") ||
7133 !strcmp(attr
->name
, "job-originating-user-name") ||
7134 !strcmp(attr
->name
, "job-printer-up-time") ||
7135 !strcmp(attr
->name
, "job-printer-uri") ||
7136 !strcmp(attr
->name
, "job-sheets") ||
7137 !strcmp(attr
->name
, "job-state-message") ||
7138 !strcmp(attr
->name
, "job-state-reasons") ||
7139 !strcmp(attr
->name
, "job-uri") ||
7140 !strcmp(attr
->name
, "number-of-documents") ||
7141 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
7142 !strcmp(attr
->name
, "output-device-assigned") ||
7143 !strncmp(attr
->name
, "date-time-at-", 13) ||
7144 !strncmp(attr
->name
, "job-impressions", 15) ||
7145 !strncmp(attr
->name
, "job-k-octets", 12) ||
7146 !strncmp(attr
->name
, "job-media-sheets", 16) ||
7147 !strncmp(attr
->name
, "time-at-", 8))
7153 send_ipp_error(con
, IPP_ATTRIBUTES_NOT_SETTABLE
);
7155 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7156 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7161 if (!strcmp(attr
->name
, "job-priority"))
7164 * Change the job priority...
7167 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
7169 send_ipp_error(con
, IPP_REQUEST_VALUE
);
7171 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7172 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7174 else if (job
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
7176 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7179 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7180 SetJobPriority(jobid
, attr
->values
[0].integer
);
7182 else if (!strcmp(attr
->name
, "job-state"))
7185 * Change the job state...
7188 if (attr
->value_tag
!= IPP_TAG_ENUM
)
7190 send_ipp_error(con
, IPP_REQUEST_VALUE
);
7192 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
7193 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
7197 switch (attr
->values
[0].integer
)
7199 case IPP_JOB_PENDING
:
7201 if (job
->state
->values
[0].integer
> IPP_JOB_HELD
)
7203 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7206 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7207 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7210 case IPP_JOB_PROCESSING
:
7211 case IPP_JOB_STOPPED
:
7212 if (job
->state
->values
[0].integer
!= attr
->values
[0].integer
)
7214 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7219 case IPP_JOB_CANCELLED
:
7220 case IPP_JOB_ABORTED
:
7221 case IPP_JOB_COMPLETED
:
7222 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
)
7224 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7227 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7229 CancelJob(job
->id
, 0);
7233 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7241 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
7243 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
7246 * Some other value; first free the old value...
7249 if (job
->attrs
->attrs
== attr2
)
7251 job
->attrs
->attrs
= attr2
->next
;
7256 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
7257 if (prev2
->next
== attr2
)
7259 prev2
->next
= attr2
->next
;
7264 if (job
->attrs
->last
== attr2
)
7265 job
->attrs
->last
= prev2
;
7267 _ipp_free_attr(attr2
);
7270 * Then copy the attribute...
7273 copy_attribute(job
->attrs
, attr
, 0);
7276 * See if the job-name or job-hold-until is being changed.
7279 if (strcmp(attr
->name
, "job-hold-until") == 0)
7281 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
7283 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7284 ReleaseJob(job
->id
);
7289 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
7292 * Delete the attribute...
7295 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
7297 prev2
= attr2
, attr2
= attr2
->next
)
7298 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
7304 prev2
->next
= attr2
->next
;
7306 job
->attrs
->attrs
= attr2
->next
;
7308 if (attr2
== job
->attrs
->last
)
7309 job
->attrs
->last
= prev2
;
7311 _ipp_free_attr(attr2
);
7317 * Add new option by copying it...
7320 copy_attribute(job
->attrs
, attr
, 0);
7331 * Start jobs if possible...
7339 * 'start_printer()' - Start a printer.
7343 start_printer(client_t
*con
, /* I - Client connection */
7344 ipp_attribute_t
*uri
) /* I - Printer URI */
7346 cups_ptype_t dtype
; /* Destination type (printer or class) */
7347 char method
[HTTP_MAX_URI
],
7348 /* Method portion of URI */
7349 username
[HTTP_MAX_URI
],
7350 /* Username portion of URI */
7352 /* Host portion of URI */
7353 resource
[HTTP_MAX_URI
];
7354 /* Resource portion of URI */
7355 int port
; /* Port portion of URI */
7356 const char *name
; /* Printer name */
7357 printer_t
*printer
; /* Printer data */
7360 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7361 uri
->values
[0].string
.text
);
7364 * Was this operation called from the correct URI?
7367 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7369 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
7371 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7376 * Is the destination valid?
7379 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7381 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7387 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
7388 send_ipp_error(con
, IPP_NOT_FOUND
);
7396 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7398 LogMessage(L_ERROR
, "start_printer: not authorized!");
7399 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7404 * Start the printer...
7407 printer
->state_message
[0] = '\0';
7409 StartPrinter(printer
, 1);
7411 if (dtype
& CUPS_PRINTER_CLASS
)
7412 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
7414 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
7420 * Everything was ok, so return OK status...
7423 con
->response
->request
.status
.status_code
= IPP_OK
;
7428 * 'stop_printer()' - Stop a printer.
7432 stop_printer(client_t
*con
, /* I - Client connection */
7433 ipp_attribute_t
*uri
) /* I - Printer URI */
7435 cups_ptype_t dtype
; /* Destination type (printer or class) */
7436 char method
[HTTP_MAX_URI
],
7437 /* Method portion of URI */
7438 username
[HTTP_MAX_URI
],
7439 /* Username portion of URI */
7441 /* Host portion of URI */
7442 resource
[HTTP_MAX_URI
];
7443 /* Resource portion of URI */
7444 int port
; /* Port portion of URI */
7445 const char *name
; /* Printer name */
7446 printer_t
*printer
; /* Printer data */
7447 ipp_attribute_t
*attr
; /* printer-state-message attribute */
7450 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7451 uri
->values
[0].string
.text
);
7454 * Was this operation called from the correct URI?
7457 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7459 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
7461 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7466 * Is the destination valid?
7469 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7471 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7477 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
7478 send_ipp_error(con
, IPP_NOT_FOUND
);
7486 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7488 LogMessage(L_ERROR
, "stop_printer: not authorized!");
7489 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7494 * Stop the printer...
7497 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
7498 IPP_TAG_TEXT
)) == NULL
)
7499 strcpy(printer
->state_message
, "Paused");
7502 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
7503 sizeof(printer
->state_message
));
7506 StopPrinter(printer
, 1);
7508 if (dtype
& CUPS_PRINTER_CLASS
)
7509 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
7512 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
7516 * Everything was ok, so return OK status...
7519 con
->response
->request
.status
.status_code
= IPP_OK
;
7524 * 'user_allowed()' - See if a user is allowed to print to a queue.
7527 static int /* O - 0 if not allowed, 1 if allowed */
7528 user_allowed(printer_t
*p
, /* I - Printer or class */
7529 const char *username
) /* I - Username */
7531 int i
, j
; /* Looping vars */
7532 struct passwd
*pw
; /* User password data */
7533 struct group
*grp
; /* Group data */
7536 if (p
->num_users
== 0)
7539 if (!strcmp(username
, "root"))
7542 pw
= getpwnam(username
);
7545 for (i
= 0; i
< p
->num_users
; i
++)
7547 if (p
->users
[i
][0] == '@')
7550 * Check group membership...
7553 grp
= getgrnam(p
->users
[i
] + 1);
7559 * Check primary group...
7562 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
7566 * Check usernames in group...
7569 for (j
= 0; grp
->gr_mem
[j
]; j
++)
7570 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
7577 else if (!strcasecmp(username
, p
->users
[i
]))
7581 return ((i
< p
->num_users
) != p
->deny_users
);
7586 * 'validate_job()' - Validate printer options and destination.
7590 validate_job(client_t
*con
, /* I - Client connection */
7591 ipp_attribute_t
*uri
) /* I - Printer URI */
7593 ipp_attribute_t
*attr
; /* Current attribute */
7594 ipp_attribute_t
*format
; /* Document-format attribute */
7595 cups_ptype_t dtype
; /* Destination type (printer or class) */
7596 char method
[HTTP_MAX_URI
],
7597 /* Method portion of URI */
7598 username
[HTTP_MAX_URI
],
7599 /* Username portion of URI */
7601 /* Host portion of URI */
7602 resource
[HTTP_MAX_URI
];
7603 /* Resource portion of URI */
7604 int port
; /* Port portion of URI */
7605 char super
[MIME_MAX_SUPER
],
7606 /* Supertype of file */
7607 type
[MIME_MAX_TYPE
];
7608 /* Subtype of file */
7609 printer_t
*printer
; /* Printer */
7612 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
7613 uri
->values
[0].string
.text
);
7616 * Verify that the POST operation was done to a valid URI.
7619 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
7620 strncmp(con
->uri
, "/printers/", 10) != 0)
7622 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
7624 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7629 * OK, see if the client is sending the document compressed - CUPS
7630 * doesn't support compression yet...
7633 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
7634 strcmp(attr
->values
[0].string
.text
, "none") == 0)
7636 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
7637 attr
->values
[0].string
.text
);
7638 send_ipp_error(con
, IPP_ATTRIBUTES
);
7639 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7640 "compression", NULL
, attr
->values
[0].string
.text
);
7645 * Is it a format we support?
7648 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
7650 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7652 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
7653 format
->values
[0].string
.text
);
7654 send_ipp_error(con
, IPP_BAD_REQUEST
);
7658 if ((strcmp(super
, "application") != 0 ||
7659 strcmp(type
, "octet-stream") != 0) &&
7660 mimeType(MimeDatabase
, super
, type
) == NULL
)
7662 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
7663 format
->values
[0].string
.text
);
7664 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
7665 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
7666 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7667 "document-format", NULL
, format
->values
[0].string
.text
);
7673 * Is the destination valid?
7676 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7678 if (ValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
7684 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
7685 send_ipp_error(con
, IPP_NOT_FOUND
);
7693 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7695 LogMessage(L_ERROR
, "validate_job: not authorized!");
7696 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7701 * Everything was ok, so return OK status...
7704 con
->response
->request
.status
.status_code
= IPP_OK
;
7709 * 'validate_name()' - Make sure the printer name only contains valid chars.
7712 static int /* O - 0 if name is no good, 1 if name is good */
7713 validate_name(const char *name
) /* I - Name to check */
7715 const char *ptr
; /* Pointer into name */
7719 * Scan the whole name...
7722 for (ptr
= name
; *ptr
; ptr
++)
7723 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
7727 * All the characters are good; validate the length, too...
7730 return ((ptr
- name
) < 128);
7735 * 'validate_user()' - Validate the user for the request.
7738 static int /* O - 1 if permitted, 0 otherwise */
7739 validate_user(job_t
*job
, /* I - Job */
7740 client_t
*con
, /* I - Client connection */
7741 const char *owner
, /* I - Owner of job/resource */
7742 char *username
, /* O - Authenticated username */
7743 int userlen
) /* I - Length of username */
7745 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
7746 printer_t
*printer
; /* Printer for job */
7749 LogMessage(L_DEBUG2
, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=%d)\n",
7750 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
7757 if (!con
|| !owner
|| !username
|| userlen
<= 0)
7761 * Get the best authenticated username that is available.
7764 if (con
->username
[0])
7765 strlcpy(username
, con
->username
, userlen
);
7766 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
7767 strlcpy(username
, attr
->values
[0].string
.text
, userlen
);
7769 strlcpy(username
, "anonymous", userlen
);
7772 * Check the username against the owner...
7775 if (job
->dtype
& CUPS_PRINTER_CLASS
)
7776 printer
= FindClass(job
->dest
);
7778 printer
= FindPrinter(job
->dest
);
7781 return (CheckPolicy(printer
->op_policy_ptr
, con
, owner
));
7783 return (CheckPolicy(DefaultPolicyPtr
, con
, owner
));