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
);
557 LogMessage(L_DEBUG
, "ProcessIPPRequest: %d status_code=%x (%s)",
558 con
->http
.fd
, con
->response
->request
.status
.status_code
,
559 ippErrorString(con
->response
->request
.status
.status_code
));
561 if (SendHeader(con
, HTTP_OK
, "application/ipp"))
563 if (con
->http
.version
== HTTP_1_1
)
565 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
567 httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n");
571 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
572 con
->http
.data_remaining
= ippLength(con
->response
);
574 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
575 con
->http
.data_remaining
);
578 LogMessage(L_DEBUG2
, "ProcessIPPRequest: Adding fd %d to OutputSet...",
581 FD_SET(con
->http
.fd
, OutputSet
);
584 * Tell the caller the response header was sent successfully...
592 * Tell the caller the response header could not be sent...
601 * 'accept_jobs()' - Accept print jobs to a printer.
605 accept_jobs(client_t
*con
, /* I - Client connection */
606 ipp_attribute_t
*uri
) /* I - Printer or class URI */
608 cups_ptype_t dtype
; /* Destination type (printer or class) */
609 char method
[HTTP_MAX_URI
], /* Method portion of URI */
610 username
[HTTP_MAX_URI
], /* Username portion of URI */
611 host
[HTTP_MAX_URI
], /* Host portion of URI */
612 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
613 int port
; /* Port portion of URI */
614 const char *name
; /* Printer name */
615 printer_t
*printer
; /* Printer data */
618 LogMessage(L_DEBUG2
, "accept_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
619 uri
->values
[0].string
.text
);
622 * Was this operation called from the correct URI?
625 if (strncmp(con
->uri
, "/admin/", 7) != 0)
627 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
629 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
634 * Is the destination valid?
637 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
639 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
645 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
646 send_ipp_error(con
, IPP_NOT_FOUND
);
654 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
656 LogMessage(L_ERROR
, "accept_jobs: not authorized!");
657 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
662 * Accept jobs sent to the printer...
665 printer
->accepting
= 1;
666 printer
->state_message
[0] = '\0';
668 AddPrinterHistory(printer
);
670 if (dtype
& CUPS_PRINTER_CLASS
)
675 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
679 * Everything was ok, so return OK status...
682 con
->response
->request
.status
.status_code
= IPP_OK
;
687 * 'add_class()' - Add a class to the system.
691 add_class(client_t
*con
, /* I - Client connection */
692 ipp_attribute_t
*uri
) /* I - URI of class */
694 int i
; /* Looping var */
695 char method
[HTTP_MAX_URI
], /* Method portion of URI */
696 username
[HTTP_MAX_URI
], /* Username portion of URI */
697 host
[HTTP_MAX_URI
], /* Host portion of URI */
698 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
699 int port
; /* Port portion of URI */
700 printer_t
*pclass
, /* Class */
701 *member
; /* Member printer/class */
702 cups_ptype_t dtype
; /* Destination type */
703 const char *dest
; /* Printer or class name */
704 ipp_attribute_t
*attr
; /* Printer attribute */
705 int modify
; /* Non-zero if we just modified */
708 LogMessage(L_DEBUG2
, "add_class(%p[%d], %s)\n", con
, con
->http
.fd
,
709 uri
->values
[0].string
.text
);
712 * Was this operation called from the correct URI?
715 if (strncmp(con
->uri
, "/admin/", 7) != 0)
717 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
719 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
724 * Do we have a valid URI?
727 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
729 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
732 * No, return an error...
735 send_ipp_error(con
, IPP_BAD_REQUEST
);
740 * Do we have a valid printer name?
743 if (!validate_name(resource
+ 9))
746 * No, return an error...
749 send_ipp_error(con
, IPP_BAD_REQUEST
);
757 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
759 LogMessage(L_ERROR
, "add_class: not authorized!");
760 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
765 * See if the class already exists; if not, create a new class...
768 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
771 * Class doesn't exist; see if we have a printer of the same name...
774 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
775 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
778 * Yes, return an error...
781 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
786 * No, add the pclass...
789 pclass
= AddClass(resource
+ 9);
792 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
795 * Rename the implicit class to "AnyClass" or remove it...
798 if (ImplicitAnyClasses
)
800 SetStringf(&pclass
->name
, "Any%s", resource
+ 9);
804 DeletePrinter(pclass
, 1);
807 * Add the class as a new local class...
810 pclass
= AddClass(resource
+ 9);
813 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
816 * Rename the remote class to "Class"...
819 DeletePrinterFilters(pclass
);
820 SetStringf(&pclass
->name
, "%s@%s", resource
+ 9, pclass
->hostname
);
821 SetPrinterAttrs(pclass
);
825 * Add the class as a new local class...
828 pclass
= AddClass(resource
+ 9);
835 * Look for attributes and copy them over as needed...
838 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
839 SetString(&pclass
->location
, attr
->values
[0].string
.text
);
841 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
842 SetString(&pclass
->info
, attr
->values
[0].string
.text
);
844 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
846 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
847 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
849 pclass
->accepting
= attr
->values
[0].boolean
;
850 AddPrinterHistory(pclass
);
852 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
854 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
855 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
857 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
858 pclass
->name
, attr
->values
[0].integer
);
859 send_ipp_error(con
, IPP_BAD_REQUEST
);
863 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
864 attr
->values
[0].integer
, pclass
->state
);
866 SetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
868 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
870 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
871 sizeof(pclass
->state_message
));
872 AddPrinterHistory(pclass
);
874 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
877 SetString(&pclass
->job_sheets
[0], attr
->values
[0].string
.text
);
878 if (attr
->num_values
> 1)
879 SetString(&pclass
->job_sheets
[1], attr
->values
[1].string
.text
);
881 SetString(&pclass
->job_sheets
[1], "none");
883 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
884 IPP_TAG_ZERO
)) != NULL
)
886 FreePrinterUsers(pclass
);
888 pclass
->deny_users
= 0;
889 if (attr
->value_tag
== IPP_TAG_NAME
&&
890 (attr
->num_values
> 1 ||
891 strcmp(attr
->values
[0].string
.text
, "all") != 0))
892 for (i
= 0; i
< attr
->num_values
; i
++)
893 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
895 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
896 IPP_TAG_ZERO
)) != NULL
)
898 FreePrinterUsers(pclass
);
900 pclass
->deny_users
= 1;
901 if (attr
->value_tag
== IPP_TAG_NAME
&&
902 (attr
->num_values
> 1 ||
903 strcmp(attr
->values
[0].string
.text
, "none") != 0))
904 for (i
= 0; i
< attr
->num_values
; i
++)
905 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
907 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
908 IPP_TAG_INTEGER
)) != NULL
)
910 LogMessage(L_DEBUG
, "add_class: Setting job-quota-period to %d...",
911 attr
->values
[0].integer
);
913 pclass
->quota_period
= attr
->values
[0].integer
;
915 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
916 IPP_TAG_INTEGER
)) != NULL
)
918 LogMessage(L_DEBUG
, "add_class: Setting job-k-limit to %d...",
919 attr
->values
[0].integer
);
921 pclass
->k_limit
= attr
->values
[0].integer
;
923 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
924 IPP_TAG_INTEGER
)) != NULL
)
926 LogMessage(L_DEBUG
, "add_class: Setting job-page-limit to %d...",
927 attr
->values
[0].integer
);
929 pclass
->page_limit
= attr
->values
[0].integer
;
931 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
933 policy_t
*p
; /* Policy */
936 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
938 LogMessage(L_DEBUG
, "add_class: Setting printer-op-policy to \"%s\"...",
939 attr
->values
[0].string
.text
);
940 SetString(&pclass
->op_policy
, attr
->values
[0].string
.text
);
941 pclass
->op_policy_ptr
= p
;
945 LogMessage(L_ERROR
, "add_class: Unknown printer-op-policy \"%s\"...",
946 attr
->values
[0].string
.text
);
947 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
951 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
953 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
954 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
955 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
957 LogMessage(L_ERROR
, "add_class: Unknown printer-error-policy \"%s\"...",
958 attr
->values
[0].string
.text
);
959 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
963 LogMessage(L_DEBUG
, "add_class: Setting printer-error-policy to \"%s\"...",
964 attr
->values
[0].string
.text
);
965 SetString(&pclass
->error_policy
, attr
->values
[0].string
.text
);
967 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
970 * Clear the printer array as needed...
973 if (pclass
->num_printers
> 0)
975 free(pclass
->printers
);
976 pclass
->num_printers
= 0;
980 * Add each printer or class that is listed...
983 for (i
= 0; i
< attr
->num_values
; i
++)
986 * Search for the printer or class URI...
989 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
992 if ((dest
= ValidateDest(host
, resource
, &dtype
, &member
)) == NULL
)
998 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
999 send_ipp_error(con
, IPP_NOT_FOUND
);
1004 * Add it to the class...
1007 AddPrinterToClass(pclass
, member
);
1012 * Update the printer class attributes and return...
1015 SetPrinterAttrs(pclass
);
1023 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1024 "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1027 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1032 AddPrinterHistory(pclass
);
1034 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1035 "New class \'%s\' added by \'%s\'.", pclass
->name
,
1038 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
1042 con
->response
->request
.status
.status_code
= IPP_OK
;
1047 * 'add_file()' - Add a file to a job.
1050 static int /* O - 0 on success, -1 on error */
1051 add_file(client_t
*con
, /* I - Connection to client */
1052 job_t
*job
, /* I - Job to add to */
1053 mime_type_t
*filetype
, /* I - Type of file */
1054 int compression
) /* I - Compression */
1056 mime_type_t
**filetypes
; /* New filetypes array... */
1057 int *compressions
; /* New compressions array... */
1060 LogMessage(L_DEBUG2
, "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)\n",
1061 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1065 * Add the file to the job...
1068 if (job
->num_files
== 0)
1070 compressions
= (int *)malloc(sizeof(int));
1071 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1075 compressions
= (int *)realloc(job
->compressions
,
1076 (job
->num_files
+ 1) * sizeof(int));
1077 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1078 (job
->num_files
+ 1) *
1079 sizeof(mime_type_t
*));
1082 if (compressions
== NULL
|| filetypes
== NULL
)
1084 CancelJob(job
->id
, 1);
1085 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
1086 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1090 job
->compressions
= compressions
;
1091 job
->compressions
[job
->num_files
] = compression
;
1092 job
->filetypes
= filetypes
;
1093 job
->filetypes
[job
->num_files
] = filetype
;
1102 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1103 * upon the job and printer state...
1107 add_job_state_reasons(client_t
*con
, /* I - Client connection */
1108 job_t
*job
) /* I - Job info */
1110 printer_t
*dest
; /* Destination printer */
1113 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
1116 switch (job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
)
1118 case IPP_JOB_PENDING
:
1119 if (job
->dtype
& CUPS_PRINTER_CLASS
)
1120 dest
= FindClass(job
->dest
);
1122 dest
= FindPrinter(job
->dest
);
1124 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
1125 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1126 "job-state-reasons", NULL
, "printer-stopped");
1128 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1129 "job-state-reasons", NULL
, "none");
1133 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
1134 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
1135 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1136 "job-state-reasons", NULL
, "job-hold-until-specified");
1138 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1139 "job-state-reasons", NULL
, "job-incoming");
1142 case IPP_JOB_PROCESSING
:
1143 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1144 "job-state-reasons", NULL
, "job-printing");
1147 case IPP_JOB_STOPPED
:
1148 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1149 "job-state-reasons", NULL
, "job-stopped");
1152 case IPP_JOB_CANCELLED
:
1153 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1154 "job-state-reasons", NULL
, "job-canceled-by-user");
1157 case IPP_JOB_ABORTED
:
1158 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1159 "job-state-reasons", NULL
, "aborted-by-system");
1162 case IPP_JOB_COMPLETED
:
1163 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1164 "job-state-reasons", NULL
, "job-completed-successfully");
1171 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1175 add_job_subscriptions(client_t
*con
, /* I - Client connection */
1176 job_t
*job
) /* I - Newly created job */
1178 int i
; /* Looping var */
1179 ipp_attribute_t
*prev
, /* Previous attribute */
1180 *next
, /* Next attribute */
1181 *attr
; /* Current attribute */
1182 cupsd_subscription_t
*sub
; /* Subscription object */
1183 const char *recipient
, /* notify-recipient-uri */
1184 *pullmethod
; /* notify-pull-method */
1185 ipp_attribute_t
*user_data
; /* notify-user-data */
1186 int interval
; /* notify-time-interval */
1187 unsigned mask
; /* notify-events */
1191 * Find the first subscription group attribute; return if we have
1195 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; prev
= attr
, attr
= attr
->next
)
1196 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1203 * Process the subscription attributes in the request...
1212 mask
= CUPSD_EVENT_NONE
;
1214 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1216 if (!strcmp(attr
->name
, "notify-recipient") &&
1217 attr
->value_tag
== IPP_TAG_URI
)
1218 recipient
= attr
->values
[0].string
.text
;
1219 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1220 attr
->value_tag
== IPP_TAG_KEYWORD
)
1221 pullmethod
= attr
->values
[0].string
.text
;
1222 else if (!strcmp(attr
->name
, "notify-charset") &&
1223 attr
->value_tag
== IPP_TAG_CHARSET
&&
1224 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1226 send_ipp_error(con
, IPP_CHARSET
);
1229 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1230 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
1231 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
))
1233 send_ipp_error(con
, IPP_CHARSET
);
1236 else if (!strcmp(attr
->name
, "notify-user-data") &&
1237 attr
->value_tag
== IPP_TAG_STRING
)
1239 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1241 send_ipp_error(con
, IPP_REQUEST_VALUE
);
1247 else if (!strcmp(attr
->name
, "notify-events") &&
1248 attr
->value_tag
== IPP_TAG_KEYWORD
)
1250 for (i
= 0; i
< attr
->num_values
; i
++)
1251 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1253 else if (!strcmp(attr
->name
, "notify-lease-time"))
1255 send_ipp_error(con
, IPP_BAD_REQUEST
);
1258 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1259 attr
->value_tag
== IPP_TAG_INTEGER
)
1260 interval
= attr
->values
[0].integer
;
1265 if (!recipient
&& !pullmethod
)
1268 if (mask
== CUPSD_EVENT_NONE
)
1269 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1271 sub
= cupsdAddSubscription(mask
, FindDest(job
->dest
), job
, recipient
);
1273 sub
->interval
= interval
;
1275 SetString(&sub
->owner
, job
->username
);
1279 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1280 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1281 sub
->user_data_len
);
1289 * Remove all of the subscription attributes from the job request...
1292 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1296 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1297 attr
->group_tag
== IPP_TAG_ZERO
)
1300 * Free and remove this attribute...
1303 _ipp_free_attr(attr
);
1308 job
->attrs
->attrs
= next
;
1314 job
->attrs
->last
= prev
;
1315 job
->attrs
->current
= prev
;
1320 * 'add_printer()' - Add a printer to the system.
1324 add_printer(client_t
*con
, /* I - Client connection */
1325 ipp_attribute_t
*uri
) /* I - URI of printer */
1327 int i
; /* Looping var */
1328 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1329 username
[HTTP_MAX_URI
], /* Username portion of URI */
1330 host
[HTTP_MAX_URI
], /* Host portion of URI */
1331 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1332 int port
; /* Port portion of URI */
1333 printer_t
*printer
; /* Printer/class */
1334 ipp_attribute_t
*attr
; /* Printer attribute */
1335 cups_file_t
*fp
; /* Script/PPD file */
1336 char line
[1024]; /* Line from file... */
1337 char srcfile
[1024], /* Source Script/PPD file */
1338 dstfile
[1024]; /* Destination Script/PPD file */
1339 int modify
; /* Non-zero if we are modifying */
1342 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
1343 uri
->values
[0].string
.text
);
1346 * Was this operation called from the correct URI?
1349 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1351 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
1353 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1358 * Do we have a valid URI?
1361 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1363 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1366 * No, return an error...
1369 LogMessage(L_ERROR
, "add_printer: bad printer URI \"%s\"!",
1370 uri
->values
[0].string
.text
);
1371 send_ipp_error(con
, IPP_BAD_REQUEST
);
1376 * Do we have a valid printer name?
1379 if (!validate_name(resource
+ 10))
1382 * No, return an error...
1385 send_ipp_error(con
, IPP_BAD_REQUEST
);
1393 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
1395 LogMessage(L_ERROR
, "add_printer: not authorized!");
1396 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1401 * See if the printer already exists; if not, create a new printer...
1404 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1407 * Printer doesn't exist; see if we have a class of the same name...
1410 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1411 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1414 * Yes, return an error...
1417 LogMessage(L_ERROR
, "add_printer: \"%s\" already exists as a class!",
1419 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1424 * No, add the printer...
1427 printer
= AddPrinter(resource
+ 10);
1430 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1433 * Rename the implicit printer to "AnyPrinter" or delete it...
1436 if (ImplicitAnyClasses
)
1438 SetStringf(&printer
->name
, "Any%s", resource
+ 10);
1442 DeletePrinter(printer
, 1);
1445 * Add the printer as a new local printer...
1448 printer
= AddPrinter(resource
+ 10);
1451 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1454 * Rename the remote printer to "Printer@server"...
1457 DeletePrinterFilters(printer
);
1458 SetStringf(&printer
->name
, "%s@%s", resource
+ 10, printer
->hostname
);
1459 SetPrinterAttrs(printer
);
1463 * Add the printer as a new local printer...
1466 printer
= AddPrinter(resource
+ 10);
1473 * Look for attributes and copy them over as needed...
1476 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1477 SetString(&printer
->location
, attr
->values
[0].string
.text
);
1479 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1480 SetString(&printer
->info
, attr
->values
[0].string
.text
);
1482 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1484 ipp_attribute_t
*device
; /* Current device */
1485 int methodlen
; /* Length of method string */
1489 * Do we have a valid device URI?
1492 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1494 methodlen
= strlen(method
);
1496 if (strcmp(method
, "file") == 0)
1499 * See if the administrator has enabled file devices...
1502 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
1505 * File devices are disabled and the URL is not file:/dev/null...
1508 LogMessage(L_ERROR
, "add_printer: File device URIs have been disabled! "
1509 "To enable, see the FileDevice directive in cupsd.conf.");
1510 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1517 * See if the backend is listed as a device...
1520 for (device
= ippFindAttribute(Devices
, "device-uri", IPP_TAG_URI
);
1522 device
= ippFindNextAttribute(Devices
, "device-uri", IPP_TAG_URI
))
1523 if (strncmp(method
, device
->values
[0].string
.text
, methodlen
) == 0 &&
1524 (device
->values
[0].string
.text
[methodlen
] == ':' ||
1525 device
->values
[0].string
.text
[methodlen
] == '\0'))
1531 * Could not find device in list!
1534 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1535 attr
->values
[0].string
.text
);
1536 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1541 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1543 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
, sizeof(line
)),
1544 cupsdSanitizeURI(printer
->device_uri
, resource
, sizeof(resource
)));
1546 SetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
1549 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1551 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1552 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1554 printer
->accepting
= attr
->values
[0].boolean
;
1555 AddPrinterHistory(printer
);
1557 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1559 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1560 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1562 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
1563 printer
->name
, attr
->values
[0].integer
);
1564 send_ipp_error(con
, IPP_BAD_REQUEST
);
1568 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1569 attr
->values
[0].integer
, printer
->state
);
1571 SetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1573 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1575 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
1576 sizeof(printer
->state_message
));
1577 AddPrinterHistory(printer
);
1579 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1582 SetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
1583 if (attr
->num_values
> 1)
1584 SetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
1586 SetString(&printer
->job_sheets
[1], "none");
1588 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1589 IPP_TAG_ZERO
)) != NULL
)
1591 FreePrinterUsers(printer
);
1593 printer
->deny_users
= 0;
1594 if (attr
->value_tag
== IPP_TAG_NAME
&&
1595 (attr
->num_values
> 1 ||
1596 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1597 for (i
= 0; i
< attr
->num_values
; i
++)
1598 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1600 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1601 IPP_TAG_ZERO
)) != NULL
)
1603 FreePrinterUsers(printer
);
1605 printer
->deny_users
= 1;
1606 if (attr
->value_tag
== IPP_TAG_NAME
&&
1607 (attr
->num_values
> 1 ||
1608 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1609 for (i
= 0; i
< attr
->num_values
; i
++)
1610 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1612 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1613 IPP_TAG_INTEGER
)) != NULL
)
1615 LogMessage(L_DEBUG
, "add_printer: Setting job-quota-period to %d...",
1616 attr
->values
[0].integer
);
1617 FreeQuotas(printer
);
1618 printer
->quota_period
= attr
->values
[0].integer
;
1620 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1621 IPP_TAG_INTEGER
)) != NULL
)
1623 LogMessage(L_DEBUG
, "add_printer: Setting job-k-limit to %d...",
1624 attr
->values
[0].integer
);
1625 FreeQuotas(printer
);
1626 printer
->k_limit
= attr
->values
[0].integer
;
1628 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1629 IPP_TAG_INTEGER
)) != NULL
)
1631 LogMessage(L_DEBUG
, "add_printer: Setting job-page-limit to %d...",
1632 attr
->values
[0].integer
);
1633 FreeQuotas(printer
);
1634 printer
->page_limit
= attr
->values
[0].integer
;
1636 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
1638 policy_t
*p
; /* Policy */
1641 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
1643 LogMessage(L_DEBUG
, "add_printer: Setting printer-op-policy to \"%s\"...",
1644 attr
->values
[0].string
.text
);
1645 SetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
1646 printer
->op_policy_ptr
= p
;
1650 LogMessage(L_ERROR
, "add_printer: Unknown printer-op-policy \"%s\"...",
1651 attr
->values
[0].string
.text
);
1652 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1656 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
1658 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
1659 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
1660 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
1662 LogMessage(L_ERROR
, "add_printer: Unknown printer-error-policy \"%s\"...",
1663 attr
->values
[0].string
.text
);
1664 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1668 LogMessage(L_DEBUG
, "add_printer: Setting printer-error-policy to \"%s\"...",
1669 attr
->values
[0].string
.text
);
1670 SetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
1674 * See if we have all required attributes...
1677 if (!printer
->device_uri
)
1678 SetString(&printer
->device_uri
, "file:/dev/null");
1681 * See if we have an interface script or PPD file attached to the request...
1686 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
1688 if ((fp
= cupsFileOpen(srcfile
, "rb")) != NULL
)
1691 * Yes; get the first line from it...
1695 cupsFileGets(fp
, line
, sizeof(line
));
1699 * Then see what kind of file it is...
1702 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1705 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1708 * The new file is a PPD file, so remove any old interface script
1709 * that might be lying around...
1717 * This must be an interface script, so move the file over to the
1718 * interfaces directory and make it executable...
1721 if (copy_file(srcfile
, dstfile
))
1723 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1724 srcfile
, dstfile
, strerror(errno
));
1725 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1730 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1731 chmod(dstfile
, 0755);
1735 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1738 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1741 * The new file is a PPD file, so move the file over to the
1742 * ppd directory and make it readable by all...
1745 if (copy_file(srcfile
, dstfile
))
1747 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1748 srcfile
, dstfile
, strerror(errno
));
1749 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1754 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1755 chmod(dstfile
, 0644);
1761 * This must be an interface script, so remove any old PPD file that
1762 * may be lying around...
1769 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1771 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1774 * Raw driver, remove any existing PPD or interface script files.
1777 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1781 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1791 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1792 attr
->values
[0].string
.text
);
1794 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1798 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1801 if (copy_model(srcfile
, dstfile
))
1803 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1804 srcfile
, dstfile
, strerror(errno
));
1805 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1810 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1811 chmod(dstfile
, 0644);
1817 * Make this printer the default if there is none...
1820 if (DefaultPrinter
== NULL
)
1821 DefaultPrinter
= printer
;
1824 * Update the printer attributes and return...
1827 SetPrinterAttrs(printer
);
1830 if (printer
->job
!= NULL
)
1835 * Stop the current job and then restart it below...
1838 job
= (job_t
*)printer
->job
;
1840 StopJob(job
->id
, 1);
1841 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1850 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
1851 "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1854 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1859 AddPrinterHistory(printer
);
1861 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
1862 "New printer \'%s\' added by \'%s\'.", printer
->name
,
1865 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1869 con
->response
->request
.status
.status_code
= IPP_OK
;
1874 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1875 * based upon the printer state...
1879 add_printer_state_reasons(
1880 client_t
*con
, /* I - Client connection */
1881 printer_t
*p
) /* I - Printer info */
1883 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1884 con
, con
->http
.fd
, p
, p
->name
);
1886 if (p
->num_reasons
== 0)
1887 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1888 "printer-state-reasons", NULL
,
1889 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
1891 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1892 "printer-state-reasons", p
->num_reasons
, NULL
,
1893 (const char * const *)p
->reasons
);
1898 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1899 * the specified printer or class.
1903 add_queued_job_count(client_t
*con
, /* I - Client connection */
1904 printer_t
*p
) /* I - Printer or class */
1906 int count
; /* Number of jobs on destination */
1909 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1910 con
, con
->http
.fd
, p
, p
->name
);
1912 count
= GetPrinterJobCount(p
->name
);
1914 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1915 "queued-job-count", count
);
1920 * 'cancel_all_jobs()' - Cancel all print jobs.
1924 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1925 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1927 const char *dest
; /* Destination */
1928 cups_ptype_t dtype
; /* Destination type */
1929 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1930 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
1931 host
[HTTP_MAX_URI
], /* Host portion of URI */
1932 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1933 int port
; /* Port portion of URI */
1934 ipp_attribute_t
*attr
; /* Attribute in request */
1935 const char *username
; /* Username */
1936 int purge
; /* Purge? */
1937 printer_t
*printer
; /* Printer */
1940 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
1941 uri
->values
[0].string
.text
);
1944 * Was this operation called from the correct URI?
1947 if (strncmp(con
->uri
, "/admin/", 7) &&
1948 strncmp(con
->uri
, "/jobs/", 7))
1950 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
1952 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1957 * See if we have a printer URI...
1960 if (strcmp(uri
->name
, "printer-uri"))
1962 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
1963 uri
->name
, uri
->values
[0].string
.text
);
1964 send_ipp_error(con
, IPP_BAD_REQUEST
);
1969 * Get the username (if any) for the jobs we want to cancel (only if
1970 * "my-jobs" is specified...
1973 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
1974 attr
->values
[0].boolean
)
1976 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
1977 username
= attr
->values
[0].string
.text
;
1980 LogMessage(L_ERROR
, "cancel_all_jobs: missing requesting-user-name attribute!");
1981 send_ipp_error(con
, IPP_BAD_REQUEST
);
1989 (username
&& con
->username
[0] && strcmp(username
, con
->username
))) &&
1990 strncmp(con
->uri
, "/admin/", 7))
1992 LogMessage(L_ERROR
, "cancel_all_jobs: only administrators can cancel "
1993 "other users\' jobs!");
1994 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1999 * Look for the "purge-jobs" attribute...
2002 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
2003 purge
= attr
->values
[0].boolean
;
2008 * And if the destination is valid...
2011 httpSeparate(uri
->values
[0].string
.text
, method
, userpass
, host
, &port
,
2014 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2020 if (strcmp(resource
, "/printers/") != 0)
2022 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
2023 send_ipp_error(con
, IPP_NOT_FOUND
);
2031 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
2033 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2034 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2039 * Cancel all jobs on all printers...
2042 CancelJobs(NULL
, username
, purge
);
2044 LogMessage(L_INFO
, "All jobs were %s by \'%s\'.",
2045 purge
? "purged" : "cancelled", con
->username
);
2053 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
2055 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2056 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2061 * Cancel all of the jobs on the named printer...
2064 CancelJobs(dest
, username
, purge
);
2066 LogMessage(L_INFO
, "All jobs on \'%s\' were %s by \'%s\'.", dest
,
2067 purge
? "purged" : "cancelled", con
->username
);
2070 con
->response
->request
.status
.status_code
= IPP_OK
;
2075 * 'cancel_job()' - Cancel a print job.
2079 cancel_job(client_t
*con
, /* I - Client connection */
2080 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2082 ipp_attribute_t
*attr
; /* Current attribute */
2083 int jobid
; /* Job ID */
2084 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2085 username
[HTTP_MAX_URI
], /* Username portion of URI */
2086 host
[HTTP_MAX_URI
], /* Host portion of URI */
2087 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2088 int port
; /* Port portion of URI */
2089 job_t
*job
; /* Job information */
2090 const char *dest
; /* Destination */
2091 cups_ptype_t dtype
; /* Destination type (printer or class) */
2092 printer_t
*printer
; /* Printer data */
2095 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2096 uri
->values
[0].string
.text
);
2099 * Verify that the POST operation was done to a valid URI.
2102 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2103 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
2104 strncmp(con
->uri
, "/printers/", 10) != 0)
2106 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
2108 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2113 * See if we have a job URI or a printer URI...
2116 if (strcmp(uri
->name
, "printer-uri") == 0)
2119 * Got a printer URI; see if we also have a job-id attribute...
2122 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2124 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
2125 send_ipp_error(con
, IPP_BAD_REQUEST
);
2129 if ((jobid
= attr
->values
[0].integer
) == 0)
2132 * Find the current job on the specified printer...
2135 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2137 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2143 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
2144 send_ipp_error(con
, IPP_NOT_FOUND
);
2149 * See if the printer is currently printing a job...
2153 jobid
= ((job_t
*)printer
->job
)->id
;
2157 * No, see if there are any pending jobs...
2160 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
2161 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
2162 strcasecmp(job
->dest
, dest
) == 0)
2169 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
2170 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2179 * Got a job URI; parse it to get the job ID...
2182 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2184 if (strncmp(resource
, "/jobs/", 6) != 0)
2190 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
2191 uri
->values
[0].string
.text
);
2192 send_ipp_error(con
, IPP_BAD_REQUEST
);
2196 jobid
= atoi(resource
+ 6);
2200 * See if the job exists...
2203 if ((job
= FindJob(jobid
)) == NULL
)
2206 * Nope - return a "not found" error...
2209 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
2210 send_ipp_error(con
, IPP_NOT_FOUND
);
2215 * See if the job is owned by the requesting user...
2218 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2220 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
2221 username
, jobid
, job
->username
);
2222 send_ipp_error(con
, IPP_FORBIDDEN
);
2227 * See if the job is already completed, cancelled, or aborted; if so,
2228 * we can't cancel...
2231 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
2233 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
2235 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
2236 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
2238 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2243 * Cancel the job and return...
2246 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED
, job
->printer
, job
,
2247 "Job cancelled by \'%s\'.", username
);
2249 CancelJob(jobid
, 0);
2252 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
2254 con
->response
->request
.status
.status_code
= IPP_OK
;
2259 * 'cancel_subscription()' - Cancel a subscription.
2263 cancel_subscription(client_t
*con
, /* I - Client connection */
2264 int sub_id
) /* I - Subscription ID */
2270 * 'check_quotas()' - Check quotas for a printer and user.
2273 static int /* O - 1 if OK, 0 if not */
2274 check_quotas(client_t
*con
, /* I - Client connection */
2275 printer_t
*p
) /* I - Printer or class */
2277 int i
, j
; /* Looping vars */
2278 ipp_attribute_t
*attr
; /* Current attribute */
2279 char username
[33]; /* Username */
2280 quota_t
*q
; /* Quota data */
2281 struct passwd
*pw
; /* User password data */
2282 struct group
*grp
; /* Group data */
2285 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
2286 con
, con
->http
.fd
, p
, p
->name
);
2292 if (con
== NULL
|| p
== NULL
)
2296 * Figure out who is printing...
2299 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
2301 if (con
->username
[0])
2302 strlcpy(username
, con
->username
, sizeof(username
));
2303 else if (attr
!= NULL
)
2305 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
2306 attr
->values
[0].string
.text
);
2308 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
2311 strcpy(username
, "anonymous");
2314 * Check global active job limits for printers and users...
2317 if (MaxJobsPerPrinter
)
2320 * Check if there are too many pending jobs on this printer...
2323 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
2325 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
2333 * Check if there are too many pending jobs for this user...
2336 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
2338 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
2344 * Check against users...
2347 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
2352 pw
= getpwnam(username
);
2355 for (i
= 0; i
< p
->num_users
; i
++)
2356 if (p
->users
[i
][0] == '@')
2359 * Check group membership...
2362 grp
= getgrnam(p
->users
[i
] + 1);
2368 * Check primary group...
2371 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
2375 * Check usernames in group...
2378 for (j
= 0; grp
->gr_mem
[j
]; j
++)
2379 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
2386 else if (!strcasecmp(username
, p
->users
[i
]))
2389 if ((i
< p
->num_users
) == p
->deny_users
)
2391 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
2401 if (p
->k_limit
|| p
->page_limit
)
2403 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
2405 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
2410 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
2411 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
2413 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
2420 * If we have gotten this far, we're done!
2428 * 'copy_attribute()' - Copy a single attribute.
2431 static ipp_attribute_t
* /* O - New attribute */
2433 ipp_t
*to
, /* O - Destination request/response */
2434 ipp_attribute_t
*attr
, /* I - Attribute to copy */
2435 int quickcopy
) /* I - Do a quick copy? */
2437 int i
; /* Looping var */
2438 ipp_attribute_t
*toattr
; /* Destination attribute */
2441 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
2442 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
2445 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2448 toattr
= ippAddSeparator(to
);
2451 case IPP_TAG_INTEGER
:
2453 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2454 attr
->name
, attr
->num_values
, NULL
);
2456 for (i
= 0; i
< attr
->num_values
; i
++)
2457 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
2460 case IPP_TAG_BOOLEAN
:
2461 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
2462 attr
->num_values
, NULL
);
2464 for (i
= 0; i
< attr
->num_values
; i
++)
2465 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
2468 case IPP_TAG_STRING
:
2471 case IPP_TAG_KEYWORD
:
2473 case IPP_TAG_URISCHEME
:
2474 case IPP_TAG_CHARSET
:
2475 case IPP_TAG_LANGUAGE
:
2476 case IPP_TAG_MIMETYPE
:
2477 toattr
= ippAddStrings(to
, attr
->group_tag
,
2478 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2479 attr
->name
, attr
->num_values
, NULL
, NULL
);
2483 for (i
= 0; i
< attr
->num_values
; i
++)
2484 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2488 for (i
= 0; i
< attr
->num_values
; i
++)
2489 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2494 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
2495 attr
->values
[0].date
);
2498 case IPP_TAG_RESOLUTION
:
2499 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
2500 attr
->num_values
, IPP_RES_PER_INCH
,
2503 for (i
= 0; i
< attr
->num_values
; i
++)
2505 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
2506 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
2507 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
2511 case IPP_TAG_RANGE
:
2512 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
2513 attr
->num_values
, NULL
, NULL
);
2515 for (i
= 0; i
< attr
->num_values
; i
++)
2517 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
2518 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
2522 case IPP_TAG_TEXTLANG
:
2523 case IPP_TAG_NAMELANG
:
2524 toattr
= ippAddStrings(to
, attr
->group_tag
,
2525 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2526 attr
->name
, attr
->num_values
, NULL
, NULL
);
2530 for (i
= 0; i
< attr
->num_values
; i
++)
2532 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
2533 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2538 for (i
= 0; i
< attr
->num_values
; i
++)
2541 toattr
->values
[i
].string
.charset
=
2542 strdup(attr
->values
[i
].string
.charset
);
2544 toattr
->values
[i
].string
.charset
=
2545 toattr
->values
[0].string
.charset
;
2547 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2552 case IPP_TAG_BEGIN_COLLECTION
:
2553 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
2554 attr
->num_values
, NULL
);
2556 for (i
= 0; i
< attr
->num_values
; i
++)
2558 toattr
->values
[i
].collection
= ippNew();
2559 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
2560 NULL
, IPP_TAG_ZERO
, 0);
2565 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2566 attr
->name
, attr
->num_values
, NULL
);
2568 for (i
= 0; i
< attr
->num_values
; i
++)
2570 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
2572 if (toattr
->values
[i
].unknown
.length
> 0)
2574 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
2575 toattr
->values
[i
].unknown
.length
= 0;
2577 memcpy(toattr
->values
[i
].unknown
.data
,
2578 attr
->values
[i
].unknown
.data
,
2579 toattr
->values
[i
].unknown
.length
);
2582 break; /* anti-compiler-warning-code */
2590 * 'copy_attrs()' - Copy attributes from one request to another.
2594 copy_attrs(ipp_t
*to
, /* I - Destination request */
2595 ipp_t
*from
, /* I - Source request */
2596 ipp_attribute_t
*req
, /* I - Requested attributes */
2597 ipp_tag_t group
, /* I - Group to copy */
2598 int quickcopy
) /* I - Do a quick copy? */
2600 int i
; /* Looping var */
2601 ipp_attribute_t
*fromattr
; /* Source attribute */
2604 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2606 if (to
== NULL
|| from
== NULL
)
2609 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2610 req
= NULL
; /* "all" means no filter... */
2612 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2615 * Filter attributes as needed...
2618 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2619 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2622 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2624 for (i
= 0; i
< req
->num_values
; i
++)
2625 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2628 if (i
== req
->num_values
)
2632 copy_attribute(to
, fromattr
, quickcopy
);
2638 * 'copy_banner()' - Copy a banner file to the requests directory for the
2642 static int /* O - Size of banner file in kbytes */
2643 copy_banner(client_t
*con
, /* I - Client connection */
2644 job_t
*job
, /* I - Job information */
2645 const char *name
) /* I - Name of banner */
2647 int i
; /* Looping var */
2648 int kbytes
; /* Size of banner file in kbytes */
2649 char filename
[1024]; /* Job filename */
2650 banner_t
*banner
; /* Pointer to banner */
2651 cups_file_t
*in
; /* Input file */
2652 cups_file_t
*out
; /* Output file */
2653 int ch
; /* Character from file */
2654 char attrname
[255], /* Name of attribute */
2655 *s
; /* Pointer into name */
2656 ipp_attribute_t
*attr
; /* Attribute */
2659 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2660 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2663 * Find the banner; return if not found or "none"...
2667 strcmp(name
, "none") == 0 ||
2668 (banner
= FindBanner(name
)) == NULL
)
2672 * Open the banner and job files...
2675 if (add_file(con
, job
, banner
->filetype
, 0))
2678 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2680 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
2682 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2683 filename
, strerror(errno
));
2688 fchmod(cupsFileNumber(out
), 0640);
2689 fchown(cupsFileNumber(out
), RunUser
, Group
);
2694 * Try the localized banner file under the subdirectory...
2697 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2698 con
->language
->language
, name
);
2700 if (access(filename
, 0) && con
->language
->language
[2])
2703 * Wasn't able to find "ll_CC" locale file; try the non-national
2704 * localization banner directory.
2707 attrname
[0] = con
->language
->language
[0];
2708 attrname
[1] = con
->language
->language
[1];
2711 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2715 if (access(filename
, 0))
2718 * Use the non-localized banner file.
2721 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2727 * Use the non-localized banner file.
2730 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2733 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
2737 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2738 filename
, strerror(errno
));
2744 * Parse the file to the end...
2747 while ((ch
= cupsFileGetChar(in
)) != EOF
)
2751 * Get an attribute name...
2754 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
2755 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
2757 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2767 * Ignore { followed by stuff that is not an attribute name...
2770 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
2775 * See if it is defined...
2778 if (attrname
[0] == '?')
2783 if (strcmp(s
, "printer-name") == 0)
2785 cupsFilePuts(out
, job
->dest
);
2788 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2791 * See if we have a leading question mark...
2794 if (attrname
[0] != '?')
2797 * Nope, write to file as-is; probably a PostScript procedure...
2800 cupsFilePrintf(out
, "{%s}", attrname
);
2807 * Output value(s)...
2810 for (i
= 0; i
< attr
->num_values
; i
++)
2813 cupsFilePutChar(out
, ',');
2815 switch (attr
->value_tag
)
2817 case IPP_TAG_INTEGER
:
2819 if (strncmp(s
, "time-at-", 8) == 0)
2820 cupsFilePuts(out
, GetDateTime(attr
->values
[i
].integer
));
2822 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
2825 case IPP_TAG_BOOLEAN
:
2826 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
2829 case IPP_TAG_NOVALUE
:
2830 cupsFilePuts(out
, "novalue");
2833 case IPP_TAG_RANGE
:
2834 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2835 attr
->values
[i
].range
.upper
);
2838 case IPP_TAG_RESOLUTION
:
2839 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2840 attr
->values
[i
].resolution
.yres
,
2841 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2846 case IPP_TAG_STRING
:
2849 case IPP_TAG_KEYWORD
:
2850 case IPP_TAG_CHARSET
:
2851 case IPP_TAG_LANGUAGE
:
2852 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2855 * Need to quote strings for PS banners...
2860 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2862 if (*p
== '(' || *p
== ')' || *p
== '\\')
2864 cupsFilePutChar(out
, '\\');
2865 cupsFilePutChar(out
, *p
);
2867 else if (*p
< 32 || *p
> 126)
2868 cupsFilePrintf(out
, "\\%03o", *p
& 255);
2870 cupsFilePutChar(out
, *p
);
2874 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
2878 break; /* anti-compiler-warning-code */
2882 else if (ch
== '\\') /* Quoted char */
2884 ch
= cupsFileGetChar(in
);
2886 if (ch
!= '{') /* Only do special handling for \{ */
2887 cupsFilePutChar(out
, '\\');
2889 cupsFilePutChar(out
, ch
);
2892 cupsFilePutChar(out
, ch
);
2896 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
2898 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2899 attr
->values
[0].integer
+= kbytes
;
2908 * 'copy_file()' - Copy a PPD file or interface script...
2911 static int /* O - 0 = success, -1 = error */
2912 copy_file(const char *from
, /* I - Source file */
2913 const char *to
) /* I - Destination file */
2915 cups_file_t
*src
, /* Source file */
2916 *dst
; /* Destination file */
2917 int bytes
; /* Bytes to read/write */
2918 char buffer
[2048]; /* Copy buffer */
2921 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
2924 * Open the source and destination file for a copy...
2927 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
2930 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
2937 * Copy the source file to the destination...
2940 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
2941 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
2949 * Close both files and return...
2954 return (cupsFileClose(dst
));
2959 * 'copy_model()' - Copy a PPD model file, substituting default values
2963 static int /* O - 0 = success, -1 = error */
2964 copy_model(const char *from
, /* I - Source file */
2965 const char *to
) /* I - Destination file */
2967 cups_file_t
*src
, /* Source file */
2968 *dst
; /* Destination file */
2969 char buffer
[2048]; /* Copy buffer */
2970 int i
; /* Looping var */
2971 char option
[PPD_MAX_NAME
], /* Option name */
2972 choice
[PPD_MAX_NAME
]; /* Choice name */
2973 int num_defaults
; /* Number of default options */
2974 ppd_default_t
*defaults
; /* Default options */
2975 char cups_protocol
[PPD_MAX_LINE
];
2976 /* cupsProtocol attribute */
2977 #ifdef HAVE_LIBPAPER
2978 char *paper_result
; /* Paper size name from libpaper */
2979 char system_paper
[64]; /* Paper size name buffer */
2980 #endif /* HAVE_LIBPAPER */
2983 LogMessage(L_DEBUG2
, "copy_model(\"%s\", \"%s\")\n", from
, to
);
2986 * Open the destination (if possible) and set the default options...
2991 cups_protocol
[0] = '\0';
2993 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
2996 * Read all of the default lines from the old PPD...
2999 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)) != NULL
)
3000 if (!strncmp(buffer
, "*Default", 8))
3003 * Add the default option...
3006 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3007 choice
, sizeof(choice
)))
3008 num_defaults
= ppd_add_default(option
, choice
, num_defaults
,
3011 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
3012 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
3016 #ifdef HAVE_LIBPAPER
3017 else if ((paper_result
= systempapername()) != NULL
)
3020 * Set the default media sizes from the systemwide default...
3023 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
3024 system_paper
[0] = toupper(system_paper
[0] & 255);
3026 num_defaults
= ppd_add_default("PageSize", system_paper
,
3027 num_defaults
, &defaults
);
3028 num_defaults
= ppd_add_default("PageRegion", system_paper
,
3029 num_defaults
, &defaults
);
3030 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
3031 num_defaults
, &defaults
);
3032 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
3033 num_defaults
, &defaults
);
3035 #endif /* HAVE_LIBPAPER */
3039 * Add the default media sizes...
3041 * Note: These values are generally not valid for large-format devices
3042 * like plotters, however it is probably safe to say that those
3043 * users will configure the media size after initially adding
3044 * the device anyways...
3047 if (!DefaultLanguage
||
3048 !strcasecmp(DefaultLanguage
, "C") ||
3049 !strcasecmp(DefaultLanguage
, "POSIX") ||
3050 !strcasecmp(DefaultLanguage
, "en") ||
3051 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
3052 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
3053 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
3056 * These are the only locales that will default to "letter" size...
3059 num_defaults
= ppd_add_default("PageSize", "Letter", num_defaults
,
3061 num_defaults
= ppd_add_default("PageRegion", "Letter", num_defaults
,
3063 num_defaults
= ppd_add_default("PaperDimension", "Letter", num_defaults
,
3065 num_defaults
= ppd_add_default("ImageableArea", "Letter", num_defaults
,
3071 * The rest default to "a4" size...
3074 num_defaults
= ppd_add_default("PageSize", "A4", num_defaults
,
3076 num_defaults
= ppd_add_default("PageRegion", "A4", num_defaults
,
3078 num_defaults
= ppd_add_default("PaperDimension", "A4", num_defaults
,
3080 num_defaults
= ppd_add_default("ImageableArea", "A4", num_defaults
,
3086 * Open the source and destination file for a copy...
3089 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3091 if (num_defaults
> 0)
3097 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3099 if (num_defaults
> 0)
3107 * Copy the source file to the destination...
3110 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3112 if (!strncmp(buffer
, "*Default", 8))
3115 * Check for an previous default option choice...
3118 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3119 choice
, sizeof(choice
)))
3121 for (i
= 0; i
< num_defaults
; i
++)
3122 if (!strcmp(option
, defaults
[i
].option
))
3125 * Substitute the previous choice...
3128 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
,
3129 defaults
[i
].choice
);
3135 cupsFilePrintf(dst
, "%s\n", buffer
);
3138 if (cups_protocol
[0])
3139 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
3141 if (num_defaults
> 0)
3145 * Close both files and return...
3150 return (cupsFileClose(dst
));
3155 * 'create_job()' - Print a file to a printer or class.
3159 create_job(client_t
*con
, /* I - Client connection */
3160 ipp_attribute_t
*uri
) /* I - Printer URI */
3162 ipp_attribute_t
*attr
; /* Current attribute */
3163 const char *dest
; /* Destination */
3164 cups_ptype_t dtype
; /* Destination type (printer or class) */
3165 int priority
; /* Job priority */
3166 char *title
; /* Job name/title */
3167 job_t
*job
; /* Current job */
3168 char job_uri
[HTTP_MAX_URI
], /* Job URI */
3169 method
[HTTP_MAX_URI
], /* Method portion of URI */
3170 username
[HTTP_MAX_URI
], /* Username portion of URI */
3171 host
[HTTP_MAX_URI
], /* Host portion of URI */
3172 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3173 int port
; /* Port portion of URI */
3174 printer_t
*printer
; /* Printer data */
3175 int kbytes
; /* Size of print file */
3176 int i
; /* Looping var */
3177 int lowerpagerange
; /* Page range bound */
3180 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3181 uri
->values
[0].string
.text
);
3184 * Verify that the POST operation was done to a valid URI.
3187 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3188 strncmp(con
->uri
, "/printers/", 10) != 0)
3190 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
3192 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3197 * Is the destination valid?
3200 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3202 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3208 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
3209 send_ipp_error(con
, IPP_NOT_FOUND
);
3217 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3219 LogMessage(L_ERROR
, "create_job: not authorized!");
3220 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3225 * See if the printer is accepting jobs...
3228 if (!printer
->accepting
)
3230 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
3232 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3237 * Validate job template attributes; for now just copies and page-ranges...
3240 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
3242 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
3244 LogMessage(L_INFO
, "create_job: bad copies value %d.",
3245 attr
->values
[0].integer
);
3246 send_ipp_error(con
, IPP_BAD_REQUEST
);
3251 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
3253 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
3255 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
3256 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3258 LogMessage(L_ERROR
, "create_job: bad page-ranges values %d-%d.",
3259 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3260 send_ipp_error(con
, IPP_BAD_REQUEST
);
3264 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
3269 * Make sure we aren't over our limit...
3272 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3275 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3277 LogMessage(L_INFO
, "create_job: too many jobs.");
3278 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3282 if (!check_quotas(con
, printer
))
3284 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3289 * Create the job and set things up...
3292 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3293 priority
= attr
->values
[0].integer
;
3295 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3298 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3299 title
= attr
->values
[0].string
.text
;
3301 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3302 title
= "Untitled");
3304 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3306 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
3308 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3313 job
->attrs
= con
->request
;
3314 con
->request
= NULL
;
3316 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3318 if (con
->username
[0])
3319 SetString(&job
->username
, con
->username
);
3320 else if (attr
!= NULL
)
3322 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
3323 attr
->values
[0].string
.text
);
3325 SetString(&job
->username
, attr
->values
[0].string
.text
);
3328 SetString(&job
->username
, "anonymous");
3331 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3332 NULL
, job
->username
);
3335 attr
->group_tag
= IPP_TAG_JOB
;
3336 SetString(&attr
->name
, "job-originating-user-name");
3339 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
3340 IPP_TAG_ZERO
)) != NULL
)
3343 * Request contains a job-originating-host-name attribute; validate it...
3346 if (attr
->value_tag
!= IPP_TAG_NAME
||
3347 attr
->num_values
!= 1 ||
3348 strcmp(con
->http
.hostname
, "localhost") != 0)
3351 * Can't override the value if we aren't connected via localhost.
3352 * Also, we can only have 1 value and it must be a name value.
3355 int i
; /* Looping var */
3357 switch (attr
->value_tag
)
3359 case IPP_TAG_STRING
:
3360 case IPP_TAG_TEXTLANG
:
3361 case IPP_TAG_NAMELANG
:
3364 case IPP_TAG_KEYWORD
:
3366 case IPP_TAG_URISCHEME
:
3367 case IPP_TAG_CHARSET
:
3368 case IPP_TAG_LANGUAGE
:
3369 case IPP_TAG_MIMETYPE
:
3371 * Free old strings...
3374 for (i
= 0; i
< attr
->num_values
; i
++)
3376 free(attr
->values
[i
].string
.text
);
3377 attr
->values
[i
].string
.text
= NULL
;
3378 if (attr
->values
[i
].string
.charset
)
3380 free(attr
->values
[i
].string
.charset
);
3381 attr
->values
[i
].string
.charset
= NULL
;
3390 * Use the default connection hostname instead...
3393 attr
->value_tag
= IPP_TAG_NAME
;
3394 attr
->num_values
= 1;
3395 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
3398 attr
->group_tag
= IPP_TAG_JOB
;
3403 * No job-originating-host-name attribute, so use the hostname from
3407 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3408 "job-originating-host-name", NULL
, con
->http
.hostname
);
3411 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3413 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3414 "time-at-processing", 0);
3415 attr
->value_tag
= IPP_TAG_NOVALUE
;
3416 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3417 "time-at-completed", 0);
3418 attr
->value_tag
= IPP_TAG_NOVALUE
;
3421 * Add remaining job attributes...
3424 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3425 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3426 "job-state", IPP_JOB_STOPPED
);
3427 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3428 "job-media-sheets-completed", 0);
3429 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3431 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3434 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3435 attr
->values
[0].integer
= 0;
3437 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3440 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3441 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3443 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
3444 "job-hold-until", NULL
, "no-hold");
3445 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
3446 !(printer
->type
& CUPS_PRINTER_REMOTE
))
3449 * Hold job until specified time...
3452 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3455 job
->hold_until
= time(NULL
) + 60;
3457 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
3459 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
3463 * Add job sheets options...
3466 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
3468 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
3469 printer
->job_sheets
[0], printer
->job_sheets
[1]);
3471 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
3473 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
3474 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
3477 job
->job_sheets
= attr
;
3480 * Enforce classification level if set...
3485 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
3486 Classification
? Classification
: "(null)", ClassifyOverride
);
3488 if (ClassifyOverride
)
3490 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
3491 (attr
->num_values
== 1 ||
3492 strcmp(attr
->values
[1].string
.text
, "none") == 0))
3495 * Force the leading banner to have the classification on it...
3498 SetString(&attr
->values
[0].string
.text
, Classification
);
3500 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3501 "job-sheets=\"%s,none\", "
3502 "job-originating-user-name=\"%s\"",
3503 job
->id
, Classification
,
3506 else if (attr
->num_values
== 2 &&
3507 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
3508 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
3509 strcmp(attr
->values
[1].string
.text
, "none") != 0)
3512 * Can't put two different security markings on the same document!
3515 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
3517 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3518 "job-sheets=\"%s,%s\", "
3519 "job-originating-user-name=\"%s\"",
3520 job
->id
, attr
->values
[0].string
.text
,
3521 attr
->values
[1].string
.text
,
3524 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
3525 strcmp(attr
->values
[0].string
.text
, "none") &&
3526 (attr
->num_values
== 1 ||
3527 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
3528 strcmp(attr
->values
[1].string
.text
, "none"))))
3530 if (attr
->num_values
== 1)
3531 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3532 "job-sheets=\"%s\", "
3533 "job-originating-user-name=\"%s\"",
3534 job
->id
, attr
->values
[0].string
.text
,
3537 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3538 "job-sheets=\"%s,%s\",fffff "
3539 "job-originating-user-name=\"%s\"",
3540 job
->id
, attr
->values
[0].string
.text
,
3541 attr
->values
[1].string
.text
,
3545 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
3546 (attr
->num_values
== 1 ||
3547 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
3550 * Force the banner to have the classification on it...
3553 if (attr
->num_values
> 1 &&
3554 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
3556 SetString(&(attr
->values
[0].string
.text
), Classification
);
3557 SetString(&(attr
->values
[1].string
.text
), Classification
);
3561 if (attr
->num_values
== 1 ||
3562 strcmp(attr
->values
[0].string
.text
, "none"))
3563 SetString(&(attr
->values
[0].string
.text
), Classification
);
3565 if (attr
->num_values
> 1 &&
3566 strcmp(attr
->values
[1].string
.text
, "none"))
3567 SetString(&(attr
->values
[1].string
.text
), Classification
);
3570 if (attr
->num_values
> 1)
3571 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3572 "job-sheets=\"%s,%s\", "
3573 "job-originating-user-name=\"%s\"",
3574 job
->id
, attr
->values
[0].string
.text
,
3575 attr
->values
[1].string
.text
,
3578 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3579 "job-sheets=\"%s\", "
3580 "job-originating-user-name=\"%s\"",
3581 job
->id
, Classification
,
3587 * See if we need to add the starting sheet...
3590 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
3592 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
3593 attr
->values
[0].string
.text
, job
->id
);
3595 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
3597 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3600 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
3604 * Add any job subscriptions...
3607 add_job_subscriptions(con
, job
);
3610 * Set all but the first two attributes to the job attributes group...
3613 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
3614 attr
->group_tag
= IPP_TAG_JOB
;
3617 * Save and log the job...
3622 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
3623 job
->dest
, job
->username
);
3625 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
3628 * Fill in the response info...
3631 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3632 LocalPort
, job
->id
);
3634 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
3636 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3638 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
3639 job
->state
->values
[0].integer
);
3641 con
->response
->request
.status
.status_code
= IPP_OK
;
3646 * 'create_subscription()' - Create a notification subscription.
3650 create_subscription(
3651 client_t
*con
, /* I - Client connection */
3652 ipp_attribute_t
*uri
) /* I - Printer URI */
3658 * 'delete_printer()' - Remove a printer or class from the system.
3662 delete_printer(client_t
*con
, /* I - Client connection */
3663 ipp_attribute_t
*uri
) /* I - URI of printer or class */
3665 const char *dest
; /* Destination */
3666 cups_ptype_t dtype
; /* Destination type (printer or class) */
3667 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3668 username
[HTTP_MAX_URI
], /* Username portion of URI */
3669 host
[HTTP_MAX_URI
], /* Host portion of URI */
3670 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3671 int port
; /* Port portion of URI */
3672 printer_t
*printer
; /* Printer/class */
3673 char filename
[1024]; /* Script/PPD filename */
3676 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
3677 uri
->values
[0].string
.text
);
3680 * Was this operation called from the correct URI?
3683 if (strncmp(con
->uri
, "/admin/", 7) != 0)
3685 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
3687 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3692 * Do we have a valid URI?
3695 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3697 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3703 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
3704 send_ipp_error(con
, IPP_NOT_FOUND
);
3712 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3714 LogMessage(L_ERROR
, "delete_printer: not authorized!");
3715 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3720 * Remove old jobs...
3723 CancelJobs(dest
, NULL
, 1);
3726 * Remove old subscriptions and send a "deleted printer" event...
3729 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
3730 "%s \'%s\' deleted by \'%s\'.",
3731 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
3732 dest
, con
->username
);
3734 cupsdExpireSubscriptions(printer
, NULL
);
3737 * Remove any old PPD or script files...
3740 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
3743 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
3746 if (dtype
& CUPS_PRINTER_CLASS
)
3748 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
3751 DeletePrinter(printer
, 0);
3756 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
3759 DeletePrinter(printer
, 0);
3764 * Return with no errors...
3767 con
->response
->request
.status
.status_code
= IPP_OK
;
3772 * 'get_default()' - Get the default destination.
3776 get_default(client_t
*con
) /* I - Client connection */
3778 int i
; /* Looping var */
3779 ipp_attribute_t
*requested
, /* requested-attributes */
3780 *history
; /* History collection */
3781 int need_history
; /* Need to send history collection? */
3784 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
3790 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3792 LogMessage(L_ERROR
, "get_default: not authorized!");
3793 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3797 if (DefaultPrinter
!= NULL
)
3799 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3802 copy_attrs(con
->response
, DefaultPrinter
->attrs
, requested
, IPP_TAG_ZERO
, 0);
3803 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
3807 if (MaxPrinterHistory
> 0 && DefaultPrinter
->num_history
> 0 && requested
)
3809 for (i
= 0; i
< requested
->num_values
; i
++)
3810 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
3811 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
3820 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
3821 "printer-state-history",
3822 DefaultPrinter
->num_history
, NULL
);
3824 for (i
= 0; i
< DefaultPrinter
->num_history
; i
++)
3825 copy_attrs(history
->values
[i
].collection
= ippNew(),
3826 DefaultPrinter
->history
[i
],
3827 NULL
, IPP_TAG_ZERO
, 0);
3830 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
3833 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
3838 * 'get_devices()' - Get the list of available devices on the local system.
3842 get_devices(client_t
*con
) /* I - Client connection */
3844 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
3850 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3852 LogMessage(L_ERROR
, "get_devices: not authorized!");
3853 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3858 * Copy the device attributes to the response using the requested-attributes
3859 * attribute that may be provided by the client.
3862 copy_attrs(con
->response
, Devices
,
3863 ippFindAttribute(con
->request
, "requested-attributes",
3864 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
, IPP_TAG_COPY
);
3866 con
->response
->request
.status
.status_code
= IPP_OK
;
3871 * 'get_jobs()' - Get a list of jobs for the specified printer.
3875 get_jobs(client_t
*con
, /* I - Client connection */
3876 ipp_attribute_t
*uri
) /* I - Printer URI */
3878 ipp_attribute_t
*attr
, /* Current attribute */
3879 *requested
; /* Requested attributes */
3880 const char *dest
; /* Destination */
3881 cups_ptype_t dtype
; /* Destination type (printer or class) */
3882 cups_ptype_t dmask
; /* Destination type mask */
3883 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3884 username
[HTTP_MAX_URI
], /* Username portion of URI */
3885 host
[HTTP_MAX_URI
], /* Host portion of URI */
3886 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3887 int port
; /* Port portion of URI */
3888 int completed
; /* Completed jobs? */
3889 int limit
; /* Maximum number of jobs to return */
3890 int count
; /* Number of jobs that match */
3891 job_t
*job
; /* Current job pointer */
3892 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
3893 printer_t
*printer
; /* Printer */
3896 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
3897 uri
->values
[0].string
.text
);
3900 * Is the destination valid?
3903 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3905 if (strcmp(resource
, "/") == 0 ||
3906 (strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6))
3909 dtype
= (cups_ptype_t
)0;
3910 dmask
= (cups_ptype_t
)0;
3913 else if (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10)
3916 dtype
= (cups_ptype_t
)0;
3917 dmask
= CUPS_PRINTER_CLASS
;
3920 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
3923 dtype
= CUPS_PRINTER_CLASS
;
3924 dmask
= CUPS_PRINTER_CLASS
;
3927 else if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3933 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
3934 send_ipp_error(con
, IPP_NOT_FOUND
);
3938 dmask
= CUPS_PRINTER_CLASS
;
3946 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3948 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3949 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3953 else if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3955 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3956 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3961 * See if the "which-jobs" attribute have been specified...
3964 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
3965 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
3971 * See if they want to limit the number of jobs reported...
3974 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
3975 limit
= attr
->values
[0].integer
;
3980 * See if we only want to see jobs for a specific user...
3983 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
3984 attr
->values
[0].boolean
)
3986 if (con
->username
[0])
3987 strlcpy(username
, con
->username
, sizeof(username
));
3988 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
3989 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
3991 strcpy(username
, "anonymous");
3996 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4000 * OK, build a list of jobs for this printer...
4003 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
4006 * Filter out jobs that don't match...
4009 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
4011 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0) &&
4012 (job
->printer
== NULL
|| dest
== NULL
||
4013 strcmp(job
->printer
->name
, dest
) != 0))
4015 if ((job
->dtype
& dmask
) != dtype
&&
4016 (job
->printer
== NULL
|| (job
->printer
->type
& dmask
) != dtype
))
4018 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
4021 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
4023 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4028 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
4031 * Send the requested attributes for each job...
4034 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4035 LocalPort
, job
->id
);
4037 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4038 "job-more-info", NULL
, job_uri
);
4040 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4041 "job-uri", NULL
, job_uri
);
4043 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4044 "job-printer-up-time", time(NULL
));
4047 * Copy the job attributes to the response using the requested-attributes
4048 * attribute that may be provided by the client.
4051 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4053 add_job_state_reasons(con
, job
);
4055 ippAddSeparator(con
->response
);
4058 if (requested
!= NULL
)
4059 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4061 con
->response
->request
.status
.status_code
= IPP_OK
;
4066 * 'get_job_attrs()' - Get job attributes.
4070 get_job_attrs(client_t
*con
, /* I - Client connection */
4071 ipp_attribute_t
*uri
) /* I - Job URI */
4073 ipp_attribute_t
*attr
, /* Current attribute */
4074 *requested
; /* Requested attributes */
4075 int jobid
; /* Job ID */
4076 job_t
*job
; /* Current job */
4077 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4078 username
[HTTP_MAX_URI
], /* Username portion of URI */
4079 host
[HTTP_MAX_URI
], /* Host portion of URI */
4080 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4081 int port
; /* Port portion of URI */
4082 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4085 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4086 uri
->values
[0].string
.text
);
4089 * See if we have a job URI or a printer URI...
4092 if (strcmp(uri
->name
, "printer-uri") == 0)
4095 * Got a printer URI; see if we also have a job-id attribute...
4098 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4100 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
4101 send_ipp_error(con
, IPP_BAD_REQUEST
);
4105 jobid
= attr
->values
[0].integer
;
4110 * Got a job URI; parse it to get the job ID...
4113 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4115 if (strncmp(resource
, "/jobs/", 6) != 0)
4121 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
4122 uri
->values
[0].string
.text
);
4123 send_ipp_error(con
, IPP_BAD_REQUEST
);
4127 jobid
= atoi(resource
+ 6);
4131 * See if the job exists...
4134 if ((job
= FindJob(jobid
)) == NULL
)
4137 * Nope - return a "not found" error...
4140 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
4141 send_ipp_error(con
, IPP_NOT_FOUND
);
4149 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4151 LogMessage(L_ERROR
, "get_job_attrs: not authorized!");
4152 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4157 * Put out the standard attributes...
4160 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
4161 ServerName
, LocalPort
, job
->id
);
4163 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4165 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4166 "job-more-info", NULL
, job_uri
);
4168 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4169 "job-uri", NULL
, job_uri
);
4171 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4172 "job-printer-up-time", time(NULL
));
4175 * Copy the job attributes to the response using the requested-attributes
4176 * attribute that may be provided by the client.
4179 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4182 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4184 add_job_state_reasons(con
, job
);
4186 if (requested
!= NULL
)
4187 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4189 con
->response
->request
.status
.status_code
= IPP_OK
;
4194 * 'get_notifications()' - Get events for a subscription.
4198 get_notifications(client_t
*con
, /* I - Client connection */
4199 int id
) /* I - Subscription ID */
4205 * 'get_ppds()' - Get the list of PPD files on the local system.
4209 get_ppds(client_t
*con
) /* I - Client connection */
4211 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
4217 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4219 LogMessage(L_ERROR
, "get_ppds: not authorized!");
4220 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4225 * Copy the PPD attributes to the response using the requested-attributes
4226 * attribute that may be provided by the client.
4229 copy_attrs(con
->response
, PPDs
,
4230 ippFindAttribute(con
->request
, "requested-attributes",
4231 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
, IPP_TAG_COPY
);
4233 con
->response
->request
.status
.status_code
= IPP_OK
;
4238 * 'get_printer_attrs()' - Get printer attributes.
4242 get_printer_attrs(client_t
*con
, /* I - Client connection */
4243 ipp_attribute_t
*uri
) /* I - Printer URI */
4245 const char *dest
; /* Destination */
4246 cups_ptype_t dtype
; /* Destination type (printer or class) */
4247 char method
[HTTP_MAX_URI
],
4248 /* Method portion of URI */
4249 username
[HTTP_MAX_URI
],
4250 /* Username portion of URI */
4252 /* Host portion of URI */
4253 resource
[HTTP_MAX_URI
];
4254 /* Resource portion of URI */
4255 int port
; /* Port portion of URI */
4256 printer_t
*printer
; /* Printer/class */
4257 time_t curtime
; /* Current time */
4258 int i
; /* Looping var */
4259 ipp_attribute_t
*requested
, /* requested-attributes */
4260 *history
; /* History collection */
4261 int need_history
; /* Need to send history collection? */
4264 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4265 uri
->values
[0].string
.text
);
4268 * Is the destination valid?
4271 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4273 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4279 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
4280 send_ipp_error(con
, IPP_NOT_FOUND
);
4288 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4290 LogMessage(L_ERROR
, "get_printer_attrs: not authorized!");
4291 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4295 curtime
= time(NULL
);
4298 * Copy the printer attributes to the response using requested-attributes
4299 * and document-format attributes that may be provided by the client.
4302 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4305 add_printer_state_reasons(con
, printer
);
4307 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4308 "printer-state-message", NULL
, printer
->state_message
);
4310 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4311 printer
->accepting
);
4313 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4314 "printer-up-time", curtime
);
4315 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4316 "printer-state-time", printer
->state_time
);
4317 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4318 ippTimeToDate(curtime
));
4320 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4321 "printer-error-policy", NULL
, printer
->op_policy
);
4322 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4323 "printer-op-policy", NULL
, printer
->op_policy
);
4325 add_queued_job_count(con
, printer
);
4327 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4330 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4331 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4335 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 && requested
)
4337 for (i
= 0; i
< requested
->num_values
; i
++)
4338 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4339 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4348 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4349 "printer-state-history",
4350 printer
->num_history
, NULL
);
4352 for (i
= 0; i
< printer
->num_history
; i
++)
4353 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4354 NULL
, IPP_TAG_ZERO
, 0);
4357 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4362 * 'get_printers()' - Get a list of printers or classes.
4366 get_printers(client_t
*con
, /* I - Client connection */
4367 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
4369 int i
; /* Looping var */
4370 ipp_attribute_t
*requested
, /* requested-attributes */
4371 *history
, /* History collection */
4372 *attr
; /* Current attribute */
4373 int need_history
; /* Need to send history collection? */
4374 int limit
; /* Maximum number of printers to return */
4375 int count
; /* Number of printers that match */
4376 printer_t
*printer
; /* Current printer pointer */
4377 time_t curtime
; /* Current time */
4378 int printer_type
, /* printer-type attribute */
4379 printer_mask
; /* printer-type-mask attribute */
4380 char *location
; /* Location string */
4381 char name
[IPP_MAX_NAME
], /* Printer name */
4382 *nameptr
; /* Pointer into name */
4383 printer_t
*iclass
; /* Implicit class */
4384 const char *username
; /* Current user */
4387 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
4393 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4395 LogMessage(L_ERROR
, "get_printers: not authorized!");
4396 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4401 * See if they want to limit the number of printers reported...
4404 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4405 limit
= attr
->values
[0].integer
;
4410 * Support filtering...
4413 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
4414 printer_type
= attr
->values
[0].integer
;
4418 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
4419 printer_mask
= attr
->values
[0].integer
;
4423 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
4424 location
= attr
->values
[0].string
.text
;
4428 if (con
->username
[0])
4429 username
= con
->username
;
4430 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4431 username
= attr
->values
[0].string
.text
;
4435 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4440 if (MaxPrinterHistory
> 0 && requested
)
4442 for (i
= 0; i
< requested
->num_values
; i
++)
4443 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4444 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4452 * OK, build a list of printers for this printer...
4455 curtime
= time(NULL
);
4457 for (count
= 0, printer
= Printers
;
4458 count
< limit
&& printer
!= NULL
;
4459 printer
= printer
->next
)
4460 if ((printer
->type
& CUPS_PRINTER_CLASS
) == type
&&
4461 (printer
->type
& printer_mask
) == printer_type
&&
4462 (location
== NULL
|| printer
->location
== NULL
||
4463 strcasecmp(printer
->location
, location
) == 0))
4466 * If HideImplicitMembers is enabled, see if this printer or class
4467 * is a member of an implicit class...
4470 if (ImplicitClasses
&& HideImplicitMembers
&&
4471 (printer
->type
& CUPS_PRINTER_REMOTE
))
4474 * Make a copy of the printer name...
4477 strlcpy(name
, printer
->name
, sizeof(name
));
4479 if ((nameptr
= strchr(name
, '@')) != NULL
)
4482 * Strip trailing @server...
4488 * Find the core printer, if any...
4491 if ((iclass
= FindPrinter(name
)) != NULL
&&
4492 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
4498 * If a username is specified, see if it is allowed or denied
4502 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
4506 * Add the group separator as needed...
4510 ippAddSeparator(con
->response
);
4515 * Send the following attributes for each printer:
4518 * printer-state-message
4519 * printer-is-accepting-jobs
4520 * + all printer attributes
4523 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
4524 "printer-state", printer
->state
);
4526 add_printer_state_reasons(con
, printer
);
4528 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4529 "printer-state-message", NULL
, printer
->state_message
);
4531 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4532 printer
->accepting
);
4534 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4535 "printer-up-time", curtime
);
4536 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4537 "printer-state-time", printer
->state_time
);
4538 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4539 ippTimeToDate(curtime
));
4541 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4542 "printer-error-policy", NULL
, printer
->op_policy
);
4543 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4544 "printer-op-policy", NULL
, printer
->op_policy
);
4546 add_queued_job_count(con
, printer
);
4548 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4550 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
,
4553 if (need_history
&& printer
->num_history
> 0)
4555 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4556 "printer-state-history",
4557 printer
->num_history
, NULL
);
4559 for (i
= 0; i
< printer
->num_history
; i
++)
4560 copy_attrs(history
->values
[i
].collection
= ippNew(),
4561 printer
->history
[i
], NULL
, IPP_TAG_ZERO
, 0);
4565 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4570 * 'get_subscription_attrs()' - Get subscription attributes.
4574 get_subscription_attrs(client_t
*con
, /* I - Client connection */
4575 int sub_id
) /* I - Subscription ID */
4581 * 'get_subscriptions()' - Get subscriptions.
4585 get_subscriptions(client_t
*con
, /* I - Client connection */
4586 ipp_attribute_t
*uri
) /* I - Printer URI */
4592 * 'hold_job()' - Hold a print job.
4596 hold_job(client_t
*con
, /* I - Client connection */
4597 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4599 ipp_attribute_t
*attr
, /* Current job-hold-until */
4600 *newattr
; /* New job-hold-until */
4601 int jobid
; /* Job ID */
4602 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4603 username
[HTTP_MAX_URI
], /* Username portion of URI */
4604 host
[HTTP_MAX_URI
], /* Host portion of URI */
4605 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4606 int port
; /* Port portion of URI */
4607 job_t
*job
; /* Job information */
4610 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4611 uri
->values
[0].string
.text
);
4614 * Verify that the POST operation was done to a valid URI.
4617 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4618 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4619 strncmp(con
->uri
, "/printers/", 10) != 0)
4621 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
4623 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4628 * See if we have a job URI or a printer URI...
4631 if (strcmp(uri
->name
, "printer-uri") == 0)
4634 * Got a printer URI; see if we also have a job-id attribute...
4637 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4639 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
4640 send_ipp_error(con
, IPP_BAD_REQUEST
);
4644 jobid
= attr
->values
[0].integer
;
4649 * Got a job URI; parse it to get the job ID...
4652 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4654 if (strncmp(resource
, "/jobs/", 6) != 0)
4660 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
4661 uri
->values
[0].string
.text
);
4662 send_ipp_error(con
, IPP_BAD_REQUEST
);
4666 jobid
= atoi(resource
+ 6);
4670 * See if the job exists...
4673 if ((job
= FindJob(jobid
)) == NULL
)
4676 * Nope - return a "not found" error...
4679 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
4680 send_ipp_error(con
, IPP_NOT_FOUND
);
4685 * See if the job is owned by the requesting user...
4688 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4690 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
4691 username
, jobid
, job
->username
);
4692 send_ipp_error(con
, IPP_FORBIDDEN
);
4697 * Hold the job and return...
4702 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4703 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
4705 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4706 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4711 * Free the old hold value and copy the new one over...
4714 free(attr
->values
[0].string
.text
);
4716 if (newattr
!= NULL
)
4718 attr
->value_tag
= newattr
->value_tag
;
4719 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
4723 attr
->value_tag
= IPP_TAG_KEYWORD
;
4724 attr
->values
[0].string
.text
= strdup("indefinite");
4728 * Hold job until specified time...
4731 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4734 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
4736 con
->response
->request
.status
.status_code
= IPP_OK
;
4741 * 'move_job()' - Move a job to a new destination.
4745 move_job(client_t
*con
, /* I - Client connection */
4746 ipp_attribute_t
*uri
) /* I - Job URI */
4748 ipp_attribute_t
*attr
; /* Current attribute */
4749 int jobid
; /* Job ID */
4750 job_t
*job
; /* Current job */
4751 const char *dest
; /* Destination */
4752 cups_ptype_t dtype
; /* Destination type (printer or class) */
4753 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4754 username
[HTTP_MAX_URI
], /* Username portion of URI */
4755 host
[HTTP_MAX_URI
], /* Host portion of URI */
4756 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4757 int port
; /* Port portion of URI */
4758 printer_t
*printer
; /* Printer */
4761 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4762 uri
->values
[0].string
.text
);
4765 * See if we have a job URI or a printer URI...
4768 if (strcmp(uri
->name
, "printer-uri") == 0)
4771 * Got a printer URI; see if we also have a job-id attribute...
4774 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4776 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
4777 send_ipp_error(con
, IPP_BAD_REQUEST
);
4781 jobid
= attr
->values
[0].integer
;
4786 * Got a job URI; parse it to get the job ID...
4789 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4791 if (strncmp(resource
, "/jobs/", 6) != 0)
4797 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
4798 uri
->values
[0].string
.text
);
4799 send_ipp_error(con
, IPP_BAD_REQUEST
);
4803 jobid
= atoi(resource
+ 6);
4807 * See if the job exists...
4810 if ((job
= FindJob(jobid
)) == NULL
)
4813 * Nope - return a "not found" error...
4816 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
4817 send_ipp_error(con
, IPP_NOT_FOUND
);
4822 * See if the job has been completed...
4825 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4828 * Return a "not-possible" error...
4831 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
4832 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4837 * See if the job is owned by the requesting user...
4840 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4842 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
4843 username
, jobid
, job
->username
);
4844 send_ipp_error(con
, IPP_FORBIDDEN
);
4848 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
4851 * Need job-printer-uri...
4854 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
4855 send_ipp_error(con
, IPP_BAD_REQUEST
);
4860 * Get the new printer or class...
4863 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
4865 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4871 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
4872 send_ipp_error(con
, IPP_NOT_FOUND
);
4880 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4882 LogMessage(L_ERROR
, "move_job: not authorized!");
4883 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4888 * Move the job to a different printer or class...
4891 MoveJob(jobid
, dest
);
4894 * Start jobs if possible...
4900 * Return with "everything is OK" status...
4903 con
->response
->request
.status
.status_code
= IPP_OK
;
4908 * 'ppd_add_default()' - Add a PPD default choice.
4911 static int /* O - Number of defaults */
4913 const char *option
, /* I - Option name */
4914 const char *choice
, /* I - Choice name */
4915 int num_defaults
, /* I - Number of defaults */
4916 ppd_default_t
**defaults
) /* IO - Defaults */
4918 int i
; /* Looping var */
4919 ppd_default_t
*temp
; /* Temporary defaults array */
4923 * First check if the option already has a default value; the PPD spec
4924 * says that the first one is used...
4927 for (i
= 0, temp
= *defaults
; i
< num_defaults
; i
++)
4928 if (!strcmp(option
, temp
[i
].option
))
4929 return (num_defaults
);
4932 * Now add the option...
4935 if (num_defaults
== 0)
4936 temp
= malloc(sizeof(ppd_default_t
));
4938 temp
= realloc(*defaults
, (num_defaults
+ 1) * sizeof(ppd_default_t
));
4942 LogMessage(L_ERROR
, "ppd_add_default: Unable to add default value for \"%s\" - %s",
4943 option
, strerror(errno
));
4944 return (num_defaults
);
4948 temp
+= num_defaults
;
4950 strlcpy(temp
->option
, option
, sizeof(temp
->option
));
4951 strlcpy(temp
->choice
, choice
, sizeof(temp
->choice
));
4953 return (num_defaults
+ 1);
4958 * 'ppd_parse_line()' - Parse a PPD default line.
4961 static int /* O - 0 on success, -1 on failure */
4962 ppd_parse_line(const char *line
, /* I - Line */
4963 char *option
, /* O - Option name */
4964 int olen
, /* I - Size of option name */
4965 char *choice
, /* O - Choice name */
4966 int clen
) /* I - Size of choice name */
4969 * Verify this is a default option line...
4972 if (strncmp(line
, "*Default", 8))
4976 * Read the option name...
4979 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
4989 * Skip everything else up to the colon (:)...
4992 while (*line
&& *line
!= ':')
5001 * Now grab the option choice, skipping leading whitespace...
5004 while (isspace(*line
& 255))
5007 for (clen
--; isalnum(*line
& 255); line
++)
5017 * Return with no errors...
5025 * 'print_job()' - Print a file to a printer or class.
5029 print_job(client_t
*con
, /* I - Client connection */
5030 ipp_attribute_t
*uri
) /* I - Printer URI */
5032 ipp_attribute_t
*attr
; /* Current attribute */
5033 ipp_attribute_t
*format
; /* Document-format attribute */
5034 const char *dest
; /* Destination */
5035 cups_ptype_t dtype
; /* Destination type (printer or class) */
5036 int priority
; /* Job priority */
5037 char *title
; /* Job name/title */
5038 job_t
*job
; /* Current job */
5039 int jobid
; /* Job ID number */
5040 char job_uri
[HTTP_MAX_URI
], /* Job URI */
5041 method
[HTTP_MAX_URI
], /* Method portion of URI */
5042 username
[HTTP_MAX_URI
], /* Username portion of URI */
5043 host
[HTTP_MAX_URI
], /* Host portion of URI */
5044 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5045 filename
[1024]; /* Job filename */
5046 int port
; /* Port portion of URI */
5047 mime_type_t
*filetype
; /* Type of file */
5048 char super
[MIME_MAX_SUPER
], /* Supertype of file */
5049 type
[MIME_MAX_TYPE
], /* Subtype of file */
5050 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
5051 /* Textual name of mime type */
5052 printer_t
*printer
; /* Printer data */
5053 struct stat fileinfo
; /* File information */
5054 int kbytes
; /* Size of file */
5055 int i
; /* Looping var */
5056 int lowerpagerange
; /* Page range bound */
5057 int compression
; /* Document compression */
5060 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5061 uri
->values
[0].string
.text
);
5064 * Verify that the POST operation was done to a valid URI.
5067 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5068 strncmp(con
->uri
, "/printers/", 10) != 0)
5070 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
5072 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5077 * Validate job template attributes; for now just copies and page-ranges...
5080 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
5082 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
5084 LogMessage(L_INFO
, "print_job: bad copies value %d.",
5085 attr
->values
[0].integer
);
5086 send_ipp_error(con
, IPP_BAD_REQUEST
);
5091 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
5093 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
5095 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
5096 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5098 LogMessage(L_ERROR
, "print_job: bad page-ranges values %d-%d.",
5099 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
5100 send_ipp_error(con
, IPP_BAD_REQUEST
);
5104 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
5109 * OK, see if the client is sending the document compressed - CUPS
5110 * only supports "none" and "gzip".
5113 compression
= CUPS_FILE_NONE
;
5115 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
5117 if (strcmp(attr
->values
[0].string
.text
, "none")
5119 && strcmp(attr
->values
[0].string
.text
, "gzip")
5120 #endif /* HAVE_LIBZ */
5123 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
5124 attr
->values
[0].string
.text
);
5125 send_ipp_error(con
, IPP_ATTRIBUTES
);
5126 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5127 "compression", NULL
, attr
->values
[0].string
.text
);
5132 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
5133 compression
= CUPS_FILE_GZIP
;
5134 #endif /* HAVE_LIBZ */
5138 * Do we have a file to print?
5143 LogMessage(L_ERROR
, "print_job: No file!?!");
5144 send_ipp_error(con
, IPP_BAD_REQUEST
);
5149 * Is it a format we support?
5152 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5155 * Grab format from client...
5158 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5160 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
5161 format
->values
[0].string
.text
);
5162 send_ipp_error(con
, IPP_BAD_REQUEST
);
5169 * No document format attribute? Auto-type it!
5172 strcpy(super
, "application");
5173 strcpy(type
, "octet-stream");
5176 if (strcmp(super
, "application") == 0 &&
5177 strcmp(type
, "octet-stream") == 0)
5180 * Auto-type the file...
5183 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
5185 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
5187 if (filetype
!= NULL
)
5190 * Replace the document-format attribute value with the auto-typed one.
5193 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
5198 free(format
->values
[0].string
.text
);
5199 format
->values
[0].string
.text
= strdup(mimetype
);
5202 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
5203 "document-format", NULL
, mimetype
);
5206 filetype
= mimeType(MimeDatabase
, super
, type
);
5209 filetype
= mimeType(MimeDatabase
, super
, type
);
5211 if (filetype
== NULL
)
5213 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
5215 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
5216 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5219 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5220 "document-format", NULL
, format
->values
[0].string
.text
);
5225 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
5226 filetype
->super
, filetype
->type
);
5229 * Read any embedded job ticket info from PS files...
5232 if (strcasecmp(filetype
->super
, "application") == 0 &&
5233 strcasecmp(filetype
->type
, "postscript") == 0)
5234 read_ps_job_ticket(con
);
5237 * Is the destination valid?
5240 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5242 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5248 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
5249 send_ipp_error(con
, IPP_NOT_FOUND
);
5257 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5259 LogMessage(L_ERROR
, "print_job: not authorized!");
5260 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5265 * See if the printer is accepting jobs...
5268 if (!printer
->accepting
)
5270 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
5272 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
5277 * Make sure we aren't over our limit...
5280 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5283 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5285 LogMessage(L_INFO
, "print_job: too many jobs - %d jobs, max jobs is %d.",
5287 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5291 if (!check_quotas(con
, printer
))
5293 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5298 * Create the job and set things up...
5301 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
5302 priority
= attr
->values
[0].integer
;
5304 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
5307 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
5308 title
= attr
->values
[0].string
.text
;
5310 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5311 title
= "Untitled");
5313 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
5315 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
5317 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
5322 job
->attrs
= con
->request
;
5323 con
->request
= NULL
;
5326 * Copy the rest of the job info...
5329 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
5331 if (con
->username
[0])
5332 SetString(&job
->username
, con
->username
);
5333 else if (attr
!= NULL
)
5335 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
5336 attr
->values
[0].string
.text
);
5338 SetString(&job
->username
, attr
->values
[0].string
.text
);
5341 SetString(&job
->username
, "anonymous");
5344 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
5345 NULL
, job
->username
);
5348 attr
->group_tag
= IPP_TAG_JOB
;
5349 SetString(&attr
->name
, "job-originating-user-name");
5353 * Add remaining job attributes...
5356 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
5357 IPP_TAG_ZERO
)) != NULL
)
5360 * Request contains a job-originating-host-name attribute; validate it...
5363 if (attr
->value_tag
!= IPP_TAG_NAME
||
5364 attr
->num_values
!= 1 ||
5365 strcmp(con
->http
.hostname
, "localhost") != 0)
5368 * Can't override the value if we aren't connected via localhost.
5369 * Also, we can only have 1 value and it must be a name value.
5372 int i
; /* Looping var */
5374 switch (attr
->value_tag
)
5376 case IPP_TAG_STRING
:
5377 case IPP_TAG_TEXTLANG
:
5378 case IPP_TAG_NAMELANG
:
5381 case IPP_TAG_KEYWORD
:
5383 case IPP_TAG_URISCHEME
:
5384 case IPP_TAG_CHARSET
:
5385 case IPP_TAG_LANGUAGE
:
5386 case IPP_TAG_MIMETYPE
:
5388 * Free old strings...
5391 for (i
= 0; i
< attr
->num_values
; i
++)
5393 free(attr
->values
[i
].string
.text
);
5394 attr
->values
[i
].string
.text
= NULL
;
5395 if (attr
->values
[i
].string
.charset
)
5397 free(attr
->values
[i
].string
.charset
);
5398 attr
->values
[i
].string
.charset
= NULL
;
5407 * Use the default connection hostname instead...
5410 attr
->value_tag
= IPP_TAG_NAME
;
5411 attr
->num_values
= 1;
5412 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
5415 attr
->group_tag
= IPP_TAG_JOB
;
5420 * No job-originating-host-name attribute, so use the hostname from
5424 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
5425 "job-originating-host-name", NULL
, con
->http
.hostname
);
5428 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
5429 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
5430 "job-state", IPP_JOB_PENDING
);
5431 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5432 "job-media-sheets-completed", 0);
5433 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
5435 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5438 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
5439 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5442 if (stat(con
->filename
, &fileinfo
))
5445 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
5447 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5448 attr
->values
[0].integer
+= kbytes
;
5450 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
5452 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5453 "time-at-processing", 0);
5454 attr
->value_tag
= IPP_TAG_NOVALUE
;
5455 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5456 "time-at-completed", 0);
5457 attr
->value_tag
= IPP_TAG_NOVALUE
;
5459 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5460 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
5462 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
5463 "job-hold-until", NULL
, "no-hold");
5465 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
5466 !(printer
->type
& CUPS_PRINTER_REMOTE
))
5469 * Hold job until specified time...
5472 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
5473 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5476 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
5480 * Add job sheets options...
5483 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
5485 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
5486 printer
->job_sheets
[0], printer
->job_sheets
[1]);
5488 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
5490 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
5491 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
5494 job
->job_sheets
= attr
;
5497 * Enforce classification level if set...
5502 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
5503 Classification
? Classification
: "(null)", ClassifyOverride
);
5505 if (ClassifyOverride
)
5507 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
5508 (attr
->num_values
== 1 ||
5509 strcmp(attr
->values
[1].string
.text
, "none") == 0))
5512 * Force the leading banner to have the classification on it...
5515 SetString(&attr
->values
[0].string
.text
, Classification
);
5517 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5518 "job-sheets=\"%s,none\", "
5519 "job-originating-user-name=\"%s\"",
5520 job
->id
, Classification
,
5523 else if (attr
->num_values
== 2 &&
5524 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
5525 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
5526 strcmp(attr
->values
[1].string
.text
, "none") != 0)
5529 * Can't put two different security markings on the same document!
5532 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
5534 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5535 "job-sheets=\"%s,%s\", "
5536 "job-originating-user-name=\"%s\"",
5537 job
->id
, attr
->values
[0].string
.text
,
5538 attr
->values
[1].string
.text
,
5541 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
5542 strcmp(attr
->values
[0].string
.text
, "none") &&
5543 (attr
->num_values
== 1 ||
5544 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
5545 strcmp(attr
->values
[1].string
.text
, "none"))))
5547 if (attr
->num_values
== 1)
5548 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5549 "job-sheets=\"%s\", "
5550 "job-originating-user-name=\"%s\"",
5551 job
->id
, attr
->values
[0].string
.text
,
5554 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5555 "job-sheets=\"%s,%s\", "
5556 "job-originating-user-name=\"%s\"",
5557 job
->id
, attr
->values
[0].string
.text
,
5558 attr
->values
[1].string
.text
,
5562 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
5563 (attr
->num_values
== 1 ||
5564 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
5567 * Force the banner to have the classification on it...
5570 if (attr
->num_values
> 1 &&
5571 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
5573 SetString(&(attr
->values
[0].string
.text
), Classification
);
5574 SetString(&(attr
->values
[1].string
.text
), Classification
);
5578 if (attr
->num_values
== 1 ||
5579 strcmp(attr
->values
[0].string
.text
, "none"))
5580 SetString(&(attr
->values
[0].string
.text
), Classification
);
5582 if (attr
->num_values
> 1 &&
5583 strcmp(attr
->values
[1].string
.text
, "none"))
5584 SetString(&(attr
->values
[1].string
.text
), Classification
);
5587 if (attr
->num_values
> 1)
5588 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5589 "job-sheets=\"%s,%s\", "
5590 "job-originating-user-name=\"%s\"",
5591 job
->id
, attr
->values
[0].string
.text
,
5592 attr
->values
[1].string
.text
,
5595 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5596 "job-sheets=\"%s\", "
5597 "job-originating-user-name=\"%s\"",
5598 job
->id
, Classification
,
5604 * Add the starting sheet...
5607 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
5609 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
5610 attr
->values
[0].string
.text
, job
->id
);
5612 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
5614 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5617 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
5621 * Add the job file...
5624 if (add_file(con
, job
, filetype
, compression
))
5627 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
5629 rename(con
->filename
, filename
);
5630 ClearString(&con
->filename
);
5633 * See if we need to add the ending sheet...
5636 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
5637 attr
->num_values
> 1)
5643 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
5644 attr
->values
[1].string
.text
, job
->id
);
5646 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
5648 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5652 * Add any job subscriptions...
5655 add_job_subscriptions(con
, job
);
5658 * Set all but the first two attributes to the job attributes group...
5661 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
5662 attr
->group_tag
= IPP_TAG_JOB
;
5665 * Log and save the job...
5668 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
5669 job
->dest
, job
->username
);
5670 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, (int)job
->hold_until
);
5674 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
5677 * Start the job if possible... Since CheckJobs() can cancel a job if it
5678 * doesn't print, we need to re-find the job afterwards...
5685 job
= FindJob(jobid
);
5688 * Fill in the response info...
5691 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
5694 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
5696 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
5698 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
5699 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
5700 add_job_state_reasons(con
, job
);
5702 con
->response
->request
.status
.status_code
= IPP_OK
;
5707 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
5709 * This function only gets called when printing a single PostScript
5710 * file using the Print-Job operation. It doesn't work for Create-Job +
5711 * Send-File, since the job attributes need to be set at job creation
5712 * time for banners to work. The embedded PS job ticket stuff is here
5713 * only to allow the Windows printer driver for CUPS to pass in JCL
5714 * options and IPP attributes which otherwise would be lost.
5716 * The format of a PS job ticket is simple:
5718 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
5720 * %cupsJobTicket: attr1=value1
5721 * %cupsJobTicket: attr2=value2
5723 * %cupsJobTicket: attrN=valueN
5725 * Job ticket lines must appear immediately after the first line that
5726 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
5727 * looking for job ticket info when it finds a line that does not begin
5728 * with "%cupsJobTicket:".
5730 * The maximum length of a job ticket line, including the prefix, is
5731 * 255 characters to conform with the Adobe DSC.
5733 * Read-only attributes are rejected with a notice to the error log in
5734 * case a malicious user tries anything. Since the job ticket is read
5735 * prior to attribute validation in print_job(), job ticket attributes
5736 * will go through the same validation as IPP attributes...
5740 read_ps_job_ticket(client_t
*con
) /* I - Client connection */
5742 cups_file_t
*fp
; /* File to read from */
5743 char line
[256]; /* Line data */
5744 int num_options
; /* Number of options */
5745 cups_option_t
*options
; /* Options */
5746 ipp_t
*ticket
; /* New attributes */
5747 ipp_attribute_t
*attr
, /* Current attribute */
5748 *attr2
, /* Job attribute */
5749 *prev2
; /* Previous job attribute */
5753 * First open the print file...
5756 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
5758 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to open PostScript print file - %s",
5764 * Skip the first line...
5767 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
5769 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to read from PostScript print file - %s",
5775 if (strncmp(line
, "%!PS-Adobe-", 11) != 0)
5778 * Not a DSC-compliant file, so no job ticket info will be available...
5786 * Read job ticket info from the file...
5792 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
5795 * Stop at the first non-ticket line...
5798 if (strncmp(line
, "%cupsJobTicket:", 15) != 0)
5802 * Add the options to the option array...
5805 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
5809 * Done with the file; see if we have any options...
5814 if (num_options
== 0)
5818 * OK, convert the options to an attribute list, and apply them to
5823 cupsEncodeOptions(ticket
, num_options
, options
);
5826 * See what the user wants to change.
5829 for (attr
= ticket
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5831 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
5834 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
5835 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
5836 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
5837 strcmp(attr
->name
, "job-k-octets") == 0 ||
5838 strcmp(attr
->name
, "job-id") == 0 ||
5839 strncmp(attr
->name
, "job-state", 9) == 0 ||
5840 strncmp(attr
->name
, "time-at-", 8) == 0)
5841 continue; /* Read-only attrs */
5843 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
5846 * Some other value; first free the old value...
5849 if (con
->request
->attrs
== attr2
)
5851 con
->request
->attrs
= attr2
->next
;
5856 for (prev2
= con
->request
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
5857 if (prev2
->next
== attr2
)
5859 prev2
->next
= attr2
->next
;
5864 if (con
->request
->last
== attr2
)
5865 con
->request
->last
= prev2
;
5867 _ipp_free_attr(attr2
);
5871 * Add new option by copying it...
5874 copy_attribute(con
->request
, attr
, 0);
5878 * Then free the attribute list and option array...
5882 cupsFreeOptions(num_options
, options
);
5887 * 'reject_jobs()' - Reject print jobs to a printer.
5891 reject_jobs(client_t
*con
, /* I - Client connection */
5892 ipp_attribute_t
*uri
) /* I - Printer or class URI */
5894 cups_ptype_t dtype
; /* Destination type (printer or class) */
5895 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5896 username
[HTTP_MAX_URI
], /* Username portion of URI */
5897 host
[HTTP_MAX_URI
], /* Host portion of URI */
5898 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5899 int port
; /* Port portion of URI */
5900 const char *name
; /* Printer name */
5901 printer_t
*printer
; /* Printer data */
5902 ipp_attribute_t
*attr
; /* printer-state-message text */
5905 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
5906 uri
->values
[0].string
.text
);
5909 * Was this operation called from the correct URI?
5912 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5914 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
5916 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5921 * Is the destination valid?
5924 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5926 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5932 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
5933 send_ipp_error(con
, IPP_NOT_FOUND
);
5941 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5943 LogMessage(L_ERROR
, "reject_jobs: not authorized!");
5944 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5949 * Reject jobs sent to the printer...
5952 printer
->accepting
= 0;
5954 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
5955 IPP_TAG_TEXT
)) == NULL
)
5956 strcpy(printer
->state_message
, "Rejecting Jobs");
5958 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
5959 sizeof(printer
->state_message
));
5961 AddPrinterHistory(printer
);
5963 if (dtype
& CUPS_PRINTER_CLASS
)
5967 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
5974 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
5979 * Everything was ok, so return OK status...
5982 con
->response
->request
.status
.status_code
= IPP_OK
;
5987 * 'release_job()' - Release a held print job.
5991 release_job(client_t
*con
, /* I - Client connection */
5992 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
5994 ipp_attribute_t
*attr
; /* Current attribute */
5995 int jobid
; /* Job ID */
5996 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5997 username
[HTTP_MAX_URI
], /* Username portion of URI */
5998 host
[HTTP_MAX_URI
], /* Host portion of URI */
5999 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6000 int port
; /* Port portion of URI */
6001 job_t
*job
; /* Job information */
6004 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6005 uri
->values
[0].string
.text
);
6008 * Verify that the POST operation was done to a valid URI.
6011 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6012 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6013 strncmp(con
->uri
, "/printers/", 10) != 0)
6015 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
6017 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6022 * See if we have a job URI or a printer URI...
6025 if (strcmp(uri
->name
, "printer-uri") == 0)
6028 * Got a printer URI; see if we also have a job-id attribute...
6031 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6033 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
6034 send_ipp_error(con
, IPP_BAD_REQUEST
);
6038 jobid
= attr
->values
[0].integer
;
6043 * Got a job URI; parse it to get the job ID...
6046 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6048 if (strncmp(resource
, "/jobs/", 6) != 0)
6054 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
6055 uri
->values
[0].string
.text
);
6056 send_ipp_error(con
, IPP_BAD_REQUEST
);
6060 jobid
= atoi(resource
+ 6);
6064 * See if the job exists...
6067 if ((job
= FindJob(jobid
)) == NULL
)
6070 * Nope - return a "not found" error...
6073 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
6074 send_ipp_error(con
, IPP_NOT_FOUND
);
6079 * See if job is "held"...
6082 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
6085 * Nope - return a "not possible" error...
6088 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
6089 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6094 * See if the job is owned by the requesting user...
6097 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6099 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
6100 username
, jobid
, job
->username
);
6101 send_ipp_error(con
, IPP_FORBIDDEN
);
6106 * Reset the job-hold-until value to "no-hold"...
6109 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6110 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6114 free(attr
->values
[0].string
.text
);
6115 attr
->value_tag
= IPP_TAG_KEYWORD
;
6116 attr
->values
[0].string
.text
= strdup("no-hold");
6120 * Release the job and return...
6125 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
6127 con
->response
->request
.status
.status_code
= IPP_OK
;
6132 * 'renew_subscription()' - Renew an existing subscription...
6136 renew_subscription(client_t
*con
, /* I - Client connection */
6137 int sub_id
) /* I - Subscription ID */
6143 * 'restart_job()' - Restart an old print job.
6147 restart_job(client_t
*con
, /* I - Client connection */
6148 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6150 ipp_attribute_t
*attr
; /* Current attribute */
6151 int jobid
; /* Job ID */
6152 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6153 username
[HTTP_MAX_URI
], /* Username portion of URI */
6154 host
[HTTP_MAX_URI
], /* Host portion of URI */
6155 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6156 int port
; /* Port portion of URI */
6157 job_t
*job
; /* Job information */
6160 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6161 uri
->values
[0].string
.text
);
6164 * Verify that the POST operation was done to a valid URI.
6167 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6168 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6169 strncmp(con
->uri
, "/printers/", 10) != 0)
6171 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
6173 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6178 * See if we have a job URI or a printer URI...
6181 if (strcmp(uri
->name
, "printer-uri") == 0)
6184 * Got a printer URI; see if we also have a job-id attribute...
6187 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6189 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
6190 send_ipp_error(con
, IPP_BAD_REQUEST
);
6194 jobid
= attr
->values
[0].integer
;
6199 * Got a job URI; parse it to get the job ID...
6202 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6204 if (strncmp(resource
, "/jobs/", 6) != 0)
6210 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
6211 uri
->values
[0].string
.text
);
6212 send_ipp_error(con
, IPP_BAD_REQUEST
);
6216 jobid
= atoi(resource
+ 6);
6220 * See if the job exists...
6223 if ((job
= FindJob(jobid
)) == NULL
)
6226 * Nope - return a "not found" error...
6229 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
6230 send_ipp_error(con
, IPP_NOT_FOUND
);
6235 * See if job is in any of the "completed" states...
6238 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
6241 * Nope - return a "not possible" error...
6244 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
6245 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6250 * See if we have retained the job files...
6253 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6256 * Nope - return a "not possible" error...
6259 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
6260 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6265 * See if the job is owned by the requesting user...
6268 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6270 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
6271 username
, jobid
, job
->username
);
6272 send_ipp_error(con
, IPP_FORBIDDEN
);
6277 * Restart the job and return...
6282 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
6284 con
->response
->request
.status
.status_code
= IPP_OK
;
6289 * 'send_document()' - Send a file to a printer or class.
6293 send_document(client_t
*con
, /* I - Client connection */
6294 ipp_attribute_t
*uri
) /* I - Printer URI */
6296 ipp_attribute_t
*attr
; /* Current attribute */
6297 ipp_attribute_t
*format
; /* Document-format attribute */
6298 int jobid
; /* Job ID number */
6299 job_t
*job
; /* Current job */
6300 char job_uri
[HTTP_MAX_URI
],
6302 method
[HTTP_MAX_URI
],
6303 /* Method portion of URI */
6304 username
[HTTP_MAX_URI
],
6305 /* Username portion of URI */
6307 /* Host portion of URI */
6308 resource
[HTTP_MAX_URI
];
6309 /* Resource portion of URI */
6310 int port
; /* Port portion of URI */
6311 mime_type_t
*filetype
; /* Type of file */
6312 char super
[MIME_MAX_SUPER
],
6313 /* Supertype of file */
6314 type
[MIME_MAX_TYPE
],
6315 /* Subtype of file */
6316 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
6317 /* Textual name of mime type */
6318 char filename
[1024]; /* Job filename */
6319 printer_t
*printer
; /* Current printer */
6320 struct stat fileinfo
; /* File information */
6321 int kbytes
; /* Size of file */
6322 int compression
; /* Type of compression */
6325 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
6326 uri
->values
[0].string
.text
);
6329 * Verify that the POST operation was done to a valid URI.
6332 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6333 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
6334 strncmp(con
->uri
, "/printers/", 10) != 0)
6336 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
6338 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6343 * See if we have a job URI or a printer URI...
6346 if (strcmp(uri
->name
, "printer-uri") == 0)
6349 * Got a printer URI; see if we also have a job-id attribute...
6352 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6354 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
6355 send_ipp_error(con
, IPP_BAD_REQUEST
);
6359 jobid
= attr
->values
[0].integer
;
6364 * Got a job URI; parse it to get the job ID...
6367 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6369 if (strncmp(resource
, "/jobs/", 6) != 0)
6375 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
6376 uri
->values
[0].string
.text
);
6377 send_ipp_error(con
, IPP_BAD_REQUEST
);
6381 jobid
= atoi(resource
+ 6);
6385 * See if the job exists...
6388 if ((job
= FindJob(jobid
)) == NULL
)
6391 * Nope - return a "not found" error...
6394 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
6395 send_ipp_error(con
, IPP_NOT_FOUND
);
6400 * See if the job is owned by the requesting user...
6403 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6405 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
6406 username
, jobid
, job
->username
);
6407 send_ipp_error(con
, IPP_FORBIDDEN
);
6412 * OK, see if the client is sending the document compressed - CUPS
6413 * only supports "none" and "gzip".
6416 compression
= CUPS_FILE_NONE
;
6418 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
6420 if (strcmp(attr
->values
[0].string
.text
, "none")
6422 && strcmp(attr
->values
[0].string
.text
, "gzip")
6423 #endif /* HAVE_LIBZ */
6426 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
6427 attr
->values
[0].string
.text
);
6428 send_ipp_error(con
, IPP_ATTRIBUTES
);
6429 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
6430 "compression", NULL
, attr
->values
[0].string
.text
);
6435 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
6436 compression
= CUPS_FILE_GZIP
;
6437 #endif /* HAVE_LIBZ */
6441 * Do we have a file to print?
6446 LogMessage(L_ERROR
, "send_document: No file!?!");
6447 send_ipp_error(con
, IPP_BAD_REQUEST
);
6452 * Is it a format we support?
6455 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
6458 * Grab format from client...
6461 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
6463 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
6464 format
->values
[0].string
.text
);
6465 send_ipp_error(con
, IPP_BAD_REQUEST
);
6472 * No document format attribute? Auto-type it!
6475 strcpy(super
, "application");
6476 strcpy(type
, "octet-stream");
6479 if (strcmp(super
, "application") == 0 &&
6480 strcmp(type
, "octet-stream") == 0)
6483 * Auto-type the file...
6486 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
6488 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
6490 if (filetype
!= NULL
)
6493 * Replace the document-format attribute value with the auto-typed one.
6496 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
6501 free(format
->values
[0].string
.text
);
6502 format
->values
[0].string
.text
= strdup(mimetype
);
6505 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
6506 "document-format", NULL
, mimetype
);
6509 filetype
= mimeType(MimeDatabase
, super
, type
);
6512 filetype
= mimeType(MimeDatabase
, super
, type
);
6514 if (filetype
== NULL
)
6516 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
6518 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
6519 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
6522 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
6523 "document-format", NULL
, format
->values
[0].string
.text
);
6528 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
6529 filetype
->super
, filetype
->type
);
6532 * Add the file to the job...
6535 if (add_file(con
, job
, filetype
, compression
))
6538 if (job
->dtype
& CUPS_PRINTER_CLASS
)
6539 printer
= FindClass(job
->dest
);
6541 printer
= FindPrinter(job
->dest
);
6543 if (stat(con
->filename
, &fileinfo
))
6546 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6548 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6550 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
6551 attr
->values
[0].integer
+= kbytes
;
6553 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6555 rename(con
->filename
, filename
);
6557 ClearString(&con
->filename
);
6559 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
6560 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
6563 * Start the job if this is the last document...
6566 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
6567 attr
->values
[0].boolean
)
6570 * See if we need to add the ending sheet...
6573 if (printer
!= NULL
&&
6574 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6575 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
6576 attr
->num_values
> 1)
6582 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
6583 attr
->values
[1].string
.text
, job
->id
);
6585 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6587 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6590 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
6591 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6592 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
6594 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6595 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6597 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6598 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6604 * Start the job if possible... Since CheckJobs() can cancel a job if it
6605 * doesn't print, we need to re-find the job afterwards...
6612 job
= FindJob(jobid
);
6616 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6617 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6619 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6621 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
6622 job
->hold_until
= time(NULL
) + 60;
6628 * Fill in the response info...
6631 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
6634 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
6637 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
6639 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
6640 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
6641 add_job_state_reasons(con
, job
);
6643 con
->response
->request
.status
.status_code
= IPP_OK
;
6648 * 'send_ipp_error()' - Send an error status back to the IPP client.
6652 send_ipp_error(client_t
*con
, /* I - Client connection */
6653 ipp_status_t status
) /* I - IPP status code */
6655 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
6658 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
6660 con
->response
->request
.status
.status_code
= status
;
6662 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
6663 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
6664 "attributes-charset", NULL
, DefaultCharset
);
6666 if (ippFindAttribute(con
->response
, "attributes-natural-language",
6667 IPP_TAG_ZERO
) == NULL
)
6668 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
6669 "attributes-natural-language", NULL
, DefaultLanguage
);
6674 * 'set_default()' - Set the default destination...
6678 set_default(client_t
*con
, /* I - Client connection */
6679 ipp_attribute_t
*uri
) /* I - Printer URI */
6681 cups_ptype_t dtype
; /* Destination type (printer or class) */
6682 char method
[HTTP_MAX_URI
],
6683 /* Method portion of URI */
6684 username
[HTTP_MAX_URI
],
6685 /* Username portion of URI */
6687 /* Host portion of URI */
6688 resource
[HTTP_MAX_URI
];
6689 /* Resource portion of URI */
6690 int port
; /* Port portion of URI */
6691 const char *name
; /* Printer name */
6692 printer_t
*printer
; /* Printer */
6695 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
6696 uri
->values
[0].string
.text
);
6699 * Was this operation called from the correct URI?
6702 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6704 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
6706 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6711 * Is the destination valid?
6714 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6716 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6722 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
6723 send_ipp_error(con
, IPP_NOT_FOUND
);
6731 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
6733 LogMessage(L_ERROR
, "set_default: not authorized!");
6734 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6739 * Set it as the default...
6742 DefaultPrinter
= printer
;
6747 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
6751 * Everything was ok, so return OK status...
6754 con
->response
->request
.status
.status_code
= IPP_OK
;
6759 * 'set_job_attrs()' - Set job attributes.
6763 set_job_attrs(client_t
*con
, /* I - Client connection */
6764 ipp_attribute_t
*uri
) /* I - Job URI */
6766 ipp_attribute_t
*attr
, /* Current attribute */
6767 *attr2
, /* Job attribute */
6768 *prev2
; /* Previous job attribute */
6769 int jobid
; /* Job ID */
6770 job_t
*job
; /* Current job */
6771 char method
[HTTP_MAX_URI
],
6772 /* Method portion of URI */
6773 username
[HTTP_MAX_URI
],
6774 /* Username portion of URI */
6776 /* Host portion of URI */
6777 resource
[HTTP_MAX_URI
];
6778 /* Resource portion of URI */
6779 int port
; /* Port portion of URI */
6782 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
6783 uri
->values
[0].string
.text
);
6786 * Start with "everything is OK" status...
6789 con
->response
->request
.status
.status_code
= IPP_OK
;
6792 * See if we have a job URI or a printer URI...
6795 if (strcmp(uri
->name
, "printer-uri") == 0)
6798 * Got a printer URI; see if we also have a job-id attribute...
6801 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6803 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
6804 send_ipp_error(con
, IPP_BAD_REQUEST
);
6808 jobid
= attr
->values
[0].integer
;
6813 * Got a job URI; parse it to get the job ID...
6816 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6818 if (strncmp(resource
, "/jobs/", 6) != 0)
6824 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
6825 uri
->values
[0].string
.text
);
6826 send_ipp_error(con
, IPP_BAD_REQUEST
);
6830 jobid
= atoi(resource
+ 6);
6834 * See if the job exists...
6837 if ((job
= FindJob(jobid
)) == NULL
)
6840 * Nope - return a "not found" error...
6843 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
6844 send_ipp_error(con
, IPP_NOT_FOUND
);
6849 * See if the job has been completed...
6852 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6855 * Return a "not-possible" error...
6858 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
6859 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6864 * See if the job is owned by the requesting user...
6867 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6869 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
6870 username
, jobid
, job
->username
);
6871 send_ipp_error(con
, IPP_FORBIDDEN
);
6876 * See what the user wants to change.
6879 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6881 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6884 if (!strcmp(attr
->name
, "attributes-charset") ||
6885 !strcmp(attr
->name
, "attributes-natural-language") ||
6886 !strcmp(attr
->name
, "document-compression") ||
6887 !strcmp(attr
->name
, "document-format") ||
6888 !strcmp(attr
->name
, "job-detailed-status-messages") ||
6889 !strcmp(attr
->name
, "job-document-access-errors") ||
6890 !strcmp(attr
->name
, "job-id") ||
6891 !strcmp(attr
->name
, "job-k-octets") ||
6892 !strcmp(attr
->name
, "job-originating-host-name") ||
6893 !strcmp(attr
->name
, "job-originating-user-name") ||
6894 !strcmp(attr
->name
, "job-printer-up-time") ||
6895 !strcmp(attr
->name
, "job-printer-uri") ||
6896 !strcmp(attr
->name
, "job-sheets") ||
6897 !strcmp(attr
->name
, "job-state-message") ||
6898 !strcmp(attr
->name
, "job-state-reasons") ||
6899 !strcmp(attr
->name
, "job-uri") ||
6900 !strcmp(attr
->name
, "number-of-documents") ||
6901 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
6902 !strcmp(attr
->name
, "output-device-assigned") ||
6903 !strncmp(attr
->name
, "date-time-at-", 13) ||
6904 !strncmp(attr
->name
, "job-impressions", 15) ||
6905 !strncmp(attr
->name
, "job-k-octets", 12) ||
6906 !strncmp(attr
->name
, "job-media-sheets", 16) ||
6907 !strncmp(attr
->name
, "time-at-", 8))
6913 send_ipp_error(con
, IPP_ATTRIBUTES_NOT_SETTABLE
);
6915 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6916 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6921 if (!strcmp(attr
->name
, "job-priority"))
6924 * Change the job priority...
6927 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
6929 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6931 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6932 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6934 else if (job
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
6936 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6939 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6940 SetJobPriority(jobid
, attr
->values
[0].integer
);
6942 else if (!strcmp(attr
->name
, "job-state"))
6945 * Change the job state...
6948 if (attr
->value_tag
!= IPP_TAG_ENUM
)
6950 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6952 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6953 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6957 switch (attr
->values
[0].integer
)
6959 case IPP_JOB_PENDING
:
6961 if (job
->state
->values
[0].integer
> IPP_JOB_HELD
)
6963 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6966 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6967 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
6970 case IPP_JOB_PROCESSING
:
6971 case IPP_JOB_STOPPED
:
6972 if (job
->state
->values
[0].integer
!= attr
->values
[0].integer
)
6974 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6979 case IPP_JOB_CANCELLED
:
6980 case IPP_JOB_ABORTED
:
6981 case IPP_JOB_COMPLETED
:
6982 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
)
6984 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6987 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6989 CancelJob(job
->id
, 0);
6993 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7001 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
7003 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
7006 * Some other value; first free the old value...
7009 if (job
->attrs
->attrs
== attr2
)
7011 job
->attrs
->attrs
= attr2
->next
;
7016 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
7017 if (prev2
->next
== attr2
)
7019 prev2
->next
= attr2
->next
;
7024 if (job
->attrs
->last
== attr2
)
7025 job
->attrs
->last
= prev2
;
7027 _ipp_free_attr(attr2
);
7030 * Then copy the attribute...
7033 copy_attribute(job
->attrs
, attr
, 0);
7036 * See if the job-name or job-hold-until is being changed.
7039 if (strcmp(attr
->name
, "job-hold-until") == 0)
7041 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
7043 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7044 ReleaseJob(job
->id
);
7049 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
7052 * Delete the attribute...
7055 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
7057 prev2
= attr2
, attr2
= attr2
->next
)
7058 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
7064 prev2
->next
= attr2
->next
;
7066 job
->attrs
->attrs
= attr2
->next
;
7068 if (attr2
== job
->attrs
->last
)
7069 job
->attrs
->last
= prev2
;
7071 _ipp_free_attr(attr2
);
7077 * Add new option by copying it...
7080 copy_attribute(job
->attrs
, attr
, 0);
7091 * Start jobs if possible...
7099 * 'start_printer()' - Start a printer.
7103 start_printer(client_t
*con
, /* I - Client connection */
7104 ipp_attribute_t
*uri
) /* I - Printer URI */
7106 cups_ptype_t dtype
; /* Destination type (printer or class) */
7107 char method
[HTTP_MAX_URI
],
7108 /* Method portion of URI */
7109 username
[HTTP_MAX_URI
],
7110 /* Username portion of URI */
7112 /* Host portion of URI */
7113 resource
[HTTP_MAX_URI
];
7114 /* Resource portion of URI */
7115 int port
; /* Port portion of URI */
7116 const char *name
; /* Printer name */
7117 printer_t
*printer
; /* Printer data */
7120 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7121 uri
->values
[0].string
.text
);
7124 * Was this operation called from the correct URI?
7127 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7129 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
7131 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7136 * Is the destination valid?
7139 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7141 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7147 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
7148 send_ipp_error(con
, IPP_NOT_FOUND
);
7156 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7158 LogMessage(L_ERROR
, "start_printer: not authorized!");
7159 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7164 * Start the printer...
7167 printer
->state_message
[0] = '\0';
7169 StartPrinter(printer
, 1);
7171 if (dtype
& CUPS_PRINTER_CLASS
)
7172 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
7174 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
7180 * Everything was ok, so return OK status...
7183 con
->response
->request
.status
.status_code
= IPP_OK
;
7188 * 'stop_printer()' - Stop a printer.
7192 stop_printer(client_t
*con
, /* I - Client connection */
7193 ipp_attribute_t
*uri
) /* I - Printer URI */
7195 cups_ptype_t dtype
; /* Destination type (printer or class) */
7196 char method
[HTTP_MAX_URI
],
7197 /* Method portion of URI */
7198 username
[HTTP_MAX_URI
],
7199 /* Username portion of URI */
7201 /* Host portion of URI */
7202 resource
[HTTP_MAX_URI
];
7203 /* Resource portion of URI */
7204 int port
; /* Port portion of URI */
7205 const char *name
; /* Printer name */
7206 printer_t
*printer
; /* Printer data */
7207 ipp_attribute_t
*attr
; /* printer-state-message attribute */
7210 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7211 uri
->values
[0].string
.text
);
7214 * Was this operation called from the correct URI?
7217 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7219 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
7221 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7226 * Is the destination valid?
7229 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7231 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7237 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
7238 send_ipp_error(con
, IPP_NOT_FOUND
);
7246 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7248 LogMessage(L_ERROR
, "stop_printer: not authorized!");
7249 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7254 * Stop the printer...
7257 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
7258 IPP_TAG_TEXT
)) == NULL
)
7259 strcpy(printer
->state_message
, "Paused");
7262 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
7263 sizeof(printer
->state_message
));
7266 StopPrinter(printer
, 1);
7268 if (dtype
& CUPS_PRINTER_CLASS
)
7269 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
7272 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
7276 * Everything was ok, so return OK status...
7279 con
->response
->request
.status
.status_code
= IPP_OK
;
7284 * 'user_allowed()' - See if a user is allowed to print to a queue.
7287 static int /* O - 0 if not allowed, 1 if allowed */
7288 user_allowed(printer_t
*p
, /* I - Printer or class */
7289 const char *username
) /* I - Username */
7291 int i
, j
; /* Looping vars */
7292 struct passwd
*pw
; /* User password data */
7293 struct group
*grp
; /* Group data */
7296 if (p
->num_users
== 0)
7299 if (!strcmp(username
, "root"))
7302 pw
= getpwnam(username
);
7305 for (i
= 0; i
< p
->num_users
; i
++)
7307 if (p
->users
[i
][0] == '@')
7310 * Check group membership...
7313 grp
= getgrnam(p
->users
[i
] + 1);
7319 * Check primary group...
7322 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
7326 * Check usernames in group...
7329 for (j
= 0; grp
->gr_mem
[j
]; j
++)
7330 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
7337 else if (!strcasecmp(username
, p
->users
[i
]))
7341 return ((i
< p
->num_users
) != p
->deny_users
);
7346 * 'validate_job()' - Validate printer options and destination.
7350 validate_job(client_t
*con
, /* I - Client connection */
7351 ipp_attribute_t
*uri
) /* I - Printer URI */
7353 ipp_attribute_t
*attr
; /* Current attribute */
7354 ipp_attribute_t
*format
; /* Document-format attribute */
7355 cups_ptype_t dtype
; /* Destination type (printer or class) */
7356 char method
[HTTP_MAX_URI
],
7357 /* Method portion of URI */
7358 username
[HTTP_MAX_URI
],
7359 /* Username portion of URI */
7361 /* Host portion of URI */
7362 resource
[HTTP_MAX_URI
];
7363 /* Resource portion of URI */
7364 int port
; /* Port portion of URI */
7365 char super
[MIME_MAX_SUPER
],
7366 /* Supertype of file */
7367 type
[MIME_MAX_TYPE
];
7368 /* Subtype of file */
7369 printer_t
*printer
; /* Printer */
7372 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
7373 uri
->values
[0].string
.text
);
7376 * Verify that the POST operation was done to a valid URI.
7379 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
7380 strncmp(con
->uri
, "/printers/", 10) != 0)
7382 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
7384 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7389 * OK, see if the client is sending the document compressed - CUPS
7390 * doesn't support compression yet...
7393 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
7394 strcmp(attr
->values
[0].string
.text
, "none") == 0)
7396 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
7397 attr
->values
[0].string
.text
);
7398 send_ipp_error(con
, IPP_ATTRIBUTES
);
7399 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7400 "compression", NULL
, attr
->values
[0].string
.text
);
7405 * Is it a format we support?
7408 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
7410 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7412 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
7413 format
->values
[0].string
.text
);
7414 send_ipp_error(con
, IPP_BAD_REQUEST
);
7418 if ((strcmp(super
, "application") != 0 ||
7419 strcmp(type
, "octet-stream") != 0) &&
7420 mimeType(MimeDatabase
, super
, type
) == NULL
)
7422 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
7423 format
->values
[0].string
.text
);
7424 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
7425 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
7426 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7427 "document-format", NULL
, format
->values
[0].string
.text
);
7433 * Is the destination valid?
7436 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7438 if (ValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
7444 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
7445 send_ipp_error(con
, IPP_NOT_FOUND
);
7453 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7455 LogMessage(L_ERROR
, "validate_job: not authorized!");
7456 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7461 * Everything was ok, so return OK status...
7464 con
->response
->request
.status
.status_code
= IPP_OK
;
7469 * 'validate_name()' - Make sure the printer name only contains valid chars.
7472 static int /* O - 0 if name is no good, 1 if name is good */
7473 validate_name(const char *name
) /* I - Name to check */
7475 const char *ptr
; /* Pointer into name */
7479 * Scan the whole name...
7482 for (ptr
= name
; *ptr
; ptr
++)
7483 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
7487 * All the characters are good; validate the length, too...
7490 return ((ptr
- name
) < 128);
7495 * 'validate_user()' - Validate the user for the request.
7498 static int /* O - 1 if permitted, 0 otherwise */
7499 validate_user(job_t
*job
, /* I - Job */
7500 client_t
*con
, /* I - Client connection */
7501 const char *owner
, /* I - Owner of job/resource */
7502 char *username
, /* O - Authenticated username */
7503 int userlen
) /* I - Length of username */
7505 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
7506 printer_t
*printer
; /* Printer for job */
7509 LogMessage(L_DEBUG2
, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=%d)\n",
7510 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
7517 if (!con
|| !owner
|| !username
|| userlen
<= 0)
7521 * Get the best authenticated username that is available.
7524 if (con
->username
[0])
7525 strlcpy(username
, con
->username
, userlen
);
7526 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
7527 strlcpy(username
, attr
->values
[0].string
.text
, userlen
);
7529 strlcpy(username
, "anonymous", userlen
);
7532 * Check the username against the owner...
7535 if (job
->dtype
& CUPS_PRINTER_CLASS
)
7536 printer
= FindClass(job
->dest
);
7538 printer
= FindPrinter(job
->dest
);
7541 return (CheckPolicy(printer
->op_policy_ptr
, con
, owner
));
7543 return (CheckPolicy(DefaultPolicyPtr
, con
, owner
));