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
);
868 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
870 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
871 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
873 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
874 pclass
->name
, attr
->values
[0].integer
);
875 send_ipp_error(con
, IPP_BAD_REQUEST
);
879 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
880 attr
->values
[0].integer
, pclass
->state
);
882 SetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
884 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
886 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
887 sizeof(pclass
->state_message
));
888 AddPrinterHistory(pclass
);
890 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
893 SetString(&pclass
->job_sheets
[0], attr
->values
[0].string
.text
);
894 if (attr
->num_values
> 1)
895 SetString(&pclass
->job_sheets
[1], attr
->values
[1].string
.text
);
897 SetString(&pclass
->job_sheets
[1], "none");
899 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
900 IPP_TAG_ZERO
)) != NULL
)
902 FreePrinterUsers(pclass
);
904 pclass
->deny_users
= 0;
905 if (attr
->value_tag
== IPP_TAG_NAME
&&
906 (attr
->num_values
> 1 ||
907 strcmp(attr
->values
[0].string
.text
, "all") != 0))
908 for (i
= 0; i
< attr
->num_values
; i
++)
909 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
911 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
912 IPP_TAG_ZERO
)) != NULL
)
914 FreePrinterUsers(pclass
);
916 pclass
->deny_users
= 1;
917 if (attr
->value_tag
== IPP_TAG_NAME
&&
918 (attr
->num_values
> 1 ||
919 strcmp(attr
->values
[0].string
.text
, "none") != 0))
920 for (i
= 0; i
< attr
->num_values
; i
++)
921 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
923 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
924 IPP_TAG_INTEGER
)) != NULL
)
926 LogMessage(L_DEBUG
, "add_class: Setting job-quota-period to %d...",
927 attr
->values
[0].integer
);
929 pclass
->quota_period
= attr
->values
[0].integer
;
931 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
932 IPP_TAG_INTEGER
)) != NULL
)
934 LogMessage(L_DEBUG
, "add_class: Setting job-k-limit to %d...",
935 attr
->values
[0].integer
);
937 pclass
->k_limit
= attr
->values
[0].integer
;
939 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
940 IPP_TAG_INTEGER
)) != NULL
)
942 LogMessage(L_DEBUG
, "add_class: Setting job-page-limit to %d...",
943 attr
->values
[0].integer
);
945 pclass
->page_limit
= attr
->values
[0].integer
;
947 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
949 policy_t
*p
; /* Policy */
952 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
954 LogMessage(L_DEBUG
, "add_class: Setting printer-op-policy to \"%s\"...",
955 attr
->values
[0].string
.text
);
956 SetString(&pclass
->op_policy
, attr
->values
[0].string
.text
);
957 pclass
->op_policy_ptr
= p
;
961 LogMessage(L_ERROR
, "add_class: Unknown printer-op-policy \"%s\"...",
962 attr
->values
[0].string
.text
);
963 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
967 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
969 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
970 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
971 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
973 LogMessage(L_ERROR
, "add_class: Unknown printer-error-policy \"%s\"...",
974 attr
->values
[0].string
.text
);
975 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
979 LogMessage(L_DEBUG
, "add_class: Setting printer-error-policy to \"%s\"...",
980 attr
->values
[0].string
.text
);
981 SetString(&pclass
->error_policy
, attr
->values
[0].string
.text
);
983 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
986 * Clear the printer array as needed...
989 if (pclass
->num_printers
> 0)
991 free(pclass
->printers
);
992 pclass
->num_printers
= 0;
996 * Add each printer or class that is listed...
999 for (i
= 0; i
< attr
->num_values
; i
++)
1002 * Search for the printer or class URI...
1005 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
1008 if ((dest
= ValidateDest(host
, resource
, &dtype
, &member
)) == NULL
)
1014 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
1015 send_ipp_error(con
, IPP_NOT_FOUND
);
1020 * Add it to the class...
1023 AddPrinterToClass(pclass
, member
);
1028 * Update the printer class attributes and return...
1031 SetPrinterAttrs(pclass
);
1039 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1040 "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1043 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1048 AddPrinterHistory(pclass
);
1050 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1051 "New class \'%s\' added by \'%s\'.", pclass
->name
,
1054 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
1058 con
->response
->request
.status
.status_code
= IPP_OK
;
1063 * 'add_file()' - Add a file to a job.
1066 static int /* O - 0 on success, -1 on error */
1067 add_file(client_t
*con
, /* I - Connection to client */
1068 job_t
*job
, /* I - Job to add to */
1069 mime_type_t
*filetype
, /* I - Type of file */
1070 int compression
) /* I - Compression */
1072 mime_type_t
**filetypes
; /* New filetypes array... */
1073 int *compressions
; /* New compressions array... */
1076 LogMessage(L_DEBUG2
, "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)\n",
1077 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1081 * Add the file to the job...
1084 if (job
->num_files
== 0)
1086 compressions
= (int *)malloc(sizeof(int));
1087 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1091 compressions
= (int *)realloc(job
->compressions
,
1092 (job
->num_files
+ 1) * sizeof(int));
1093 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1094 (job
->num_files
+ 1) *
1095 sizeof(mime_type_t
*));
1098 if (compressions
== NULL
|| filetypes
== NULL
)
1100 CancelJob(job
->id
, 1);
1101 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
1102 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1106 job
->compressions
= compressions
;
1107 job
->compressions
[job
->num_files
] = compression
;
1108 job
->filetypes
= filetypes
;
1109 job
->filetypes
[job
->num_files
] = filetype
;
1118 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1119 * upon the job and printer state...
1123 add_job_state_reasons(client_t
*con
, /* I - Client connection */
1124 job_t
*job
) /* I - Job info */
1126 printer_t
*dest
; /* Destination printer */
1129 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
1132 switch (job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
)
1134 case IPP_JOB_PENDING
:
1135 if (job
->dtype
& CUPS_PRINTER_CLASS
)
1136 dest
= FindClass(job
->dest
);
1138 dest
= FindPrinter(job
->dest
);
1140 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
1141 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1142 "job-state-reasons", NULL
, "printer-stopped");
1144 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1145 "job-state-reasons", NULL
, "none");
1149 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
1150 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
1151 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1152 "job-state-reasons", NULL
, "job-hold-until-specified");
1154 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1155 "job-state-reasons", NULL
, "job-incoming");
1158 case IPP_JOB_PROCESSING
:
1159 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1160 "job-state-reasons", NULL
, "job-printing");
1163 case IPP_JOB_STOPPED
:
1164 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1165 "job-state-reasons", NULL
, "job-stopped");
1168 case IPP_JOB_CANCELLED
:
1169 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1170 "job-state-reasons", NULL
, "job-canceled-by-user");
1173 case IPP_JOB_ABORTED
:
1174 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1175 "job-state-reasons", NULL
, "aborted-by-system");
1178 case IPP_JOB_COMPLETED
:
1179 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1180 "job-state-reasons", NULL
, "job-completed-successfully");
1187 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1191 add_job_subscriptions(client_t
*con
, /* I - Client connection */
1192 job_t
*job
) /* I - Newly created job */
1194 int i
; /* Looping var */
1195 ipp_attribute_t
*prev
, /* Previous attribute */
1196 *next
, /* Next attribute */
1197 *attr
; /* Current attribute */
1198 cupsd_subscription_t
*sub
; /* Subscription object */
1199 const char *recipient
, /* notify-recipient-uri */
1200 *pullmethod
; /* notify-pull-method */
1201 ipp_attribute_t
*user_data
; /* notify-user-data */
1202 int interval
; /* notify-time-interval */
1203 unsigned mask
; /* notify-events */
1207 * Find the first subscription group attribute; return if we have
1211 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; prev
= attr
, attr
= attr
->next
)
1212 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1219 * Process the subscription attributes in the request...
1228 mask
= CUPSD_EVENT_NONE
;
1230 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1232 if (!strcmp(attr
->name
, "notify-recipient") &&
1233 attr
->value_tag
== IPP_TAG_URI
)
1234 recipient
= attr
->values
[0].string
.text
;
1235 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1236 attr
->value_tag
== IPP_TAG_KEYWORD
)
1237 pullmethod
= attr
->values
[0].string
.text
;
1238 else if (!strcmp(attr
->name
, "notify-charset") &&
1239 attr
->value_tag
== IPP_TAG_CHARSET
&&
1240 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1242 send_ipp_error(con
, IPP_CHARSET
);
1245 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1246 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
1247 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
))
1249 send_ipp_error(con
, IPP_CHARSET
);
1252 else if (!strcmp(attr
->name
, "notify-user-data") &&
1253 attr
->value_tag
== IPP_TAG_STRING
)
1255 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1257 send_ipp_error(con
, IPP_REQUEST_VALUE
);
1263 else if (!strcmp(attr
->name
, "notify-events") &&
1264 attr
->value_tag
== IPP_TAG_KEYWORD
)
1266 for (i
= 0; i
< attr
->num_values
; i
++)
1267 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1269 else if (!strcmp(attr
->name
, "notify-lease-time"))
1271 send_ipp_error(con
, IPP_BAD_REQUEST
);
1274 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1275 attr
->value_tag
== IPP_TAG_INTEGER
)
1276 interval
= attr
->values
[0].integer
;
1281 if (!recipient
&& !pullmethod
)
1284 if (mask
== CUPSD_EVENT_NONE
)
1285 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1287 sub
= cupsdAddSubscription(mask
, FindDest(job
->dest
), job
, recipient
);
1289 sub
->interval
= interval
;
1291 SetString(&sub
->owner
, job
->username
);
1295 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1296 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1297 sub
->user_data_len
);
1305 * Remove all of the subscription attributes from the job request...
1308 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1312 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1313 attr
->group_tag
== IPP_TAG_ZERO
)
1316 * Free and remove this attribute...
1319 _ipp_free_attr(attr
);
1324 job
->attrs
->attrs
= next
;
1330 job
->attrs
->last
= prev
;
1331 job
->attrs
->current
= prev
;
1336 * 'add_printer()' - Add a printer to the system.
1340 add_printer(client_t
*con
, /* I - Client connection */
1341 ipp_attribute_t
*uri
) /* I - URI of printer */
1343 int i
; /* Looping var */
1344 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1345 username
[HTTP_MAX_URI
], /* Username portion of URI */
1346 host
[HTTP_MAX_URI
], /* Host portion of URI */
1347 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1348 int port
; /* Port portion of URI */
1349 printer_t
*printer
; /* Printer/class */
1350 ipp_attribute_t
*attr
; /* Printer attribute */
1351 cups_file_t
*fp
; /* Script/PPD file */
1352 char line
[1024]; /* Line from file... */
1353 char srcfile
[1024], /* Source Script/PPD file */
1354 dstfile
[1024]; /* Destination Script/PPD file */
1355 int modify
; /* Non-zero if we are modifying */
1358 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
1359 uri
->values
[0].string
.text
);
1362 * Was this operation called from the correct URI?
1365 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1367 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
1369 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1374 * Do we have a valid URI?
1377 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1379 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1382 * No, return an error...
1385 LogMessage(L_ERROR
, "add_printer: bad printer URI \"%s\"!",
1386 uri
->values
[0].string
.text
);
1387 send_ipp_error(con
, IPP_BAD_REQUEST
);
1392 * Do we have a valid printer name?
1395 if (!validate_name(resource
+ 10))
1398 * No, return an error...
1401 send_ipp_error(con
, IPP_BAD_REQUEST
);
1409 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
1411 LogMessage(L_ERROR
, "add_printer: not authorized!");
1412 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1417 * See if the printer already exists; if not, create a new printer...
1420 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1423 * Printer doesn't exist; see if we have a class of the same name...
1426 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1427 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1430 * Yes, return an error...
1433 LogMessage(L_ERROR
, "add_printer: \"%s\" already exists as a class!",
1435 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1440 * No, add the printer...
1443 printer
= AddPrinter(resource
+ 10);
1446 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1449 * Rename the implicit printer to "AnyPrinter" or delete it...
1452 if (ImplicitAnyClasses
)
1454 SetStringf(&printer
->name
, "Any%s", resource
+ 10);
1458 DeletePrinter(printer
, 1);
1461 * Add the printer as a new local printer...
1464 printer
= AddPrinter(resource
+ 10);
1467 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1470 * Rename the remote printer to "Printer@server"...
1473 DeletePrinterFilters(printer
);
1474 SetStringf(&printer
->name
, "%s@%s", resource
+ 10, printer
->hostname
);
1475 SetPrinterAttrs(printer
);
1479 * Add the printer as a new local printer...
1482 printer
= AddPrinter(resource
+ 10);
1489 * Look for attributes and copy them over as needed...
1492 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1493 SetString(&printer
->location
, attr
->values
[0].string
.text
);
1495 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1496 SetString(&printer
->info
, attr
->values
[0].string
.text
);
1498 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1500 ipp_attribute_t
*device
; /* Current device */
1501 int methodlen
; /* Length of method string */
1505 * Do we have a valid device URI?
1508 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1510 methodlen
= strlen(method
);
1512 if (!strcmp(method
, "file"))
1515 * See if the administrator has enabled file devices...
1518 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
1521 * File devices are disabled and the URL is not file:/dev/null...
1524 LogMessage(L_ERROR
, "add_printer: File device URIs have been disabled! "
1525 "To enable, see the FileDevice directive in cupsd.conf.");
1526 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1533 * See if the backend exists and is executable...
1536 snprintf(srcfile
, sizeof(srcfile
), "%s/backend/%s", ServerBin
, method
);
1537 if (access(srcfile
, X_OK
))
1540 * Could not find device in list!
1543 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1544 attr
->values
[0].string
.text
);
1545 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1550 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1552 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
, sizeof(line
)),
1553 cupsdSanitizeURI(printer
->device_uri
, resource
, sizeof(resource
)));
1555 SetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
1558 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1560 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1561 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1563 printer
->accepting
= attr
->values
[0].boolean
;
1564 AddPrinterHistory(printer
);
1566 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1568 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1569 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1571 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
1572 printer
->name
, attr
->values
[0].integer
);
1573 send_ipp_error(con
, IPP_BAD_REQUEST
);
1577 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1578 attr
->values
[0].integer
, printer
->state
);
1580 SetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1582 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1584 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
1585 sizeof(printer
->state_message
));
1586 AddPrinterHistory(printer
);
1588 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1591 SetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
1592 if (attr
->num_values
> 1)
1593 SetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
1595 SetString(&printer
->job_sheets
[1], "none");
1597 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1598 IPP_TAG_ZERO
)) != NULL
)
1600 FreePrinterUsers(printer
);
1602 printer
->deny_users
= 0;
1603 if (attr
->value_tag
== IPP_TAG_NAME
&&
1604 (attr
->num_values
> 1 ||
1605 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1606 for (i
= 0; i
< attr
->num_values
; i
++)
1607 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1609 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1610 IPP_TAG_ZERO
)) != NULL
)
1612 FreePrinterUsers(printer
);
1614 printer
->deny_users
= 1;
1615 if (attr
->value_tag
== IPP_TAG_NAME
&&
1616 (attr
->num_values
> 1 ||
1617 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1618 for (i
= 0; i
< attr
->num_values
; i
++)
1619 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1621 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1622 IPP_TAG_INTEGER
)) != NULL
)
1624 LogMessage(L_DEBUG
, "add_printer: Setting job-quota-period to %d...",
1625 attr
->values
[0].integer
);
1626 FreeQuotas(printer
);
1627 printer
->quota_period
= attr
->values
[0].integer
;
1629 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1630 IPP_TAG_INTEGER
)) != NULL
)
1632 LogMessage(L_DEBUG
, "add_printer: Setting job-k-limit to %d...",
1633 attr
->values
[0].integer
);
1634 FreeQuotas(printer
);
1635 printer
->k_limit
= attr
->values
[0].integer
;
1637 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1638 IPP_TAG_INTEGER
)) != NULL
)
1640 LogMessage(L_DEBUG
, "add_printer: Setting job-page-limit to %d...",
1641 attr
->values
[0].integer
);
1642 FreeQuotas(printer
);
1643 printer
->page_limit
= attr
->values
[0].integer
;
1645 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
1647 policy_t
*p
; /* Policy */
1650 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
1652 LogMessage(L_DEBUG
, "add_printer: Setting printer-op-policy to \"%s\"...",
1653 attr
->values
[0].string
.text
);
1654 SetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
1655 printer
->op_policy_ptr
= p
;
1659 LogMessage(L_ERROR
, "add_printer: Unknown printer-op-policy \"%s\"...",
1660 attr
->values
[0].string
.text
);
1661 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1665 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
1667 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
1668 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
1669 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
1671 LogMessage(L_ERROR
, "add_printer: Unknown printer-error-policy \"%s\"...",
1672 attr
->values
[0].string
.text
);
1673 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1677 LogMessage(L_DEBUG
, "add_printer: Setting printer-error-policy to \"%s\"...",
1678 attr
->values
[0].string
.text
);
1679 SetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
1683 * See if we have all required attributes...
1686 if (!printer
->device_uri
)
1687 SetString(&printer
->device_uri
, "file:/dev/null");
1690 * See if we have an interface script or PPD file attached to the request...
1695 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
1697 if ((fp
= cupsFileOpen(srcfile
, "rb")) != NULL
)
1700 * Yes; get the first line from it...
1704 cupsFileGets(fp
, line
, sizeof(line
));
1708 * Then see what kind of file it is...
1711 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1714 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1717 * The new file is a PPD file, so remove any old interface script
1718 * that might be lying around...
1726 * This must be an interface script, so move the file over to the
1727 * interfaces directory and make it executable...
1730 if (copy_file(srcfile
, dstfile
))
1732 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1733 srcfile
, dstfile
, strerror(errno
));
1734 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1739 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1740 chmod(dstfile
, 0755);
1744 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1747 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1750 * The new file is a PPD file, so move the file over to the
1751 * ppd directory and make it readable by all...
1754 if (copy_file(srcfile
, dstfile
))
1756 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1757 srcfile
, dstfile
, strerror(errno
));
1758 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1763 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1764 chmod(dstfile
, 0644);
1770 * This must be an interface script, so remove any old PPD file that
1771 * may be lying around...
1778 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1780 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1783 * Raw driver, remove any existing PPD or interface script files.
1786 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1790 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1800 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1801 attr
->values
[0].string
.text
);
1803 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1807 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1810 if (copy_model(srcfile
, dstfile
))
1812 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1813 srcfile
, dstfile
, strerror(errno
));
1814 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1819 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1820 chmod(dstfile
, 0644);
1826 * Make this printer the default if there is none...
1829 if (DefaultPrinter
== NULL
)
1830 DefaultPrinter
= printer
;
1833 * Update the printer attributes and return...
1836 SetPrinterAttrs(printer
);
1839 if (printer
->job
!= NULL
)
1844 * Stop the current job and then restart it below...
1847 job
= (job_t
*)printer
->job
;
1849 StopJob(job
->id
, 1);
1850 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1859 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
1860 "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1863 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1868 AddPrinterHistory(printer
);
1870 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
1871 "New printer \'%s\' added by \'%s\'.", printer
->name
,
1874 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1878 con
->response
->request
.status
.status_code
= IPP_OK
;
1883 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1884 * based upon the printer state...
1888 add_printer_state_reasons(
1889 client_t
*con
, /* I - Client connection */
1890 printer_t
*p
) /* I - Printer info */
1892 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1893 con
, con
->http
.fd
, p
, p
->name
);
1895 if (p
->num_reasons
== 0)
1896 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1897 "printer-state-reasons", NULL
,
1898 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
1900 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1901 "printer-state-reasons", p
->num_reasons
, NULL
,
1902 (const char * const *)p
->reasons
);
1907 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1908 * the specified printer or class.
1912 add_queued_job_count(client_t
*con
, /* I - Client connection */
1913 printer_t
*p
) /* I - Printer or class */
1915 int count
; /* Number of jobs on destination */
1918 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1919 con
, con
->http
.fd
, p
, p
->name
);
1921 count
= GetPrinterJobCount(p
->name
);
1923 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1924 "queued-job-count", count
);
1929 * 'cancel_all_jobs()' - Cancel all print jobs.
1933 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1934 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1936 const char *dest
; /* Destination */
1937 cups_ptype_t dtype
; /* Destination type */
1938 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1939 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
1940 host
[HTTP_MAX_URI
], /* Host portion of URI */
1941 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1942 int port
; /* Port portion of URI */
1943 ipp_attribute_t
*attr
; /* Attribute in request */
1944 const char *username
; /* Username */
1945 int purge
; /* Purge? */
1946 printer_t
*printer
; /* Printer */
1949 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
1950 uri
->values
[0].string
.text
);
1953 * Was this operation called from the correct URI?
1956 if (strncmp(con
->uri
, "/admin/", 7) &&
1957 strncmp(con
->uri
, "/jobs/", 7))
1959 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
1961 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1966 * See if we have a printer URI...
1969 if (strcmp(uri
->name
, "printer-uri"))
1971 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
1972 uri
->name
, uri
->values
[0].string
.text
);
1973 send_ipp_error(con
, IPP_BAD_REQUEST
);
1978 * Get the username (if any) for the jobs we want to cancel (only if
1979 * "my-jobs" is specified...
1982 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
1983 attr
->values
[0].boolean
)
1985 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
1986 username
= attr
->values
[0].string
.text
;
1989 LogMessage(L_ERROR
, "cancel_all_jobs: missing requesting-user-name attribute!");
1990 send_ipp_error(con
, IPP_BAD_REQUEST
);
1998 (username
&& con
->username
[0] && strcmp(username
, con
->username
))) &&
1999 strncmp(con
->uri
, "/admin/", 7))
2001 LogMessage(L_ERROR
, "cancel_all_jobs: only administrators can cancel "
2002 "other users\' jobs!");
2003 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2008 * Look for the "purge-jobs" attribute...
2011 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
2012 purge
= attr
->values
[0].boolean
;
2017 * And if the destination is valid...
2020 httpSeparate(uri
->values
[0].string
.text
, method
, userpass
, host
, &port
,
2023 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2029 if (strcmp(resource
, "/printers/") != 0)
2031 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
2032 send_ipp_error(con
, IPP_NOT_FOUND
);
2040 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
2042 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2043 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2048 * Cancel all jobs on all printers...
2051 CancelJobs(NULL
, username
, purge
);
2053 LogMessage(L_INFO
, "All jobs were %s by \'%s\'.",
2054 purge
? "purged" : "cancelled", con
->username
);
2062 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
2064 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2065 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2070 * Cancel all of the jobs on the named printer...
2073 CancelJobs(dest
, username
, purge
);
2075 LogMessage(L_INFO
, "All jobs on \'%s\' were %s by \'%s\'.", dest
,
2076 purge
? "purged" : "cancelled", con
->username
);
2079 con
->response
->request
.status
.status_code
= IPP_OK
;
2084 * 'cancel_job()' - Cancel a print job.
2088 cancel_job(client_t
*con
, /* I - Client connection */
2089 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2091 ipp_attribute_t
*attr
; /* Current attribute */
2092 int jobid
; /* Job ID */
2093 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2094 username
[HTTP_MAX_URI
], /* Username portion of URI */
2095 host
[HTTP_MAX_URI
], /* Host portion of URI */
2096 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2097 int port
; /* Port portion of URI */
2098 job_t
*job
; /* Job information */
2099 const char *dest
; /* Destination */
2100 cups_ptype_t dtype
; /* Destination type (printer or class) */
2101 printer_t
*printer
; /* Printer data */
2104 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2105 uri
->values
[0].string
.text
);
2108 * Verify that the POST operation was done to a valid URI.
2111 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2112 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
2113 strncmp(con
->uri
, "/printers/", 10) != 0)
2115 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
2117 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2122 * See if we have a job URI or a printer URI...
2125 if (strcmp(uri
->name
, "printer-uri") == 0)
2128 * Got a printer URI; see if we also have a job-id attribute...
2131 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2133 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
2134 send_ipp_error(con
, IPP_BAD_REQUEST
);
2138 if ((jobid
= attr
->values
[0].integer
) == 0)
2141 * Find the current job on the specified printer...
2144 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2146 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2152 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
2153 send_ipp_error(con
, IPP_NOT_FOUND
);
2158 * See if the printer is currently printing a job...
2162 jobid
= ((job_t
*)printer
->job
)->id
;
2166 * No, see if there are any pending jobs...
2169 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
2170 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
2171 strcasecmp(job
->dest
, dest
) == 0)
2178 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
2179 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2188 * Got a job URI; parse it to get the job ID...
2191 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2193 if (strncmp(resource
, "/jobs/", 6) != 0)
2199 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
2200 uri
->values
[0].string
.text
);
2201 send_ipp_error(con
, IPP_BAD_REQUEST
);
2205 jobid
= atoi(resource
+ 6);
2209 * See if the job exists...
2212 if ((job
= FindJob(jobid
)) == NULL
)
2215 * Nope - return a "not found" error...
2218 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
2219 send_ipp_error(con
, IPP_NOT_FOUND
);
2224 * See if the job is owned by the requesting user...
2227 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2229 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
2230 username
, jobid
, job
->username
);
2231 send_ipp_error(con
, IPP_FORBIDDEN
);
2236 * See if the job is already completed, cancelled, or aborted; if so,
2237 * we can't cancel...
2240 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
2242 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
2244 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
2245 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
2247 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2252 * Cancel the job and return...
2255 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED
, job
->printer
, job
,
2256 "Job cancelled by \'%s\'.", username
);
2258 CancelJob(jobid
, 0);
2261 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
2263 con
->response
->request
.status
.status_code
= IPP_OK
;
2268 * 'cancel_subscription()' - Cancel a subscription.
2272 cancel_subscription(client_t
*con
, /* I - Client connection */
2273 int sub_id
) /* I - Subscription ID */
2279 * 'check_quotas()' - Check quotas for a printer and user.
2282 static int /* O - 1 if OK, 0 if not */
2283 check_quotas(client_t
*con
, /* I - Client connection */
2284 printer_t
*p
) /* I - Printer or class */
2286 int i
, j
; /* Looping vars */
2287 ipp_attribute_t
*attr
; /* Current attribute */
2288 char username
[33]; /* Username */
2289 quota_t
*q
; /* Quota data */
2290 struct passwd
*pw
; /* User password data */
2291 struct group
*grp
; /* Group data */
2294 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
2295 con
, con
->http
.fd
, p
, p
->name
);
2301 if (con
== NULL
|| p
== NULL
)
2305 * Figure out who is printing...
2308 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
2310 if (con
->username
[0])
2311 strlcpy(username
, con
->username
, sizeof(username
));
2312 else if (attr
!= NULL
)
2314 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
2315 attr
->values
[0].string
.text
);
2317 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
2320 strcpy(username
, "anonymous");
2323 * Check global active job limits for printers and users...
2326 if (MaxJobsPerPrinter
)
2329 * Check if there are too many pending jobs on this printer...
2332 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
2334 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
2342 * Check if there are too many pending jobs for this user...
2345 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
2347 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
2353 * Check against users...
2356 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
2361 pw
= getpwnam(username
);
2364 for (i
= 0; i
< p
->num_users
; i
++)
2365 if (p
->users
[i
][0] == '@')
2368 * Check group membership...
2371 grp
= getgrnam(p
->users
[i
] + 1);
2377 * Check primary group...
2380 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
2384 * Check usernames in group...
2387 for (j
= 0; grp
->gr_mem
[j
]; j
++)
2388 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
2395 else if (!strcasecmp(username
, p
->users
[i
]))
2398 if ((i
< p
->num_users
) == p
->deny_users
)
2400 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
2410 if (p
->k_limit
|| p
->page_limit
)
2412 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
2414 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
2419 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
2420 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
2422 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
2429 * If we have gotten this far, we're done!
2437 * 'copy_attribute()' - Copy a single attribute.
2440 static ipp_attribute_t
* /* O - New attribute */
2442 ipp_t
*to
, /* O - Destination request/response */
2443 ipp_attribute_t
*attr
, /* I - Attribute to copy */
2444 int quickcopy
) /* I - Do a quick copy? */
2446 int i
; /* Looping var */
2447 ipp_attribute_t
*toattr
; /* Destination attribute */
2450 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
2451 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
2454 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2457 toattr
= ippAddSeparator(to
);
2460 case IPP_TAG_INTEGER
:
2462 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2463 attr
->name
, attr
->num_values
, NULL
);
2465 for (i
= 0; i
< attr
->num_values
; i
++)
2466 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
2469 case IPP_TAG_BOOLEAN
:
2470 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
2471 attr
->num_values
, NULL
);
2473 for (i
= 0; i
< attr
->num_values
; i
++)
2474 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
2477 case IPP_TAG_STRING
:
2480 case IPP_TAG_KEYWORD
:
2482 case IPP_TAG_URISCHEME
:
2483 case IPP_TAG_CHARSET
:
2484 case IPP_TAG_LANGUAGE
:
2485 case IPP_TAG_MIMETYPE
:
2486 toattr
= ippAddStrings(to
, attr
->group_tag
,
2487 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2488 attr
->name
, attr
->num_values
, NULL
, NULL
);
2492 for (i
= 0; i
< attr
->num_values
; i
++)
2493 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2497 for (i
= 0; i
< attr
->num_values
; i
++)
2498 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2503 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
2504 attr
->values
[0].date
);
2507 case IPP_TAG_RESOLUTION
:
2508 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
2509 attr
->num_values
, IPP_RES_PER_INCH
,
2512 for (i
= 0; i
< attr
->num_values
; i
++)
2514 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
2515 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
2516 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
2520 case IPP_TAG_RANGE
:
2521 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
2522 attr
->num_values
, NULL
, NULL
);
2524 for (i
= 0; i
< attr
->num_values
; i
++)
2526 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
2527 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
2531 case IPP_TAG_TEXTLANG
:
2532 case IPP_TAG_NAMELANG
:
2533 toattr
= ippAddStrings(to
, attr
->group_tag
,
2534 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2535 attr
->name
, attr
->num_values
, NULL
, NULL
);
2539 for (i
= 0; i
< attr
->num_values
; i
++)
2541 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
2542 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2547 for (i
= 0; i
< attr
->num_values
; i
++)
2550 toattr
->values
[i
].string
.charset
=
2551 strdup(attr
->values
[i
].string
.charset
);
2553 toattr
->values
[i
].string
.charset
=
2554 toattr
->values
[0].string
.charset
;
2556 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2561 case IPP_TAG_BEGIN_COLLECTION
:
2562 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
2563 attr
->num_values
, NULL
);
2565 for (i
= 0; i
< attr
->num_values
; i
++)
2567 toattr
->values
[i
].collection
= ippNew();
2568 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
2569 NULL
, IPP_TAG_ZERO
, 0);
2574 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2575 attr
->name
, attr
->num_values
, NULL
);
2577 for (i
= 0; i
< attr
->num_values
; i
++)
2579 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
2581 if (toattr
->values
[i
].unknown
.length
> 0)
2583 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
2584 toattr
->values
[i
].unknown
.length
= 0;
2586 memcpy(toattr
->values
[i
].unknown
.data
,
2587 attr
->values
[i
].unknown
.data
,
2588 toattr
->values
[i
].unknown
.length
);
2591 break; /* anti-compiler-warning-code */
2599 * 'copy_attrs()' - Copy attributes from one request to another.
2603 copy_attrs(ipp_t
*to
, /* I - Destination request */
2604 ipp_t
*from
, /* I - Source request */
2605 ipp_attribute_t
*req
, /* I - Requested attributes */
2606 ipp_tag_t group
, /* I - Group to copy */
2607 int quickcopy
) /* I - Do a quick copy? */
2609 int i
; /* Looping var */
2610 ipp_attribute_t
*fromattr
; /* Source attribute */
2613 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2615 if (to
== NULL
|| from
== NULL
)
2618 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2619 req
= NULL
; /* "all" means no filter... */
2621 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2624 * Filter attributes as needed...
2627 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2628 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2631 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2633 for (i
= 0; i
< req
->num_values
; i
++)
2634 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2637 if (i
== req
->num_values
)
2641 copy_attribute(to
, fromattr
, quickcopy
);
2647 * 'copy_banner()' - Copy a banner file to the requests directory for the
2651 static int /* O - Size of banner file in kbytes */
2652 copy_banner(client_t
*con
, /* I - Client connection */
2653 job_t
*job
, /* I - Job information */
2654 const char *name
) /* I - Name of banner */
2656 int i
; /* Looping var */
2657 int kbytes
; /* Size of banner file in kbytes */
2658 char filename
[1024]; /* Job filename */
2659 banner_t
*banner
; /* Pointer to banner */
2660 cups_file_t
*in
; /* Input file */
2661 cups_file_t
*out
; /* Output file */
2662 int ch
; /* Character from file */
2663 char attrname
[255], /* Name of attribute */
2664 *s
; /* Pointer into name */
2665 ipp_attribute_t
*attr
; /* Attribute */
2668 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2669 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2672 * Find the banner; return if not found or "none"...
2676 strcmp(name
, "none") == 0 ||
2677 (banner
= FindBanner(name
)) == NULL
)
2681 * Open the banner and job files...
2684 if (add_file(con
, job
, banner
->filetype
, 0))
2687 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2689 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
2691 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2692 filename
, strerror(errno
));
2697 fchmod(cupsFileNumber(out
), 0640);
2698 fchown(cupsFileNumber(out
), RunUser
, Group
);
2703 * Try the localized banner file under the subdirectory...
2706 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2707 con
->language
->language
, name
);
2709 if (access(filename
, 0) && con
->language
->language
[2])
2712 * Wasn't able to find "ll_CC" locale file; try the non-national
2713 * localization banner directory.
2716 attrname
[0] = con
->language
->language
[0];
2717 attrname
[1] = con
->language
->language
[1];
2720 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2724 if (access(filename
, 0))
2727 * Use the non-localized banner file.
2730 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2736 * Use the non-localized banner file.
2739 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2742 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
2746 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2747 filename
, strerror(errno
));
2753 * Parse the file to the end...
2756 while ((ch
= cupsFileGetChar(in
)) != EOF
)
2760 * Get an attribute name...
2763 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
2764 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
2766 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2776 * Ignore { followed by stuff that is not an attribute name...
2779 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
2784 * See if it is defined...
2787 if (attrname
[0] == '?')
2792 if (strcmp(s
, "printer-name") == 0)
2794 cupsFilePuts(out
, job
->dest
);
2797 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2800 * See if we have a leading question mark...
2803 if (attrname
[0] != '?')
2806 * Nope, write to file as-is; probably a PostScript procedure...
2809 cupsFilePrintf(out
, "{%s}", attrname
);
2816 * Output value(s)...
2819 for (i
= 0; i
< attr
->num_values
; i
++)
2822 cupsFilePutChar(out
, ',');
2824 switch (attr
->value_tag
)
2826 case IPP_TAG_INTEGER
:
2828 if (strncmp(s
, "time-at-", 8) == 0)
2829 cupsFilePuts(out
, GetDateTime(attr
->values
[i
].integer
));
2831 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
2834 case IPP_TAG_BOOLEAN
:
2835 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
2838 case IPP_TAG_NOVALUE
:
2839 cupsFilePuts(out
, "novalue");
2842 case IPP_TAG_RANGE
:
2843 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2844 attr
->values
[i
].range
.upper
);
2847 case IPP_TAG_RESOLUTION
:
2848 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2849 attr
->values
[i
].resolution
.yres
,
2850 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2855 case IPP_TAG_STRING
:
2858 case IPP_TAG_KEYWORD
:
2859 case IPP_TAG_CHARSET
:
2860 case IPP_TAG_LANGUAGE
:
2861 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2864 * Need to quote strings for PS banners...
2869 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2871 if (*p
== '(' || *p
== ')' || *p
== '\\')
2873 cupsFilePutChar(out
, '\\');
2874 cupsFilePutChar(out
, *p
);
2876 else if (*p
< 32 || *p
> 126)
2877 cupsFilePrintf(out
, "\\%03o", *p
& 255);
2879 cupsFilePutChar(out
, *p
);
2883 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
2887 break; /* anti-compiler-warning-code */
2891 else if (ch
== '\\') /* Quoted char */
2893 ch
= cupsFileGetChar(in
);
2895 if (ch
!= '{') /* Only do special handling for \{ */
2896 cupsFilePutChar(out
, '\\');
2898 cupsFilePutChar(out
, ch
);
2901 cupsFilePutChar(out
, ch
);
2905 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
2907 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2908 attr
->values
[0].integer
+= kbytes
;
2917 * 'copy_file()' - Copy a PPD file or interface script...
2920 static int /* O - 0 = success, -1 = error */
2921 copy_file(const char *from
, /* I - Source file */
2922 const char *to
) /* I - Destination file */
2924 cups_file_t
*src
, /* Source file */
2925 *dst
; /* Destination file */
2926 int bytes
; /* Bytes to read/write */
2927 char buffer
[2048]; /* Copy buffer */
2930 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
2933 * Open the source and destination file for a copy...
2936 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
2939 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
2946 * Copy the source file to the destination...
2949 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
2950 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
2958 * Close both files and return...
2963 return (cupsFileClose(dst
));
2968 * 'copy_model()' - Copy a PPD model file, substituting default values
2972 static int /* O - 0 = success, -1 = error */
2973 copy_model(const char *from
, /* I - Source file */
2974 const char *to
) /* I - Destination file */
2976 cups_file_t
*src
, /* Source file */
2977 *dst
; /* Destination file */
2978 char buffer
[2048]; /* Copy buffer */
2979 int i
; /* Looping var */
2980 char option
[PPD_MAX_NAME
], /* Option name */
2981 choice
[PPD_MAX_NAME
]; /* Choice name */
2982 int num_defaults
; /* Number of default options */
2983 ppd_default_t
*defaults
; /* Default options */
2984 char cups_protocol
[PPD_MAX_LINE
];
2985 /* cupsProtocol attribute */
2986 #ifdef HAVE_LIBPAPER
2987 char *paper_result
; /* Paper size name from libpaper */
2988 char system_paper
[64]; /* Paper size name buffer */
2989 #endif /* HAVE_LIBPAPER */
2992 LogMessage(L_DEBUG2
, "copy_model(\"%s\", \"%s\")\n", from
, to
);
2995 * Open the destination (if possible) and set the default options...
3000 cups_protocol
[0] = '\0';
3002 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
3005 * Read all of the default lines from the old PPD...
3008 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)) != NULL
)
3009 if (!strncmp(buffer
, "*Default", 8))
3012 * Add the default option...
3015 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3016 choice
, sizeof(choice
)))
3017 num_defaults
= ppd_add_default(option
, choice
, num_defaults
,
3020 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
3021 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
3025 #ifdef HAVE_LIBPAPER
3026 else if ((paper_result
= systempapername()) != NULL
)
3029 * Set the default media sizes from the systemwide default...
3032 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
3033 system_paper
[0] = toupper(system_paper
[0] & 255);
3035 num_defaults
= ppd_add_default("PageSize", system_paper
,
3036 num_defaults
, &defaults
);
3037 num_defaults
= ppd_add_default("PageRegion", system_paper
,
3038 num_defaults
, &defaults
);
3039 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
3040 num_defaults
, &defaults
);
3041 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
3042 num_defaults
, &defaults
);
3044 #endif /* HAVE_LIBPAPER */
3048 * Add the default media sizes...
3050 * Note: These values are generally not valid for large-format devices
3051 * like plotters, however it is probably safe to say that those
3052 * users will configure the media size after initially adding
3053 * the device anyways...
3056 if (!DefaultLanguage
||
3057 !strcasecmp(DefaultLanguage
, "C") ||
3058 !strcasecmp(DefaultLanguage
, "POSIX") ||
3059 !strcasecmp(DefaultLanguage
, "en") ||
3060 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
3061 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
3062 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
3065 * These are the only locales that will default to "letter" size...
3068 num_defaults
= ppd_add_default("PageSize", "Letter", num_defaults
,
3070 num_defaults
= ppd_add_default("PageRegion", "Letter", num_defaults
,
3072 num_defaults
= ppd_add_default("PaperDimension", "Letter", num_defaults
,
3074 num_defaults
= ppd_add_default("ImageableArea", "Letter", num_defaults
,
3080 * The rest default to "a4" size...
3083 num_defaults
= ppd_add_default("PageSize", "A4", num_defaults
,
3085 num_defaults
= ppd_add_default("PageRegion", "A4", num_defaults
,
3087 num_defaults
= ppd_add_default("PaperDimension", "A4", num_defaults
,
3089 num_defaults
= ppd_add_default("ImageableArea", "A4", num_defaults
,
3095 * Open the source and destination file for a copy...
3098 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3100 if (num_defaults
> 0)
3106 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3108 if (num_defaults
> 0)
3116 * Copy the source file to the destination...
3119 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3121 if (!strncmp(buffer
, "*Default", 8))
3124 * Check for an previous default option choice...
3127 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3128 choice
, sizeof(choice
)))
3130 for (i
= 0; i
< num_defaults
; i
++)
3131 if (!strcmp(option
, defaults
[i
].option
))
3134 * Substitute the previous choice...
3137 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
,
3138 defaults
[i
].choice
);
3144 cupsFilePrintf(dst
, "%s\n", buffer
);
3147 if (cups_protocol
[0])
3148 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
3150 if (num_defaults
> 0)
3154 * Close both files and return...
3159 return (cupsFileClose(dst
));
3164 * 'create_job()' - Print a file to a printer or class.
3168 create_job(client_t
*con
, /* I - Client connection */
3169 ipp_attribute_t
*uri
) /* I - Printer URI */
3171 ipp_attribute_t
*attr
; /* Current attribute */
3172 const char *dest
; /* Destination */
3173 cups_ptype_t dtype
; /* Destination type (printer or class) */
3174 int priority
; /* Job priority */
3175 char *title
; /* Job name/title */
3176 job_t
*job
; /* Current job */
3177 char job_uri
[HTTP_MAX_URI
], /* Job URI */
3178 method
[HTTP_MAX_URI
], /* Method portion of URI */
3179 username
[HTTP_MAX_URI
], /* Username portion of URI */
3180 host
[HTTP_MAX_URI
], /* Host portion of URI */
3181 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3182 int port
; /* Port portion of URI */
3183 printer_t
*printer
; /* Printer data */
3184 int kbytes
; /* Size of print file */
3185 int i
; /* Looping var */
3186 int lowerpagerange
; /* Page range bound */
3189 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3190 uri
->values
[0].string
.text
);
3193 * Verify that the POST operation was done to a valid URI.
3196 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3197 strncmp(con
->uri
, "/printers/", 10) != 0)
3199 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
3201 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3206 * Is the destination valid?
3209 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3211 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3217 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
3218 send_ipp_error(con
, IPP_NOT_FOUND
);
3226 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3228 LogMessage(L_ERROR
, "create_job: not authorized!");
3229 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3234 * See if the printer is accepting jobs...
3237 if (!printer
->accepting
)
3239 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
3241 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3246 * Validate job template attributes; for now just copies and page-ranges...
3249 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
3251 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
3253 LogMessage(L_INFO
, "create_job: bad copies value %d.",
3254 attr
->values
[0].integer
);
3255 send_ipp_error(con
, IPP_BAD_REQUEST
);
3260 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
3262 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
3264 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
3265 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3267 LogMessage(L_ERROR
, "create_job: bad page-ranges values %d-%d.",
3268 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3269 send_ipp_error(con
, IPP_BAD_REQUEST
);
3273 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
3278 * Make sure we aren't over our limit...
3281 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3284 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3286 LogMessage(L_INFO
, "create_job: too many jobs.");
3287 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3291 if (!check_quotas(con
, printer
))
3293 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3298 * Create the job and set things up...
3301 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3302 priority
= attr
->values
[0].integer
;
3304 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3307 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3308 title
= attr
->values
[0].string
.text
;
3310 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3311 title
= "Untitled");
3313 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3315 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
3317 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3322 job
->attrs
= con
->request
;
3323 con
->request
= NULL
;
3325 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3327 if (con
->username
[0])
3328 SetString(&job
->username
, con
->username
);
3329 else if (attr
!= NULL
)
3331 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
3332 attr
->values
[0].string
.text
);
3334 SetString(&job
->username
, attr
->values
[0].string
.text
);
3337 SetString(&job
->username
, "anonymous");
3340 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3341 NULL
, job
->username
);
3344 attr
->group_tag
= IPP_TAG_JOB
;
3345 SetString(&attr
->name
, "job-originating-user-name");
3348 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
3349 IPP_TAG_ZERO
)) != NULL
)
3352 * Request contains a job-originating-host-name attribute; validate it...
3355 if (attr
->value_tag
!= IPP_TAG_NAME
||
3356 attr
->num_values
!= 1 ||
3357 strcmp(con
->http
.hostname
, "localhost") != 0)
3360 * Can't override the value if we aren't connected via localhost.
3361 * Also, we can only have 1 value and it must be a name value.
3364 switch (attr
->value_tag
)
3366 case IPP_TAG_STRING
:
3367 case IPP_TAG_TEXTLANG
:
3368 case IPP_TAG_NAMELANG
:
3371 case IPP_TAG_KEYWORD
:
3373 case IPP_TAG_URISCHEME
:
3374 case IPP_TAG_CHARSET
:
3375 case IPP_TAG_LANGUAGE
:
3376 case IPP_TAG_MIMETYPE
:
3378 * Free old strings...
3381 for (i
= 0; i
< attr
->num_values
; i
++)
3383 free(attr
->values
[i
].string
.text
);
3384 attr
->values
[i
].string
.text
= NULL
;
3385 if (attr
->values
[i
].string
.charset
)
3387 free(attr
->values
[i
].string
.charset
);
3388 attr
->values
[i
].string
.charset
= NULL
;
3397 * Use the default connection hostname instead...
3400 attr
->value_tag
= IPP_TAG_NAME
;
3401 attr
->num_values
= 1;
3402 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
3405 attr
->group_tag
= IPP_TAG_JOB
;
3410 * No job-originating-host-name attribute, so use the hostname from
3414 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3415 "job-originating-host-name", NULL
, con
->http
.hostname
);
3418 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3420 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3421 "time-at-processing", 0);
3422 attr
->value_tag
= IPP_TAG_NOVALUE
;
3423 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3424 "time-at-completed", 0);
3425 attr
->value_tag
= IPP_TAG_NOVALUE
;
3428 * Add remaining job attributes...
3431 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3432 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3433 "job-state", IPP_JOB_STOPPED
);
3434 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3435 "job-media-sheets-completed", 0);
3436 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3438 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3441 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3442 attr
->values
[0].integer
= 0;
3444 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3447 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3448 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3450 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
3451 "job-hold-until", NULL
, "no-hold");
3452 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
3453 !(printer
->type
& CUPS_PRINTER_REMOTE
))
3456 * Hold job until specified time...
3459 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3462 job
->hold_until
= time(NULL
) + 60;
3464 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
3466 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
3470 * Add job sheets options...
3473 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
3475 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
3476 printer
->job_sheets
[0], printer
->job_sheets
[1]);
3478 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
3480 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
3481 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
3484 job
->job_sheets
= attr
;
3487 * Enforce classification level if set...
3492 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
3493 Classification
? Classification
: "(null)", ClassifyOverride
);
3495 if (ClassifyOverride
)
3497 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
3498 (attr
->num_values
== 1 ||
3499 strcmp(attr
->values
[1].string
.text
, "none") == 0))
3502 * Force the leading banner to have the classification on it...
3505 SetString(&attr
->values
[0].string
.text
, Classification
);
3507 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3508 "job-sheets=\"%s,none\", "
3509 "job-originating-user-name=\"%s\"",
3510 job
->id
, Classification
,
3513 else if (attr
->num_values
== 2 &&
3514 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
3515 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
3516 strcmp(attr
->values
[1].string
.text
, "none") != 0)
3519 * Can't put two different security markings on the same document!
3522 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
3524 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3525 "job-sheets=\"%s,%s\", "
3526 "job-originating-user-name=\"%s\"",
3527 job
->id
, attr
->values
[0].string
.text
,
3528 attr
->values
[1].string
.text
,
3531 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
3532 strcmp(attr
->values
[0].string
.text
, "none") &&
3533 (attr
->num_values
== 1 ||
3534 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
3535 strcmp(attr
->values
[1].string
.text
, "none"))))
3537 if (attr
->num_values
== 1)
3538 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3539 "job-sheets=\"%s\", "
3540 "job-originating-user-name=\"%s\"",
3541 job
->id
, attr
->values
[0].string
.text
,
3544 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3545 "job-sheets=\"%s,%s\",fffff "
3546 "job-originating-user-name=\"%s\"",
3547 job
->id
, attr
->values
[0].string
.text
,
3548 attr
->values
[1].string
.text
,
3552 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
3553 (attr
->num_values
== 1 ||
3554 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
3557 * Force the banner to have the classification on it...
3560 if (attr
->num_values
> 1 &&
3561 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
3563 SetString(&(attr
->values
[0].string
.text
), Classification
);
3564 SetString(&(attr
->values
[1].string
.text
), Classification
);
3568 if (attr
->num_values
== 1 ||
3569 strcmp(attr
->values
[0].string
.text
, "none"))
3570 SetString(&(attr
->values
[0].string
.text
), Classification
);
3572 if (attr
->num_values
> 1 &&
3573 strcmp(attr
->values
[1].string
.text
, "none"))
3574 SetString(&(attr
->values
[1].string
.text
), Classification
);
3577 if (attr
->num_values
> 1)
3578 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3579 "job-sheets=\"%s,%s\", "
3580 "job-originating-user-name=\"%s\"",
3581 job
->id
, attr
->values
[0].string
.text
,
3582 attr
->values
[1].string
.text
,
3585 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3586 "job-sheets=\"%s\", "
3587 "job-originating-user-name=\"%s\"",
3588 job
->id
, Classification
,
3594 * See if we need to add the starting sheet...
3597 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
3599 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
3600 attr
->values
[0].string
.text
, job
->id
);
3602 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
3604 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3607 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
3611 * Add any job subscriptions...
3614 add_job_subscriptions(con
, job
);
3617 * Set all but the first two attributes to the job attributes group...
3620 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
3621 attr
->group_tag
= IPP_TAG_JOB
;
3624 * Save and log the job...
3629 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
3630 job
->dest
, job
->username
);
3632 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
3635 * Fill in the response info...
3638 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3639 LocalPort
, job
->id
);
3641 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
3643 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3645 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
3646 job
->state
->values
[0].integer
);
3648 con
->response
->request
.status
.status_code
= IPP_OK
;
3653 * 'create_subscription()' - Create a notification subscription.
3657 create_subscription(
3658 client_t
*con
, /* I - Client connection */
3659 ipp_attribute_t
*uri
) /* I - Printer URI */
3665 * 'delete_printer()' - Remove a printer or class from the system.
3669 delete_printer(client_t
*con
, /* I - Client connection */
3670 ipp_attribute_t
*uri
) /* I - URI of printer or class */
3672 const char *dest
; /* Destination */
3673 cups_ptype_t dtype
; /* Destination type (printer or class) */
3674 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3675 username
[HTTP_MAX_URI
], /* Username portion of URI */
3676 host
[HTTP_MAX_URI
], /* Host portion of URI */
3677 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3678 int port
; /* Port portion of URI */
3679 printer_t
*printer
; /* Printer/class */
3680 char filename
[1024]; /* Script/PPD filename */
3683 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
3684 uri
->values
[0].string
.text
);
3687 * Was this operation called from the correct URI?
3690 if (strncmp(con
->uri
, "/admin/", 7) != 0)
3692 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
3694 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3699 * Do we have a valid URI?
3702 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3704 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3710 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
3711 send_ipp_error(con
, IPP_NOT_FOUND
);
3719 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3721 LogMessage(L_ERROR
, "delete_printer: not authorized!");
3722 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3727 * Remove old jobs...
3730 CancelJobs(dest
, NULL
, 1);
3733 * Remove old subscriptions and send a "deleted printer" event...
3736 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
3737 "%s \'%s\' deleted by \'%s\'.",
3738 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
3739 dest
, con
->username
);
3741 cupsdExpireSubscriptions(printer
, NULL
);
3744 * Remove any old PPD or script files...
3747 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
3750 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
3753 if (dtype
& CUPS_PRINTER_CLASS
)
3755 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
3758 DeletePrinter(printer
, 0);
3763 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
3766 DeletePrinter(printer
, 0);
3771 * Return with no errors...
3774 con
->response
->request
.status
.status_code
= IPP_OK
;
3779 * 'get_default()' - Get the default destination.
3783 get_default(client_t
*con
) /* I - Client connection */
3785 int i
; /* Looping var */
3786 ipp_attribute_t
*requested
, /* requested-attributes */
3787 *history
; /* History collection */
3788 int need_history
; /* Need to send history collection? */
3791 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
3797 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3799 LogMessage(L_ERROR
, "get_default: not authorized!");
3800 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3804 if (DefaultPrinter
!= NULL
)
3806 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3809 copy_attrs(con
->response
, DefaultPrinter
->attrs
, requested
, IPP_TAG_ZERO
, 0);
3810 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
3814 if (MaxPrinterHistory
> 0 && DefaultPrinter
->num_history
> 0 && requested
)
3816 for (i
= 0; i
< requested
->num_values
; i
++)
3817 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
3818 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
3827 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
3828 "printer-state-history",
3829 DefaultPrinter
->num_history
, NULL
);
3831 for (i
= 0; i
< DefaultPrinter
->num_history
; i
++)
3832 copy_attrs(history
->values
[i
].collection
= ippNew(),
3833 DefaultPrinter
->history
[i
],
3834 NULL
, IPP_TAG_ZERO
, 0);
3837 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
3840 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
3845 * 'get_devices()' - Get the list of available devices on the local system.
3849 get_devices(client_t
*con
) /* I - Client connection */
3851 ipp_attribute_t
*limit
; /* Limit attribute */
3852 char command
[1024], /* cups-deviced command */
3853 options
[1024]; /* Options to pass to command */
3856 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
3862 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3864 LogMessage(L_ERROR
, "get_devices: not authorized!");
3865 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3870 * Run cups-deviced command with the given options...
3873 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
3875 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
3876 snprintf(options
, sizeof(options
), "cups-deviced %d+%d",
3877 con
->request
->request
.op
.request_id
,
3878 limit
? limit
->values
[0].integer
: 0);
3880 if (SendCommand(con
, command
, options
))
3883 * Command started successfully, don't send an IPP response here...
3886 ippDelete(con
->response
);
3887 con
->response
= NULL
;
3892 * Command failed, return "internal error" so the user knows something
3896 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3902 * 'get_jobs()' - Get a list of jobs for the specified printer.
3906 get_jobs(client_t
*con
, /* I - Client connection */
3907 ipp_attribute_t
*uri
) /* I - Printer URI */
3909 ipp_attribute_t
*attr
, /* Current attribute */
3910 *requested
; /* Requested attributes */
3911 const char *dest
; /* Destination */
3912 cups_ptype_t dtype
; /* Destination type (printer or class) */
3913 cups_ptype_t dmask
; /* Destination type mask */
3914 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3915 username
[HTTP_MAX_URI
], /* Username portion of URI */
3916 host
[HTTP_MAX_URI
], /* Host portion of URI */
3917 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3918 int port
; /* Port portion of URI */
3919 int completed
; /* Completed jobs? */
3920 int limit
; /* Maximum number of jobs to return */
3921 int count
; /* Number of jobs that match */
3922 job_t
*job
; /* Current job pointer */
3923 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
3924 printer_t
*printer
; /* Printer */
3927 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
3928 uri
->values
[0].string
.text
);
3931 * Is the destination valid?
3934 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3936 if (strcmp(resource
, "/") == 0 ||
3937 (strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6))
3940 dtype
= (cups_ptype_t
)0;
3941 dmask
= (cups_ptype_t
)0;
3944 else if (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10)
3947 dtype
= (cups_ptype_t
)0;
3948 dmask
= CUPS_PRINTER_CLASS
;
3951 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
3954 dtype
= CUPS_PRINTER_CLASS
;
3955 dmask
= CUPS_PRINTER_CLASS
;
3958 else if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3964 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
3965 send_ipp_error(con
, IPP_NOT_FOUND
);
3969 dmask
= CUPS_PRINTER_CLASS
;
3977 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3979 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3980 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3984 else if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3986 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3987 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3992 * See if the "which-jobs" attribute have been specified...
3995 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
3996 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
4002 * See if they want to limit the number of jobs reported...
4005 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4006 limit
= attr
->values
[0].integer
;
4011 * See if we only want to see jobs for a specific user...
4014 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
4015 attr
->values
[0].boolean
)
4017 if (con
->username
[0])
4018 strlcpy(username
, con
->username
, sizeof(username
));
4019 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4020 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
4022 strcpy(username
, "anonymous");
4027 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4031 * OK, build a list of jobs for this printer...
4034 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
4037 * Filter out jobs that don't match...
4040 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
4042 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0) &&
4043 (job
->printer
== NULL
|| dest
== NULL
||
4044 strcmp(job
->printer
->name
, dest
) != 0))
4046 if ((job
->dtype
& dmask
) != dtype
&&
4047 (job
->printer
== NULL
|| (job
->printer
->type
& dmask
) != dtype
))
4049 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
4052 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
4054 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4059 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
4062 * Send the requested attributes for each job...
4065 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4066 LocalPort
, job
->id
);
4068 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4069 "job-more-info", NULL
, job_uri
);
4071 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4072 "job-uri", NULL
, job_uri
);
4074 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4075 "job-printer-up-time", time(NULL
));
4078 * Copy the job attributes to the response using the requested-attributes
4079 * attribute that may be provided by the client.
4082 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4084 add_job_state_reasons(con
, job
);
4086 ippAddSeparator(con
->response
);
4089 if (requested
!= NULL
)
4090 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4092 con
->response
->request
.status
.status_code
= IPP_OK
;
4097 * 'get_job_attrs()' - Get job attributes.
4101 get_job_attrs(client_t
*con
, /* I - Client connection */
4102 ipp_attribute_t
*uri
) /* I - Job URI */
4104 ipp_attribute_t
*attr
, /* Current attribute */
4105 *requested
; /* Requested attributes */
4106 int jobid
; /* Job ID */
4107 job_t
*job
; /* Current job */
4108 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4109 username
[HTTP_MAX_URI
], /* Username portion of URI */
4110 host
[HTTP_MAX_URI
], /* Host portion of URI */
4111 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4112 int port
; /* Port portion of URI */
4113 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4116 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4117 uri
->values
[0].string
.text
);
4120 * See if we have a job URI or a printer URI...
4123 if (strcmp(uri
->name
, "printer-uri") == 0)
4126 * Got a printer URI; see if we also have a job-id attribute...
4129 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4131 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
4132 send_ipp_error(con
, IPP_BAD_REQUEST
);
4136 jobid
= attr
->values
[0].integer
;
4141 * Got a job URI; parse it to get the job ID...
4144 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4146 if (strncmp(resource
, "/jobs/", 6) != 0)
4152 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
4153 uri
->values
[0].string
.text
);
4154 send_ipp_error(con
, IPP_BAD_REQUEST
);
4158 jobid
= atoi(resource
+ 6);
4162 * See if the job exists...
4165 if ((job
= FindJob(jobid
)) == NULL
)
4168 * Nope - return a "not found" error...
4171 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
4172 send_ipp_error(con
, IPP_NOT_FOUND
);
4180 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4182 LogMessage(L_ERROR
, "get_job_attrs: not authorized!");
4183 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4188 * Put out the standard attributes...
4191 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
4192 ServerName
, LocalPort
, job
->id
);
4194 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4196 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4197 "job-more-info", NULL
, job_uri
);
4199 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4200 "job-uri", NULL
, job_uri
);
4202 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4203 "job-printer-up-time", time(NULL
));
4206 * Copy the job attributes to the response using the requested-attributes
4207 * attribute that may be provided by the client.
4210 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4213 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4215 add_job_state_reasons(con
, job
);
4217 if (requested
!= NULL
)
4218 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4220 con
->response
->request
.status
.status_code
= IPP_OK
;
4225 * 'get_notifications()' - Get events for a subscription.
4229 get_notifications(client_t
*con
, /* I - Client connection */
4230 int id
) /* I - Subscription ID */
4236 * 'get_ppds()' - Get the list of PPD files on the local system.
4240 get_ppds(client_t
*con
) /* I - Client connection */
4242 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
4248 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4250 LogMessage(L_ERROR
, "get_ppds: not authorized!");
4251 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4256 * Copy the PPD attributes to the response using the requested-attributes
4257 * attribute that may be provided by the client.
4260 copy_attrs(con
->response
, PPDs
,
4261 ippFindAttribute(con
->request
, "requested-attributes",
4262 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
, IPP_TAG_COPY
);
4264 con
->response
->request
.status
.status_code
= IPP_OK
;
4269 * 'get_printer_attrs()' - Get printer attributes.
4273 get_printer_attrs(client_t
*con
, /* I - Client connection */
4274 ipp_attribute_t
*uri
) /* I - Printer URI */
4276 const char *dest
; /* Destination */
4277 cups_ptype_t dtype
; /* Destination type (printer or class) */
4278 char method
[HTTP_MAX_URI
],
4279 /* Method portion of URI */
4280 username
[HTTP_MAX_URI
],
4281 /* Username portion of URI */
4283 /* Host portion of URI */
4284 resource
[HTTP_MAX_URI
];
4285 /* Resource portion of URI */
4286 int port
; /* Port portion of URI */
4287 printer_t
*printer
; /* Printer/class */
4288 time_t curtime
; /* Current time */
4289 int i
; /* Looping var */
4290 ipp_attribute_t
*requested
, /* requested-attributes */
4291 *history
; /* History collection */
4292 int need_history
; /* Need to send history collection? */
4295 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4296 uri
->values
[0].string
.text
);
4299 * Is the destination valid?
4302 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4304 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4310 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
4311 send_ipp_error(con
, IPP_NOT_FOUND
);
4319 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4321 LogMessage(L_ERROR
, "get_printer_attrs: not authorized!");
4322 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4326 curtime
= time(NULL
);
4329 * Copy the printer attributes to the response using requested-attributes
4330 * and document-format attributes that may be provided by the client.
4333 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4336 add_printer_state_reasons(con
, printer
);
4338 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4339 "printer-state-message", NULL
, printer
->state_message
);
4341 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4342 printer
->accepting
);
4344 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4345 "printer-up-time", curtime
);
4346 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4347 "printer-state-time", printer
->state_time
);
4348 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4349 ippTimeToDate(curtime
));
4351 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4352 "printer-error-policy", NULL
, printer
->op_policy
);
4353 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4354 "printer-op-policy", NULL
, printer
->op_policy
);
4356 add_queued_job_count(con
, printer
);
4358 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4361 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4362 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4366 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 && requested
)
4368 for (i
= 0; i
< requested
->num_values
; i
++)
4369 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4370 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4379 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4380 "printer-state-history",
4381 printer
->num_history
, NULL
);
4383 for (i
= 0; i
< printer
->num_history
; i
++)
4384 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4385 NULL
, IPP_TAG_ZERO
, 0);
4388 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4393 * 'get_printers()' - Get a list of printers or classes.
4397 get_printers(client_t
*con
, /* I - Client connection */
4398 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
4400 int i
; /* Looping var */
4401 ipp_attribute_t
*requested
, /* requested-attributes */
4402 *history
, /* History collection */
4403 *attr
; /* Current attribute */
4404 int need_history
; /* Need to send history collection? */
4405 int limit
; /* Maximum number of printers to return */
4406 int count
; /* Number of printers that match */
4407 printer_t
*printer
; /* Current printer pointer */
4408 time_t curtime
; /* Current time */
4409 int printer_type
, /* printer-type attribute */
4410 printer_mask
; /* printer-type-mask attribute */
4411 char *location
; /* Location string */
4412 char name
[IPP_MAX_NAME
], /* Printer name */
4413 *nameptr
; /* Pointer into name */
4414 printer_t
*iclass
; /* Implicit class */
4415 const char *username
; /* Current user */
4418 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
4424 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4426 LogMessage(L_ERROR
, "get_printers: not authorized!");
4427 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4432 * See if they want to limit the number of printers reported...
4435 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4436 limit
= attr
->values
[0].integer
;
4441 * Support filtering...
4444 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
4445 printer_type
= attr
->values
[0].integer
;
4449 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
4450 printer_mask
= attr
->values
[0].integer
;
4454 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
4455 location
= attr
->values
[0].string
.text
;
4459 if (con
->username
[0])
4460 username
= con
->username
;
4461 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4462 username
= attr
->values
[0].string
.text
;
4466 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4471 if (MaxPrinterHistory
> 0 && requested
)
4473 for (i
= 0; i
< requested
->num_values
; i
++)
4474 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4475 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4483 * OK, build a list of printers for this printer...
4486 curtime
= time(NULL
);
4488 for (count
= 0, printer
= Printers
;
4489 count
< limit
&& printer
!= NULL
;
4490 printer
= printer
->next
)
4491 if ((printer
->type
& CUPS_PRINTER_CLASS
) == type
&&
4492 (printer
->type
& printer_mask
) == printer_type
&&
4493 (location
== NULL
|| printer
->location
== NULL
||
4494 strcasecmp(printer
->location
, location
) == 0))
4497 * If HideImplicitMembers is enabled, see if this printer or class
4498 * is a member of an implicit class...
4501 if (ImplicitClasses
&& HideImplicitMembers
&&
4502 (printer
->type
& CUPS_PRINTER_REMOTE
))
4505 * Make a copy of the printer name...
4508 strlcpy(name
, printer
->name
, sizeof(name
));
4510 if ((nameptr
= strchr(name
, '@')) != NULL
)
4513 * Strip trailing @server...
4519 * Find the core printer, if any...
4522 if ((iclass
= FindPrinter(name
)) != NULL
&&
4523 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
4529 * If a username is specified, see if it is allowed or denied
4533 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
4537 * Add the group separator as needed...
4541 ippAddSeparator(con
->response
);
4546 * Send the following attributes for each printer:
4549 * printer-state-message
4550 * printer-is-accepting-jobs
4551 * + all printer attributes
4554 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
4555 "printer-state", printer
->state
);
4557 add_printer_state_reasons(con
, printer
);
4559 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4560 "printer-state-message", NULL
, printer
->state_message
);
4562 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4563 printer
->accepting
);
4565 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4566 "printer-up-time", curtime
);
4567 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4568 "printer-state-time", printer
->state_time
);
4569 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4570 ippTimeToDate(curtime
));
4572 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4573 "printer-error-policy", NULL
, printer
->op_policy
);
4574 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4575 "printer-op-policy", NULL
, printer
->op_policy
);
4577 add_queued_job_count(con
, printer
);
4579 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4581 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
,
4584 if (need_history
&& printer
->num_history
> 0)
4586 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4587 "printer-state-history",
4588 printer
->num_history
, NULL
);
4590 for (i
= 0; i
< printer
->num_history
; i
++)
4591 copy_attrs(history
->values
[i
].collection
= ippNew(),
4592 printer
->history
[i
], NULL
, IPP_TAG_ZERO
, 0);
4596 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4601 * 'get_subscription_attrs()' - Get subscription attributes.
4605 get_subscription_attrs(client_t
*con
, /* I - Client connection */
4606 int sub_id
) /* I - Subscription ID */
4612 * 'get_subscriptions()' - Get subscriptions.
4616 get_subscriptions(client_t
*con
, /* I - Client connection */
4617 ipp_attribute_t
*uri
) /* I - Printer URI */
4623 * 'hold_job()' - Hold a print job.
4627 hold_job(client_t
*con
, /* I - Client connection */
4628 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4630 ipp_attribute_t
*attr
, /* Current job-hold-until */
4631 *newattr
; /* New job-hold-until */
4632 int jobid
; /* Job ID */
4633 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4634 username
[HTTP_MAX_URI
], /* Username portion of URI */
4635 host
[HTTP_MAX_URI
], /* Host portion of URI */
4636 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4637 int port
; /* Port portion of URI */
4638 job_t
*job
; /* Job information */
4641 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4642 uri
->values
[0].string
.text
);
4645 * Verify that the POST operation was done to a valid URI.
4648 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4649 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4650 strncmp(con
->uri
, "/printers/", 10) != 0)
4652 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
4654 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4659 * See if we have a job URI or a printer URI...
4662 if (strcmp(uri
->name
, "printer-uri") == 0)
4665 * Got a printer URI; see if we also have a job-id attribute...
4668 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4670 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
4671 send_ipp_error(con
, IPP_BAD_REQUEST
);
4675 jobid
= attr
->values
[0].integer
;
4680 * Got a job URI; parse it to get the job ID...
4683 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4685 if (strncmp(resource
, "/jobs/", 6) != 0)
4691 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
4692 uri
->values
[0].string
.text
);
4693 send_ipp_error(con
, IPP_BAD_REQUEST
);
4697 jobid
= atoi(resource
+ 6);
4701 * See if the job exists...
4704 if ((job
= FindJob(jobid
)) == NULL
)
4707 * Nope - return a "not found" error...
4710 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
4711 send_ipp_error(con
, IPP_NOT_FOUND
);
4716 * See if the job is owned by the requesting user...
4719 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4721 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
4722 username
, jobid
, job
->username
);
4723 send_ipp_error(con
, IPP_FORBIDDEN
);
4728 * Hold the job and return...
4733 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4734 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
4736 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4737 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4742 * Free the old hold value and copy the new one over...
4745 free(attr
->values
[0].string
.text
);
4747 if (newattr
!= NULL
)
4749 attr
->value_tag
= newattr
->value_tag
;
4750 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
4754 attr
->value_tag
= IPP_TAG_KEYWORD
;
4755 attr
->values
[0].string
.text
= strdup("indefinite");
4759 * Hold job until specified time...
4762 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4765 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
4767 con
->response
->request
.status
.status_code
= IPP_OK
;
4772 * 'move_job()' - Move a job to a new destination.
4776 move_job(client_t
*con
, /* I - Client connection */
4777 ipp_attribute_t
*uri
) /* I - Job URI */
4779 ipp_attribute_t
*attr
; /* Current attribute */
4780 int jobid
; /* Job ID */
4781 job_t
*job
; /* Current job */
4782 const char *dest
; /* Destination */
4783 cups_ptype_t dtype
; /* Destination type (printer or class) */
4784 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4785 username
[HTTP_MAX_URI
], /* Username portion of URI */
4786 host
[HTTP_MAX_URI
], /* Host portion of URI */
4787 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4788 int port
; /* Port portion of URI */
4789 printer_t
*printer
; /* Printer */
4792 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4793 uri
->values
[0].string
.text
);
4796 * See if we have a job URI or a printer URI...
4799 if (strcmp(uri
->name
, "printer-uri") == 0)
4802 * Got a printer URI; see if we also have a job-id attribute...
4805 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4807 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
4808 send_ipp_error(con
, IPP_BAD_REQUEST
);
4812 jobid
= attr
->values
[0].integer
;
4817 * Got a job URI; parse it to get the job ID...
4820 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4822 if (strncmp(resource
, "/jobs/", 6) != 0)
4828 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
4829 uri
->values
[0].string
.text
);
4830 send_ipp_error(con
, IPP_BAD_REQUEST
);
4834 jobid
= atoi(resource
+ 6);
4838 * See if the job exists...
4841 if ((job
= FindJob(jobid
)) == NULL
)
4844 * Nope - return a "not found" error...
4847 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
4848 send_ipp_error(con
, IPP_NOT_FOUND
);
4853 * See if the job has been completed...
4856 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4859 * Return a "not-possible" error...
4862 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
4863 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4868 * See if the job is owned by the requesting user...
4871 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4873 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
4874 username
, jobid
, job
->username
);
4875 send_ipp_error(con
, IPP_FORBIDDEN
);
4879 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
4882 * Need job-printer-uri...
4885 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
4886 send_ipp_error(con
, IPP_BAD_REQUEST
);
4891 * Get the new printer or class...
4894 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
4896 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4902 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
4903 send_ipp_error(con
, IPP_NOT_FOUND
);
4911 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4913 LogMessage(L_ERROR
, "move_job: not authorized!");
4914 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4919 * Move the job to a different printer or class...
4922 MoveJob(jobid
, dest
);
4925 * Start jobs if possible...
4931 * Return with "everything is OK" status...
4934 con
->response
->request
.status
.status_code
= IPP_OK
;
4939 * 'ppd_add_default()' - Add a PPD default choice.
4942 static int /* O - Number of defaults */
4944 const char *option
, /* I - Option name */
4945 const char *choice
, /* I - Choice name */
4946 int num_defaults
, /* I - Number of defaults */
4947 ppd_default_t
**defaults
) /* IO - Defaults */
4949 int i
; /* Looping var */
4950 ppd_default_t
*temp
; /* Temporary defaults array */
4954 * First check if the option already has a default value; the PPD spec
4955 * says that the first one is used...
4958 for (i
= 0, temp
= *defaults
; i
< num_defaults
; i
++)
4959 if (!strcmp(option
, temp
[i
].option
))
4960 return (num_defaults
);
4963 * Now add the option...
4966 if (num_defaults
== 0)
4967 temp
= malloc(sizeof(ppd_default_t
));
4969 temp
= realloc(*defaults
, (num_defaults
+ 1) * sizeof(ppd_default_t
));
4973 LogMessage(L_ERROR
, "ppd_add_default: Unable to add default value for \"%s\" - %s",
4974 option
, strerror(errno
));
4975 return (num_defaults
);
4979 temp
+= num_defaults
;
4981 strlcpy(temp
->option
, option
, sizeof(temp
->option
));
4982 strlcpy(temp
->choice
, choice
, sizeof(temp
->choice
));
4984 return (num_defaults
+ 1);
4989 * 'ppd_parse_line()' - Parse a PPD default line.
4992 static int /* O - 0 on success, -1 on failure */
4993 ppd_parse_line(const char *line
, /* I - Line */
4994 char *option
, /* O - Option name */
4995 int olen
, /* I - Size of option name */
4996 char *choice
, /* O - Choice name */
4997 int clen
) /* I - Size of choice name */
5000 * Verify this is a default option line...
5003 if (strncmp(line
, "*Default", 8))
5007 * Read the option name...
5010 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
5020 * Skip everything else up to the colon (:)...
5023 while (*line
&& *line
!= ':')
5032 * Now grab the option choice, skipping leading whitespace...
5035 while (isspace(*line
& 255))
5038 for (clen
--; isalnum(*line
& 255); line
++)
5048 * Return with no errors...
5056 * 'print_job()' - Print a file to a printer or class.
5060 print_job(client_t
*con
, /* I - Client connection */
5061 ipp_attribute_t
*uri
) /* I - Printer URI */
5063 ipp_attribute_t
*attr
; /* Current attribute */
5064 ipp_attribute_t
*format
; /* Document-format attribute */
5065 const char *dest
; /* Destination */
5066 cups_ptype_t dtype
; /* Destination type (printer or class) */
5067 int priority
; /* Job priority */
5068 char *title
; /* Job name/title */
5069 job_t
*job
; /* Current job */
5070 int jobid
; /* Job ID number */
5071 char job_uri
[HTTP_MAX_URI
], /* Job URI */
5072 method
[HTTP_MAX_URI
], /* Method portion of URI */
5073 username
[HTTP_MAX_URI
], /* Username portion of URI */
5074 host
[HTTP_MAX_URI
], /* Host portion of URI */
5075 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5076 filename
[1024]; /* Job filename */
5077 int port
; /* Port portion of URI */
5078 mime_type_t
*filetype
; /* Type of file */
5079 char super
[MIME_MAX_SUPER
], /* Supertype of file */
5080 type
[MIME_MAX_TYPE
], /* Subtype of file */
5081 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
5082 /* Textual name of mime type */
5083 printer_t
*printer
; /* Printer data */
5084 struct stat fileinfo
; /* File information */
5085 int kbytes
; /* Size of file */
5086 int i
; /* Looping var */
5087 int lowerpagerange
; /* Page range bound */
5088 int compression
; /* Document compression */
5091 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5092 uri
->values
[0].string
.text
);
5095 * Verify that the POST operation was done to a valid URI.
5098 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5099 strncmp(con
->uri
, "/printers/", 10) != 0)
5101 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
5103 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5108 * Validate job template attributes; for now just copies and page-ranges...
5111 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
5113 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
5115 LogMessage(L_INFO
, "print_job: bad copies value %d.",
5116 attr
->values
[0].integer
);
5117 send_ipp_error(con
, IPP_BAD_REQUEST
);
5122 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
5124 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
5126 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
5127 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5129 LogMessage(L_ERROR
, "print_job: bad page-ranges values %d-%d.",
5130 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
5131 send_ipp_error(con
, IPP_BAD_REQUEST
);
5135 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
5140 * OK, see if the client is sending the document compressed - CUPS
5141 * only supports "none" and "gzip".
5144 compression
= CUPS_FILE_NONE
;
5146 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
5148 if (strcmp(attr
->values
[0].string
.text
, "none")
5150 && strcmp(attr
->values
[0].string
.text
, "gzip")
5151 #endif /* HAVE_LIBZ */
5154 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
5155 attr
->values
[0].string
.text
);
5156 send_ipp_error(con
, IPP_ATTRIBUTES
);
5157 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5158 "compression", NULL
, attr
->values
[0].string
.text
);
5163 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
5164 compression
= CUPS_FILE_GZIP
;
5165 #endif /* HAVE_LIBZ */
5169 * Do we have a file to print?
5174 LogMessage(L_ERROR
, "print_job: No file!?!");
5175 send_ipp_error(con
, IPP_BAD_REQUEST
);
5180 * Is it a format we support?
5183 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5186 * Grab format from client...
5189 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5191 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
5192 format
->values
[0].string
.text
);
5193 send_ipp_error(con
, IPP_BAD_REQUEST
);
5200 * No document format attribute? Auto-type it!
5203 strcpy(super
, "application");
5204 strcpy(type
, "octet-stream");
5207 if (strcmp(super
, "application") == 0 &&
5208 strcmp(type
, "octet-stream") == 0)
5211 * Auto-type the file...
5214 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
5216 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
5218 if (filetype
!= NULL
)
5221 * Replace the document-format attribute value with the auto-typed one.
5224 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
5229 free(format
->values
[0].string
.text
);
5230 format
->values
[0].string
.text
= strdup(mimetype
);
5233 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
5234 "document-format", NULL
, mimetype
);
5237 filetype
= mimeType(MimeDatabase
, super
, type
);
5240 filetype
= mimeType(MimeDatabase
, super
, type
);
5242 if (filetype
== NULL
)
5244 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
5246 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
5247 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5250 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5251 "document-format", NULL
, format
->values
[0].string
.text
);
5256 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
5257 filetype
->super
, filetype
->type
);
5260 * Read any embedded job ticket info from PS files...
5263 if (strcasecmp(filetype
->super
, "application") == 0 &&
5264 strcasecmp(filetype
->type
, "postscript") == 0)
5265 read_ps_job_ticket(con
);
5268 * Is the destination valid?
5271 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5273 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5279 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
5280 send_ipp_error(con
, IPP_NOT_FOUND
);
5288 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5290 LogMessage(L_ERROR
, "print_job: not authorized!");
5291 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5296 * See if the printer is accepting jobs...
5299 if (!printer
->accepting
)
5301 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
5303 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
5308 * Make sure we aren't over our limit...
5311 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5314 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5316 LogMessage(L_INFO
, "print_job: too many jobs - %d jobs, max jobs is %d.",
5318 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5322 if (!check_quotas(con
, printer
))
5324 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5329 * Create the job and set things up...
5332 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
5333 priority
= attr
->values
[0].integer
;
5335 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
5338 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
5339 title
= attr
->values
[0].string
.text
;
5341 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5342 title
= "Untitled");
5344 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
5346 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
5348 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
5353 job
->attrs
= con
->request
;
5354 con
->request
= NULL
;
5357 * Copy the rest of the job info...
5360 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
5362 if (con
->username
[0])
5363 SetString(&job
->username
, con
->username
);
5364 else if (attr
!= NULL
)
5366 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
5367 attr
->values
[0].string
.text
);
5369 SetString(&job
->username
, attr
->values
[0].string
.text
);
5372 SetString(&job
->username
, "anonymous");
5375 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
5376 NULL
, job
->username
);
5379 attr
->group_tag
= IPP_TAG_JOB
;
5380 SetString(&attr
->name
, "job-originating-user-name");
5384 * Add remaining job attributes...
5387 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
5388 IPP_TAG_ZERO
)) != NULL
)
5391 * Request contains a job-originating-host-name attribute; validate it...
5394 if (attr
->value_tag
!= IPP_TAG_NAME
||
5395 attr
->num_values
!= 1 ||
5396 strcmp(con
->http
.hostname
, "localhost") != 0)
5399 * Can't override the value if we aren't connected via localhost.
5400 * Also, we can only have 1 value and it must be a name value.
5403 switch (attr
->value_tag
)
5405 case IPP_TAG_STRING
:
5406 case IPP_TAG_TEXTLANG
:
5407 case IPP_TAG_NAMELANG
:
5410 case IPP_TAG_KEYWORD
:
5412 case IPP_TAG_URISCHEME
:
5413 case IPP_TAG_CHARSET
:
5414 case IPP_TAG_LANGUAGE
:
5415 case IPP_TAG_MIMETYPE
:
5417 * Free old strings...
5420 for (i
= 0; i
< attr
->num_values
; i
++)
5422 free(attr
->values
[i
].string
.text
);
5423 attr
->values
[i
].string
.text
= NULL
;
5424 if (attr
->values
[i
].string
.charset
)
5426 free(attr
->values
[i
].string
.charset
);
5427 attr
->values
[i
].string
.charset
= NULL
;
5436 * Use the default connection hostname instead...
5439 attr
->value_tag
= IPP_TAG_NAME
;
5440 attr
->num_values
= 1;
5441 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
5444 attr
->group_tag
= IPP_TAG_JOB
;
5449 * No job-originating-host-name attribute, so use the hostname from
5453 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
5454 "job-originating-host-name", NULL
, con
->http
.hostname
);
5457 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
5458 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
5459 "job-state", IPP_JOB_PENDING
);
5460 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5461 "job-media-sheets-completed", 0);
5462 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
5464 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5467 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
5468 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5471 if (stat(con
->filename
, &fileinfo
))
5474 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
5476 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5477 attr
->values
[0].integer
+= kbytes
;
5479 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
5481 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5482 "time-at-processing", 0);
5483 attr
->value_tag
= IPP_TAG_NOVALUE
;
5484 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5485 "time-at-completed", 0);
5486 attr
->value_tag
= IPP_TAG_NOVALUE
;
5488 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5489 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
5491 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
5492 "job-hold-until", NULL
, "no-hold");
5494 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
5495 !(printer
->type
& CUPS_PRINTER_REMOTE
))
5498 * Hold job until specified time...
5501 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
5502 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5505 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
5509 * Add job sheets options...
5512 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
5514 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
5515 printer
->job_sheets
[0], printer
->job_sheets
[1]);
5517 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
5519 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
5520 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
5523 job
->job_sheets
= attr
;
5526 * Enforce classification level if set...
5531 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
5532 Classification
? Classification
: "(null)", ClassifyOverride
);
5534 if (ClassifyOverride
)
5536 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
5537 (attr
->num_values
== 1 ||
5538 strcmp(attr
->values
[1].string
.text
, "none") == 0))
5541 * Force the leading banner to have the classification on it...
5544 SetString(&attr
->values
[0].string
.text
, Classification
);
5546 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5547 "job-sheets=\"%s,none\", "
5548 "job-originating-user-name=\"%s\"",
5549 job
->id
, Classification
,
5552 else if (attr
->num_values
== 2 &&
5553 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
5554 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
5555 strcmp(attr
->values
[1].string
.text
, "none") != 0)
5558 * Can't put two different security markings on the same document!
5561 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
5563 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5564 "job-sheets=\"%s,%s\", "
5565 "job-originating-user-name=\"%s\"",
5566 job
->id
, attr
->values
[0].string
.text
,
5567 attr
->values
[1].string
.text
,
5570 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
5571 strcmp(attr
->values
[0].string
.text
, "none") &&
5572 (attr
->num_values
== 1 ||
5573 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
5574 strcmp(attr
->values
[1].string
.text
, "none"))))
5576 if (attr
->num_values
== 1)
5577 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5578 "job-sheets=\"%s\", "
5579 "job-originating-user-name=\"%s\"",
5580 job
->id
, attr
->values
[0].string
.text
,
5583 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5584 "job-sheets=\"%s,%s\", "
5585 "job-originating-user-name=\"%s\"",
5586 job
->id
, attr
->values
[0].string
.text
,
5587 attr
->values
[1].string
.text
,
5591 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
5592 (attr
->num_values
== 1 ||
5593 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
5596 * Force the banner to have the classification on it...
5599 if (attr
->num_values
> 1 &&
5600 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
5602 SetString(&(attr
->values
[0].string
.text
), Classification
);
5603 SetString(&(attr
->values
[1].string
.text
), Classification
);
5607 if (attr
->num_values
== 1 ||
5608 strcmp(attr
->values
[0].string
.text
, "none"))
5609 SetString(&(attr
->values
[0].string
.text
), Classification
);
5611 if (attr
->num_values
> 1 &&
5612 strcmp(attr
->values
[1].string
.text
, "none"))
5613 SetString(&(attr
->values
[1].string
.text
), Classification
);
5616 if (attr
->num_values
> 1)
5617 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5618 "job-sheets=\"%s,%s\", "
5619 "job-originating-user-name=\"%s\"",
5620 job
->id
, attr
->values
[0].string
.text
,
5621 attr
->values
[1].string
.text
,
5624 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5625 "job-sheets=\"%s\", "
5626 "job-originating-user-name=\"%s\"",
5627 job
->id
, Classification
,
5633 * Add the starting sheet...
5636 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
5638 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
5639 attr
->values
[0].string
.text
, job
->id
);
5641 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
5643 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5646 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
5650 * Add the job file...
5653 if (add_file(con
, job
, filetype
, compression
))
5656 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
5658 rename(con
->filename
, filename
);
5659 ClearString(&con
->filename
);
5662 * See if we need to add the ending sheet...
5665 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
5666 attr
->num_values
> 1)
5672 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
5673 attr
->values
[1].string
.text
, job
->id
);
5675 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
5677 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5681 * Add any job subscriptions...
5684 add_job_subscriptions(con
, job
);
5687 * Set all but the first two attributes to the job attributes group...
5690 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
5691 attr
->group_tag
= IPP_TAG_JOB
;
5694 * Log and save the job...
5697 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
5698 job
->dest
, job
->username
);
5699 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, (int)job
->hold_until
);
5703 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
5706 * Start the job if possible... Since CheckJobs() can cancel a job if it
5707 * doesn't print, we need to re-find the job afterwards...
5714 job
= FindJob(jobid
);
5717 * Fill in the response info...
5720 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
5723 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
5725 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
5727 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
5728 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
5729 add_job_state_reasons(con
, job
);
5731 con
->response
->request
.status
.status_code
= IPP_OK
;
5736 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
5738 * This function only gets called when printing a single PostScript
5739 * file using the Print-Job operation. It doesn't work for Create-Job +
5740 * Send-File, since the job attributes need to be set at job creation
5741 * time for banners to work. The embedded PS job ticket stuff is here
5742 * only to allow the Windows printer driver for CUPS to pass in JCL
5743 * options and IPP attributes which otherwise would be lost.
5745 * The format of a PS job ticket is simple:
5747 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
5749 * %cupsJobTicket: attr1=value1
5750 * %cupsJobTicket: attr2=value2
5752 * %cupsJobTicket: attrN=valueN
5754 * Job ticket lines must appear immediately after the first line that
5755 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
5756 * looking for job ticket info when it finds a line that does not begin
5757 * with "%cupsJobTicket:".
5759 * The maximum length of a job ticket line, including the prefix, is
5760 * 255 characters to conform with the Adobe DSC.
5762 * Read-only attributes are rejected with a notice to the error log in
5763 * case a malicious user tries anything. Since the job ticket is read
5764 * prior to attribute validation in print_job(), job ticket attributes
5765 * will go through the same validation as IPP attributes...
5769 read_ps_job_ticket(client_t
*con
) /* I - Client connection */
5771 cups_file_t
*fp
; /* File to read from */
5772 char line
[256]; /* Line data */
5773 int num_options
; /* Number of options */
5774 cups_option_t
*options
; /* Options */
5775 ipp_t
*ticket
; /* New attributes */
5776 ipp_attribute_t
*attr
, /* Current attribute */
5777 *attr2
, /* Job attribute */
5778 *prev2
; /* Previous job attribute */
5782 * First open the print file...
5785 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
5787 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to open PostScript print file - %s",
5793 * Skip the first line...
5796 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
5798 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to read from PostScript print file - %s",
5804 if (strncmp(line
, "%!PS-Adobe-", 11) != 0)
5807 * Not a DSC-compliant file, so no job ticket info will be available...
5815 * Read job ticket info from the file...
5821 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
5824 * Stop at the first non-ticket line...
5827 if (strncmp(line
, "%cupsJobTicket:", 15) != 0)
5831 * Add the options to the option array...
5834 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
5838 * Done with the file; see if we have any options...
5843 if (num_options
== 0)
5847 * OK, convert the options to an attribute list, and apply them to
5852 cupsEncodeOptions(ticket
, num_options
, options
);
5855 * See what the user wants to change.
5858 for (attr
= ticket
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5860 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
5863 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
5864 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
5865 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
5866 strcmp(attr
->name
, "job-k-octets") == 0 ||
5867 strcmp(attr
->name
, "job-id") == 0 ||
5868 strncmp(attr
->name
, "job-state", 9) == 0 ||
5869 strncmp(attr
->name
, "time-at-", 8) == 0)
5870 continue; /* Read-only attrs */
5872 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
5875 * Some other value; first free the old value...
5878 if (con
->request
->attrs
== attr2
)
5880 con
->request
->attrs
= attr2
->next
;
5885 for (prev2
= con
->request
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
5886 if (prev2
->next
== attr2
)
5888 prev2
->next
= attr2
->next
;
5893 if (con
->request
->last
== attr2
)
5894 con
->request
->last
= prev2
;
5896 _ipp_free_attr(attr2
);
5900 * Add new option by copying it...
5903 copy_attribute(con
->request
, attr
, 0);
5907 * Then free the attribute list and option array...
5911 cupsFreeOptions(num_options
, options
);
5916 * 'reject_jobs()' - Reject print jobs to a printer.
5920 reject_jobs(client_t
*con
, /* I - Client connection */
5921 ipp_attribute_t
*uri
) /* I - Printer or class URI */
5923 cups_ptype_t dtype
; /* Destination type (printer or class) */
5924 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5925 username
[HTTP_MAX_URI
], /* Username portion of URI */
5926 host
[HTTP_MAX_URI
], /* Host portion of URI */
5927 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5928 int port
; /* Port portion of URI */
5929 const char *name
; /* Printer name */
5930 printer_t
*printer
; /* Printer data */
5931 ipp_attribute_t
*attr
; /* printer-state-message text */
5934 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
5935 uri
->values
[0].string
.text
);
5938 * Was this operation called from the correct URI?
5941 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5943 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
5945 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5950 * Is the destination valid?
5953 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5955 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5961 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
5962 send_ipp_error(con
, IPP_NOT_FOUND
);
5970 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5972 LogMessage(L_ERROR
, "reject_jobs: not authorized!");
5973 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5978 * Reject jobs sent to the printer...
5981 printer
->accepting
= 0;
5983 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
5984 IPP_TAG_TEXT
)) == NULL
)
5985 strcpy(printer
->state_message
, "Rejecting Jobs");
5987 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
5988 sizeof(printer
->state_message
));
5990 AddPrinterHistory(printer
);
5992 if (dtype
& CUPS_PRINTER_CLASS
)
5996 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
6003 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
6008 * Everything was ok, so return OK status...
6011 con
->response
->request
.status
.status_code
= IPP_OK
;
6016 * 'release_job()' - Release a held print job.
6020 release_job(client_t
*con
, /* I - Client connection */
6021 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6023 ipp_attribute_t
*attr
; /* Current attribute */
6024 int jobid
; /* Job ID */
6025 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6026 username
[HTTP_MAX_URI
], /* Username portion of URI */
6027 host
[HTTP_MAX_URI
], /* Host portion of URI */
6028 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6029 int port
; /* Port portion of URI */
6030 job_t
*job
; /* Job information */
6033 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6034 uri
->values
[0].string
.text
);
6037 * Verify that the POST operation was done to a valid URI.
6040 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6041 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6042 strncmp(con
->uri
, "/printers/", 10) != 0)
6044 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
6046 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6051 * See if we have a job URI or a printer URI...
6054 if (strcmp(uri
->name
, "printer-uri") == 0)
6057 * Got a printer URI; see if we also have a job-id attribute...
6060 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6062 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
6063 send_ipp_error(con
, IPP_BAD_REQUEST
);
6067 jobid
= attr
->values
[0].integer
;
6072 * Got a job URI; parse it to get the job ID...
6075 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6077 if (strncmp(resource
, "/jobs/", 6) != 0)
6083 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
6084 uri
->values
[0].string
.text
);
6085 send_ipp_error(con
, IPP_BAD_REQUEST
);
6089 jobid
= atoi(resource
+ 6);
6093 * See if the job exists...
6096 if ((job
= FindJob(jobid
)) == NULL
)
6099 * Nope - return a "not found" error...
6102 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
6103 send_ipp_error(con
, IPP_NOT_FOUND
);
6108 * See if job is "held"...
6111 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
6114 * Nope - return a "not possible" error...
6117 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
6118 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6123 * See if the job is owned by the requesting user...
6126 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6128 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
6129 username
, jobid
, job
->username
);
6130 send_ipp_error(con
, IPP_FORBIDDEN
);
6135 * Reset the job-hold-until value to "no-hold"...
6138 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6139 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6143 free(attr
->values
[0].string
.text
);
6144 attr
->value_tag
= IPP_TAG_KEYWORD
;
6145 attr
->values
[0].string
.text
= strdup("no-hold");
6149 * Release the job and return...
6154 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
6156 con
->response
->request
.status
.status_code
= IPP_OK
;
6161 * 'renew_subscription()' - Renew an existing subscription...
6165 renew_subscription(client_t
*con
, /* I - Client connection */
6166 int sub_id
) /* I - Subscription ID */
6172 * 'restart_job()' - Restart an old print job.
6176 restart_job(client_t
*con
, /* I - Client connection */
6177 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6179 ipp_attribute_t
*attr
; /* Current attribute */
6180 int jobid
; /* Job ID */
6181 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6182 username
[HTTP_MAX_URI
], /* Username portion of URI */
6183 host
[HTTP_MAX_URI
], /* Host portion of URI */
6184 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6185 int port
; /* Port portion of URI */
6186 job_t
*job
; /* Job information */
6189 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6190 uri
->values
[0].string
.text
);
6193 * Verify that the POST operation was done to a valid URI.
6196 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6197 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6198 strncmp(con
->uri
, "/printers/", 10) != 0)
6200 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
6202 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6207 * See if we have a job URI or a printer URI...
6210 if (strcmp(uri
->name
, "printer-uri") == 0)
6213 * Got a printer URI; see if we also have a job-id attribute...
6216 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6218 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
6219 send_ipp_error(con
, IPP_BAD_REQUEST
);
6223 jobid
= attr
->values
[0].integer
;
6228 * Got a job URI; parse it to get the job ID...
6231 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6233 if (strncmp(resource
, "/jobs/", 6) != 0)
6239 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
6240 uri
->values
[0].string
.text
);
6241 send_ipp_error(con
, IPP_BAD_REQUEST
);
6245 jobid
= atoi(resource
+ 6);
6249 * See if the job exists...
6252 if ((job
= FindJob(jobid
)) == NULL
)
6255 * Nope - return a "not found" error...
6258 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
6259 send_ipp_error(con
, IPP_NOT_FOUND
);
6264 * See if job is in any of the "completed" states...
6267 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
6270 * Nope - return a "not possible" error...
6273 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
6274 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6279 * See if we have retained the job files...
6282 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6285 * Nope - return a "not possible" error...
6288 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
6289 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6294 * See if the job is owned by the requesting user...
6297 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6299 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
6300 username
, jobid
, job
->username
);
6301 send_ipp_error(con
, IPP_FORBIDDEN
);
6306 * Restart the job and return...
6311 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
6313 con
->response
->request
.status
.status_code
= IPP_OK
;
6318 * 'send_document()' - Send a file to a printer or class.
6322 send_document(client_t
*con
, /* I - Client connection */
6323 ipp_attribute_t
*uri
) /* I - Printer URI */
6325 ipp_attribute_t
*attr
; /* Current attribute */
6326 ipp_attribute_t
*format
; /* Document-format attribute */
6327 int jobid
; /* Job ID number */
6328 job_t
*job
; /* Current job */
6329 char job_uri
[HTTP_MAX_URI
],
6331 method
[HTTP_MAX_URI
],
6332 /* Method portion of URI */
6333 username
[HTTP_MAX_URI
],
6334 /* Username portion of URI */
6336 /* Host portion of URI */
6337 resource
[HTTP_MAX_URI
];
6338 /* Resource portion of URI */
6339 int port
; /* Port portion of URI */
6340 mime_type_t
*filetype
; /* Type of file */
6341 char super
[MIME_MAX_SUPER
],
6342 /* Supertype of file */
6343 type
[MIME_MAX_TYPE
],
6344 /* Subtype of file */
6345 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
6346 /* Textual name of mime type */
6347 char filename
[1024]; /* Job filename */
6348 printer_t
*printer
; /* Current printer */
6349 struct stat fileinfo
; /* File information */
6350 int kbytes
; /* Size of file */
6351 int compression
; /* Type of compression */
6354 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
6355 uri
->values
[0].string
.text
);
6358 * Verify that the POST operation was done to a valid URI.
6361 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6362 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
6363 strncmp(con
->uri
, "/printers/", 10) != 0)
6365 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
6367 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6372 * See if we have a job URI or a printer URI...
6375 if (strcmp(uri
->name
, "printer-uri") == 0)
6378 * Got a printer URI; see if we also have a job-id attribute...
6381 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6383 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
6384 send_ipp_error(con
, IPP_BAD_REQUEST
);
6388 jobid
= attr
->values
[0].integer
;
6393 * Got a job URI; parse it to get the job ID...
6396 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6398 if (strncmp(resource
, "/jobs/", 6) != 0)
6404 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
6405 uri
->values
[0].string
.text
);
6406 send_ipp_error(con
, IPP_BAD_REQUEST
);
6410 jobid
= atoi(resource
+ 6);
6414 * See if the job exists...
6417 if ((job
= FindJob(jobid
)) == NULL
)
6420 * Nope - return a "not found" error...
6423 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
6424 send_ipp_error(con
, IPP_NOT_FOUND
);
6429 * See if the job is owned by the requesting user...
6432 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6434 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
6435 username
, jobid
, job
->username
);
6436 send_ipp_error(con
, IPP_FORBIDDEN
);
6441 * OK, see if the client is sending the document compressed - CUPS
6442 * only supports "none" and "gzip".
6445 compression
= CUPS_FILE_NONE
;
6447 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
6449 if (strcmp(attr
->values
[0].string
.text
, "none")
6451 && strcmp(attr
->values
[0].string
.text
, "gzip")
6452 #endif /* HAVE_LIBZ */
6455 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
6456 attr
->values
[0].string
.text
);
6457 send_ipp_error(con
, IPP_ATTRIBUTES
);
6458 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
6459 "compression", NULL
, attr
->values
[0].string
.text
);
6464 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
6465 compression
= CUPS_FILE_GZIP
;
6466 #endif /* HAVE_LIBZ */
6470 * Do we have a file to print?
6475 LogMessage(L_ERROR
, "send_document: No file!?!");
6476 send_ipp_error(con
, IPP_BAD_REQUEST
);
6481 * Is it a format we support?
6484 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
6487 * Grab format from client...
6490 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
6492 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
6493 format
->values
[0].string
.text
);
6494 send_ipp_error(con
, IPP_BAD_REQUEST
);
6501 * No document format attribute? Auto-type it!
6504 strcpy(super
, "application");
6505 strcpy(type
, "octet-stream");
6508 if (strcmp(super
, "application") == 0 &&
6509 strcmp(type
, "octet-stream") == 0)
6512 * Auto-type the file...
6515 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
6517 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
6519 if (filetype
!= NULL
)
6522 * Replace the document-format attribute value with the auto-typed one.
6525 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
6530 free(format
->values
[0].string
.text
);
6531 format
->values
[0].string
.text
= strdup(mimetype
);
6534 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
6535 "document-format", NULL
, mimetype
);
6538 filetype
= mimeType(MimeDatabase
, super
, type
);
6541 filetype
= mimeType(MimeDatabase
, super
, type
);
6543 if (filetype
== NULL
)
6545 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
6547 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
6548 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
6551 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
6552 "document-format", NULL
, format
->values
[0].string
.text
);
6557 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
6558 filetype
->super
, filetype
->type
);
6561 * Add the file to the job...
6564 if (add_file(con
, job
, filetype
, compression
))
6567 if (job
->dtype
& CUPS_PRINTER_CLASS
)
6568 printer
= FindClass(job
->dest
);
6570 printer
= FindPrinter(job
->dest
);
6572 if (stat(con
->filename
, &fileinfo
))
6575 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6577 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6579 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
6580 attr
->values
[0].integer
+= kbytes
;
6582 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6584 rename(con
->filename
, filename
);
6586 ClearString(&con
->filename
);
6588 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
6589 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
6592 * Start the job if this is the last document...
6595 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
6596 attr
->values
[0].boolean
)
6599 * See if we need to add the ending sheet...
6602 if (printer
!= NULL
&&
6603 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6604 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
6605 attr
->num_values
> 1)
6611 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
6612 attr
->values
[1].string
.text
, job
->id
);
6614 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6616 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6619 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
6620 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6621 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
6623 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6624 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6626 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6627 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6633 * Start the job if possible... Since CheckJobs() can cancel a job if it
6634 * doesn't print, we need to re-find the job afterwards...
6641 job
= FindJob(jobid
);
6645 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6646 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6648 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6650 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
6651 job
->hold_until
= time(NULL
) + 60;
6657 * Fill in the response info...
6660 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
6663 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
6666 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
6668 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
6669 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
6670 add_job_state_reasons(con
, job
);
6672 con
->response
->request
.status
.status_code
= IPP_OK
;
6677 * 'send_ipp_error()' - Send an error status back to the IPP client.
6681 send_ipp_error(client_t
*con
, /* I - Client connection */
6682 ipp_status_t status
) /* I - IPP status code */
6684 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
6687 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
6689 con
->response
->request
.status
.status_code
= status
;
6691 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
6692 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
6693 "attributes-charset", NULL
, DefaultCharset
);
6695 if (ippFindAttribute(con
->response
, "attributes-natural-language",
6696 IPP_TAG_ZERO
) == NULL
)
6697 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
6698 "attributes-natural-language", NULL
, DefaultLanguage
);
6703 * 'set_default()' - Set the default destination...
6707 set_default(client_t
*con
, /* I - Client connection */
6708 ipp_attribute_t
*uri
) /* I - Printer URI */
6710 cups_ptype_t dtype
; /* Destination type (printer or class) */
6711 char method
[HTTP_MAX_URI
],
6712 /* Method portion of URI */
6713 username
[HTTP_MAX_URI
],
6714 /* Username portion of URI */
6716 /* Host portion of URI */
6717 resource
[HTTP_MAX_URI
];
6718 /* Resource portion of URI */
6719 int port
; /* Port portion of URI */
6720 const char *name
; /* Printer name */
6721 printer_t
*printer
; /* Printer */
6724 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
6725 uri
->values
[0].string
.text
);
6728 * Was this operation called from the correct URI?
6731 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6733 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
6735 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6740 * Is the destination valid?
6743 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6745 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6751 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
6752 send_ipp_error(con
, IPP_NOT_FOUND
);
6760 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
6762 LogMessage(L_ERROR
, "set_default: not authorized!");
6763 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6768 * Set it as the default...
6771 DefaultPrinter
= printer
;
6776 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
6780 * Everything was ok, so return OK status...
6783 con
->response
->request
.status
.status_code
= IPP_OK
;
6788 * 'set_job_attrs()' - Set job attributes.
6792 set_job_attrs(client_t
*con
, /* I - Client connection */
6793 ipp_attribute_t
*uri
) /* I - Job URI */
6795 ipp_attribute_t
*attr
, /* Current attribute */
6796 *attr2
, /* Job attribute */
6797 *prev2
; /* Previous job attribute */
6798 int jobid
; /* Job ID */
6799 job_t
*job
; /* Current job */
6800 char method
[HTTP_MAX_URI
],
6801 /* Method portion of URI */
6802 username
[HTTP_MAX_URI
],
6803 /* Username portion of URI */
6805 /* Host portion of URI */
6806 resource
[HTTP_MAX_URI
];
6807 /* Resource portion of URI */
6808 int port
; /* Port portion of URI */
6811 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
6812 uri
->values
[0].string
.text
);
6815 * Start with "everything is OK" status...
6818 con
->response
->request
.status
.status_code
= IPP_OK
;
6821 * See if we have a job URI or a printer URI...
6824 if (strcmp(uri
->name
, "printer-uri") == 0)
6827 * Got a printer URI; see if we also have a job-id attribute...
6830 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6832 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
6833 send_ipp_error(con
, IPP_BAD_REQUEST
);
6837 jobid
= attr
->values
[0].integer
;
6842 * Got a job URI; parse it to get the job ID...
6845 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6847 if (strncmp(resource
, "/jobs/", 6) != 0)
6853 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
6854 uri
->values
[0].string
.text
);
6855 send_ipp_error(con
, IPP_BAD_REQUEST
);
6859 jobid
= atoi(resource
+ 6);
6863 * See if the job exists...
6866 if ((job
= FindJob(jobid
)) == NULL
)
6869 * Nope - return a "not found" error...
6872 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
6873 send_ipp_error(con
, IPP_NOT_FOUND
);
6878 * See if the job has been completed...
6881 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6884 * Return a "not-possible" error...
6887 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
6888 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6893 * See if the job is owned by the requesting user...
6896 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6898 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
6899 username
, jobid
, job
->username
);
6900 send_ipp_error(con
, IPP_FORBIDDEN
);
6905 * See what the user wants to change.
6908 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6910 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6913 if (!strcmp(attr
->name
, "attributes-charset") ||
6914 !strcmp(attr
->name
, "attributes-natural-language") ||
6915 !strcmp(attr
->name
, "document-compression") ||
6916 !strcmp(attr
->name
, "document-format") ||
6917 !strcmp(attr
->name
, "job-detailed-status-messages") ||
6918 !strcmp(attr
->name
, "job-document-access-errors") ||
6919 !strcmp(attr
->name
, "job-id") ||
6920 !strcmp(attr
->name
, "job-k-octets") ||
6921 !strcmp(attr
->name
, "job-originating-host-name") ||
6922 !strcmp(attr
->name
, "job-originating-user-name") ||
6923 !strcmp(attr
->name
, "job-printer-up-time") ||
6924 !strcmp(attr
->name
, "job-printer-uri") ||
6925 !strcmp(attr
->name
, "job-sheets") ||
6926 !strcmp(attr
->name
, "job-state-message") ||
6927 !strcmp(attr
->name
, "job-state-reasons") ||
6928 !strcmp(attr
->name
, "job-uri") ||
6929 !strcmp(attr
->name
, "number-of-documents") ||
6930 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
6931 !strcmp(attr
->name
, "output-device-assigned") ||
6932 !strncmp(attr
->name
, "date-time-at-", 13) ||
6933 !strncmp(attr
->name
, "job-impressions", 15) ||
6934 !strncmp(attr
->name
, "job-k-octets", 12) ||
6935 !strncmp(attr
->name
, "job-media-sheets", 16) ||
6936 !strncmp(attr
->name
, "time-at-", 8))
6942 send_ipp_error(con
, IPP_ATTRIBUTES_NOT_SETTABLE
);
6944 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6945 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6950 if (!strcmp(attr
->name
, "job-priority"))
6953 * Change the job priority...
6956 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
6958 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6960 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6961 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6963 else if (job
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
6965 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6968 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6969 SetJobPriority(jobid
, attr
->values
[0].integer
);
6971 else if (!strcmp(attr
->name
, "job-state"))
6974 * Change the job state...
6977 if (attr
->value_tag
!= IPP_TAG_ENUM
)
6979 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6981 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6982 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6986 switch (attr
->values
[0].integer
)
6988 case IPP_JOB_PENDING
:
6990 if (job
->state
->values
[0].integer
> IPP_JOB_HELD
)
6992 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6995 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6996 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
6999 case IPP_JOB_PROCESSING
:
7000 case IPP_JOB_STOPPED
:
7001 if (job
->state
->values
[0].integer
!= attr
->values
[0].integer
)
7003 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7008 case IPP_JOB_CANCELLED
:
7009 case IPP_JOB_ABORTED
:
7010 case IPP_JOB_COMPLETED
:
7011 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
)
7013 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7016 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7018 CancelJob(job
->id
, 0);
7022 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7030 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
7032 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
7035 * Some other value; first free the old value...
7038 if (job
->attrs
->attrs
== attr2
)
7040 job
->attrs
->attrs
= attr2
->next
;
7045 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
7046 if (prev2
->next
== attr2
)
7048 prev2
->next
= attr2
->next
;
7053 if (job
->attrs
->last
== attr2
)
7054 job
->attrs
->last
= prev2
;
7056 _ipp_free_attr(attr2
);
7059 * Then copy the attribute...
7062 copy_attribute(job
->attrs
, attr
, 0);
7065 * See if the job-name or job-hold-until is being changed.
7068 if (strcmp(attr
->name
, "job-hold-until") == 0)
7070 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
7072 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7073 ReleaseJob(job
->id
);
7078 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
7081 * Delete the attribute...
7084 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
7086 prev2
= attr2
, attr2
= attr2
->next
)
7087 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
7093 prev2
->next
= attr2
->next
;
7095 job
->attrs
->attrs
= attr2
->next
;
7097 if (attr2
== job
->attrs
->last
)
7098 job
->attrs
->last
= prev2
;
7100 _ipp_free_attr(attr2
);
7106 * Add new option by copying it...
7109 copy_attribute(job
->attrs
, attr
, 0);
7120 * Start jobs if possible...
7128 * 'start_printer()' - Start a printer.
7132 start_printer(client_t
*con
, /* I - Client connection */
7133 ipp_attribute_t
*uri
) /* I - Printer URI */
7135 cups_ptype_t dtype
; /* Destination type (printer or class) */
7136 char method
[HTTP_MAX_URI
],
7137 /* Method portion of URI */
7138 username
[HTTP_MAX_URI
],
7139 /* Username portion of URI */
7141 /* Host portion of URI */
7142 resource
[HTTP_MAX_URI
];
7143 /* Resource portion of URI */
7144 int port
; /* Port portion of URI */
7145 const char *name
; /* Printer name */
7146 printer_t
*printer
; /* Printer data */
7149 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7150 uri
->values
[0].string
.text
);
7153 * Was this operation called from the correct URI?
7156 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7158 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
7160 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7165 * Is the destination valid?
7168 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7170 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7176 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
7177 send_ipp_error(con
, IPP_NOT_FOUND
);
7185 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7187 LogMessage(L_ERROR
, "start_printer: not authorized!");
7188 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7193 * Start the printer...
7196 printer
->state_message
[0] = '\0';
7198 StartPrinter(printer
, 1);
7200 if (dtype
& CUPS_PRINTER_CLASS
)
7201 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
7203 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
7209 * Everything was ok, so return OK status...
7212 con
->response
->request
.status
.status_code
= IPP_OK
;
7217 * 'stop_printer()' - Stop a printer.
7221 stop_printer(client_t
*con
, /* I - Client connection */
7222 ipp_attribute_t
*uri
) /* I - Printer URI */
7224 cups_ptype_t dtype
; /* Destination type (printer or class) */
7225 char method
[HTTP_MAX_URI
],
7226 /* Method portion of URI */
7227 username
[HTTP_MAX_URI
],
7228 /* Username portion of URI */
7230 /* Host portion of URI */
7231 resource
[HTTP_MAX_URI
];
7232 /* Resource portion of URI */
7233 int port
; /* Port portion of URI */
7234 const char *name
; /* Printer name */
7235 printer_t
*printer
; /* Printer data */
7236 ipp_attribute_t
*attr
; /* printer-state-message attribute */
7239 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7240 uri
->values
[0].string
.text
);
7243 * Was this operation called from the correct URI?
7246 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7248 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
7250 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7255 * Is the destination valid?
7258 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7260 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7266 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
7267 send_ipp_error(con
, IPP_NOT_FOUND
);
7275 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7277 LogMessage(L_ERROR
, "stop_printer: not authorized!");
7278 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7283 * Stop the printer...
7286 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
7287 IPP_TAG_TEXT
)) == NULL
)
7288 strcpy(printer
->state_message
, "Paused");
7291 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
7292 sizeof(printer
->state_message
));
7295 StopPrinter(printer
, 1);
7297 if (dtype
& CUPS_PRINTER_CLASS
)
7298 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
7301 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
7305 * Everything was ok, so return OK status...
7308 con
->response
->request
.status
.status_code
= IPP_OK
;
7313 * 'user_allowed()' - See if a user is allowed to print to a queue.
7316 static int /* O - 0 if not allowed, 1 if allowed */
7317 user_allowed(printer_t
*p
, /* I - Printer or class */
7318 const char *username
) /* I - Username */
7320 int i
, j
; /* Looping vars */
7321 struct passwd
*pw
; /* User password data */
7322 struct group
*grp
; /* Group data */
7325 if (p
->num_users
== 0)
7328 if (!strcmp(username
, "root"))
7331 pw
= getpwnam(username
);
7334 for (i
= 0; i
< p
->num_users
; i
++)
7336 if (p
->users
[i
][0] == '@')
7339 * Check group membership...
7342 grp
= getgrnam(p
->users
[i
] + 1);
7348 * Check primary group...
7351 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
7355 * Check usernames in group...
7358 for (j
= 0; grp
->gr_mem
[j
]; j
++)
7359 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
7366 else if (!strcasecmp(username
, p
->users
[i
]))
7370 return ((i
< p
->num_users
) != p
->deny_users
);
7375 * 'validate_job()' - Validate printer options and destination.
7379 validate_job(client_t
*con
, /* I - Client connection */
7380 ipp_attribute_t
*uri
) /* I - Printer URI */
7382 ipp_attribute_t
*attr
; /* Current attribute */
7383 ipp_attribute_t
*format
; /* Document-format attribute */
7384 cups_ptype_t dtype
; /* Destination type (printer or class) */
7385 char method
[HTTP_MAX_URI
],
7386 /* Method portion of URI */
7387 username
[HTTP_MAX_URI
],
7388 /* Username portion of URI */
7390 /* Host portion of URI */
7391 resource
[HTTP_MAX_URI
];
7392 /* Resource portion of URI */
7393 int port
; /* Port portion of URI */
7394 char super
[MIME_MAX_SUPER
],
7395 /* Supertype of file */
7396 type
[MIME_MAX_TYPE
];
7397 /* Subtype of file */
7398 printer_t
*printer
; /* Printer */
7401 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
7402 uri
->values
[0].string
.text
);
7405 * Verify that the POST operation was done to a valid URI.
7408 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
7409 strncmp(con
->uri
, "/printers/", 10) != 0)
7411 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
7413 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7418 * OK, see if the client is sending the document compressed - CUPS
7419 * doesn't support compression yet...
7422 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
7423 strcmp(attr
->values
[0].string
.text
, "none") == 0)
7425 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
7426 attr
->values
[0].string
.text
);
7427 send_ipp_error(con
, IPP_ATTRIBUTES
);
7428 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7429 "compression", NULL
, attr
->values
[0].string
.text
);
7434 * Is it a format we support?
7437 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
7439 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7441 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
7442 format
->values
[0].string
.text
);
7443 send_ipp_error(con
, IPP_BAD_REQUEST
);
7447 if ((strcmp(super
, "application") != 0 ||
7448 strcmp(type
, "octet-stream") != 0) &&
7449 mimeType(MimeDatabase
, super
, type
) == NULL
)
7451 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
7452 format
->values
[0].string
.text
);
7453 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
7454 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
7455 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7456 "document-format", NULL
, format
->values
[0].string
.text
);
7462 * Is the destination valid?
7465 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7467 if (ValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
7473 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
7474 send_ipp_error(con
, IPP_NOT_FOUND
);
7482 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7484 LogMessage(L_ERROR
, "validate_job: not authorized!");
7485 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7490 * Everything was ok, so return OK status...
7493 con
->response
->request
.status
.status_code
= IPP_OK
;
7498 * 'validate_name()' - Make sure the printer name only contains valid chars.
7501 static int /* O - 0 if name is no good, 1 if name is good */
7502 validate_name(const char *name
) /* I - Name to check */
7504 const char *ptr
; /* Pointer into name */
7508 * Scan the whole name...
7511 for (ptr
= name
; *ptr
; ptr
++)
7512 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
7516 * All the characters are good; validate the length, too...
7519 return ((ptr
- name
) < 128);
7524 * 'validate_user()' - Validate the user for the request.
7527 static int /* O - 1 if permitted, 0 otherwise */
7528 validate_user(job_t
*job
, /* I - Job */
7529 client_t
*con
, /* I - Client connection */
7530 const char *owner
, /* I - Owner of job/resource */
7531 char *username
, /* O - Authenticated username */
7532 int userlen
) /* I - Length of username */
7534 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
7535 printer_t
*printer
; /* Printer for job */
7538 LogMessage(L_DEBUG2
, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=%d)\n",
7539 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
7546 if (!con
|| !owner
|| !username
|| userlen
<= 0)
7550 * Get the best authenticated username that is available.
7553 if (con
->username
[0])
7554 strlcpy(username
, con
->username
, userlen
);
7555 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
7556 strlcpy(username
, attr
->values
[0].string
.text
, userlen
);
7558 strlcpy(username
, "anonymous", userlen
);
7561 * Check the username against the owner...
7564 if (job
->dtype
& CUPS_PRINTER_CLASS
)
7565 printer
= FindClass(job
->dest
);
7567 printer
= FindPrinter(job
->dest
);
7570 return (CheckPolicy(printer
->op_policy_ptr
, con
, owner
));
7572 return (CheckPolicy(DefaultPolicyPtr
, con
, owner
));