4 * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * ProcessIPPRequest() - Process an incoming IPP request...
27 * accept_jobs() - Accept print jobs to a printer.
28 * add_class() - Add a class to the system.
29 * add_file() - Add a file to a job.
30 * add_job_state_reasons() - Add the "job-state-reasons" attribute based
31 * upon the job and printer state...
32 * add_job_subscriptions() - Add any subcriptions for a job.
33 * add_printer() - Add a printer to the system.
34 * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
35 * based upon the printer state...
36 * add_queued_job_count() - Add the "queued-job-count" attribute for
37 * cancel_all_jobs() - Cancel all print jobs.
38 * cancel_job() - Cancel a print job.
39 * cancel_subscription() - Cancel a subscription.
40 * check_quotas() - Check quotas for a printer and user.
41 * copy_attribute() - Copy a single attribute.
42 * copy_attrs() - Copy attributes from one request to another.
43 * copy_banner() - Copy a banner file to the requests directory
44 * for the specified job.
45 * copy_file() - Copy a PPD file or interface script...
46 * copy_model() - Copy a PPD model file, substituting default
48 * create_job() - Print a file to a printer or class.
49 * create_subscription() - Create a notification subscription.
50 * delete_printer() - Remove a printer or class from the system.
51 * get_default() - Get the default destination.
52 * get_devices() - Get the list of available devices on the
54 * get_jobs() - Get a list of jobs for the specified printer.
55 * get_job_attrs() - Get job attributes.
56 * get_notifications() - Get events for a subscription.
57 * get_ppds() - Get the list of PPD files on the local
59 * get_printer_attrs() - Get printer attributes.
60 * get_printers() - Get a list of printers.
61 * get_subscription_attrs() - Get subscription attributes.
62 * get_subscriptions() - Get subscriptions.
63 * hold_job() - Hold a print job.
64 * move_job() - Move a job to a new destination.
65 * ppd_add_default() - Add a PPD default choice.
66 * ppd_parse_line() - Parse a PPD default line.
67 * print_job() - Print a file to a printer or class.
68 * read_ps_line() - Read a line from a PS file...
69 * read_ps_job_ticket() - Reads a job ticket embedded in a PS file.
70 * reject_jobs() - Reject print jobs to a printer.
71 * release_job() - Release a held print job.
72 * restart_job() - Restart an old print job.
73 * send_document() - Send a file to a printer or class.
74 * send_ipp_error() - Send an error status back to the IPP client.
75 * set_default() - Set the default destination...
76 * set_job_attrs() - Set job attributes.
77 * start_printer() - Start a printer.
78 * stop_printer() - Stop a printer.
79 * user_allowed() - See if a user is allowed to print to a queue.
80 * validate_job() - Validate printer options and destination.
81 * validate_name() - Make sure the printer name only contains
83 * validate_user() - Validate the user for the request.
87 * Include necessary headers...
96 #endif /* HAVE_LIBPAPER */
100 * PPD default choice structure...
105 char option
[PPD_MAX_NAME
]; /* Main keyword (option name) */
106 char choice
[PPD_MAX_NAME
]; /* Option keyword (choice name) */
114 static void accept_jobs(client_t
*con
, ipp_attribute_t
*uri
);
115 static void add_class(client_t
*con
, ipp_attribute_t
*uri
);
116 static int add_file(client_t
*con
, job_t
*job
, mime_type_t
*filetype
,
118 static void add_job_state_reasons(client_t
*con
, job_t
*job
);
119 static void add_job_subscriptions(client_t
*con
, job_t
*job
);
120 static void add_printer(client_t
*con
, ipp_attribute_t
*uri
);
121 static void add_printer_state_reasons(client_t
*con
, printer_t
*p
);
122 static void add_queued_job_count(client_t
*con
, printer_t
*p
);
123 static void cancel_all_jobs(client_t
*con
, ipp_attribute_t
*uri
);
124 static void cancel_job(client_t
*con
, ipp_attribute_t
*uri
);
125 static void cancel_subscription(client_t
*con
, int id
);
126 static int check_quotas(client_t
*con
, printer_t
*p
);
127 static ipp_attribute_t
*copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
129 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, ipp_attribute_t
*req
,
130 ipp_tag_t group
, int quickcopy
);
131 static int copy_banner(client_t
*con
, job_t
*job
, const char *name
);
132 static int copy_file(const char *from
, const char *to
);
133 static int copy_model(const char *from
, const char *to
);
134 static void create_job(client_t
*con
, ipp_attribute_t
*uri
);
135 static void create_subscription(client_t
*con
, ipp_attribute_t
*uri
);
136 static void delete_printer(client_t
*con
, ipp_attribute_t
*uri
);
137 static void get_default(client_t
*con
);
138 static void get_devices(client_t
*con
);
139 static void get_jobs(client_t
*con
, ipp_attribute_t
*uri
);
140 static void get_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
141 static void get_notifications(client_t
*con
, int id
);
142 static void get_ppds(client_t
*con
);
143 static void get_printers(client_t
*con
, int type
);
144 static void get_printer_attrs(client_t
*con
, ipp_attribute_t
*uri
);
145 static void get_subscription_attrs(client_t
*con
, int sub_id
);
146 static void get_subscriptions(client_t
*con
, ipp_attribute_t
*uri
);
147 static void hold_job(client_t
*con
, ipp_attribute_t
*uri
);
148 static void move_job(client_t
*con
, ipp_attribute_t
*uri
);
149 static int ppd_add_default(const char *option
, const char *choice
,
150 int num_defaults
, ppd_default_t
**defaults
);
151 static int ppd_parse_line(const char *line
, char *option
, int olen
,
152 char *choice
, int clen
);
153 static void print_job(client_t
*con
, ipp_attribute_t
*uri
);
154 static void read_ps_job_ticket(client_t
*con
);
155 static void reject_jobs(client_t
*con
, ipp_attribute_t
*uri
);
156 static void release_job(client_t
*con
, ipp_attribute_t
*uri
);
157 static void renew_subscription(client_t
*con
, int sub_id
);
158 static void restart_job(client_t
*con
, ipp_attribute_t
*uri
);
159 static void send_document(client_t
*con
, ipp_attribute_t
*uri
);
160 static void send_ipp_error(client_t
*con
, ipp_status_t status
);
161 static void set_default(client_t
*con
, ipp_attribute_t
*uri
);
162 static void set_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
163 static void start_printer(client_t
*con
, ipp_attribute_t
*uri
);
164 static void stop_printer(client_t
*con
, ipp_attribute_t
*uri
);
165 static int user_allowed(printer_t
*p
, const char *username
);
166 static void validate_job(client_t
*con
, ipp_attribute_t
*uri
);
167 static int validate_name(const char *name
);
168 static int validate_user(job_t
*job
, client_t
*con
,
169 const char *owner
, char *username
,
174 * 'ProcessIPPRequest()' - Process an incoming IPP request...
177 int /* O - 1 on success, 0 on failure */
178 ProcessIPPRequest(client_t
*con
) /* I - Client connection */
180 ipp_tag_t group
; /* Current group tag */
181 ipp_attribute_t
*attr
; /* Current attribute */
182 ipp_attribute_t
*charset
; /* Character set attribute */
183 ipp_attribute_t
*language
; /* Language attribute */
184 ipp_attribute_t
*uri
; /* Printer URI attribute */
185 ipp_attribute_t
*username
; /* requesting-user-name attr */
186 int sub_id
; /* Subscription ID */
189 LogMessage(L_DEBUG2
, "ProcessIPPRequest(%p[%d]): operation_id = %04x",
190 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
193 * First build an empty response message for this request...
196 con
->response
= ippNew();
198 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
199 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
200 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
203 * Then validate the request header and required attributes...
206 if (con
->request
->request
.any
.version
[0] != 1)
209 * Return an error, since we only support IPP 1.x.
212 LogMessage(L_ERROR
, "ProcessIPPRequest: bad request version (%d.%d)!",
213 con
->request
->request
.any
.version
[0],
214 con
->request
->request
.any
.version
[1]);
216 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
217 "%04X %s Bad request version (%d.%d)",
218 IPP_VERSION_NOT_SUPPORTED
, con
->http
.hostname
,
219 con
->request
->request
.any
.version
[0],
220 con
->request
->request
.any
.version
[1]);
222 send_ipp_error(con
, IPP_VERSION_NOT_SUPPORTED
);
224 else if (con
->request
->attrs
== NULL
)
226 LogMessage(L_ERROR
, "ProcessIPPRequest: no attributes in request!");
228 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
229 "%04X %s No attributes in request",
230 IPP_BAD_REQUEST
, con
->http
.hostname
);
232 send_ipp_error(con
, IPP_BAD_REQUEST
);
237 * Make sure that the attributes are provided in the correct order and
238 * don't repeat groups...
241 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
244 if (attr
->group_tag
< group
)
247 * Out of order; return an error...
250 LogMessage(L_ERROR
, "ProcessIPPRequest: attribute groups are out of order!");
252 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
253 "%04X %s Attribute groups are out of order",
254 IPP_BAD_REQUEST
, con
->http
.hostname
);
256 send_ipp_error(con
, IPP_BAD_REQUEST
);
260 group
= attr
->group_tag
;
265 * Then make sure that the first three attributes are:
268 * attributes-natural-language
269 * printer-uri/job-uri
272 attr
= con
->request
->attrs
;
273 if (attr
&& !strcmp(attr
->name
, "attributes-charset") &&
274 attr
->value_tag
== IPP_TAG_CHARSET
)
282 if (attr
&& !strcmp(attr
->name
, "attributes-natural-language") &&
283 attr
->value_tag
== IPP_TAG_LANGUAGE
)
288 if ((attr
= ippFindAttribute(con
->request
, "printer-uri", IPP_TAG_URI
)) != NULL
)
290 else if ((attr
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
)) != NULL
)
296 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
297 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
299 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
300 "attributes-charset", NULL
, DefaultCharset
);
303 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
304 "attributes-natural-language", NULL
,
305 language
->values
[0].string
.text
);
307 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
308 "attributes-natural-language", NULL
, DefaultLanguage
);
310 if (charset
== NULL
|| language
== NULL
||
312 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
313 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
314 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
315 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
316 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
319 * Return an error, since attributes-charset,
320 * attributes-natural-language, and printer-uri/job-uri are required
321 * for all operations.
326 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-charset attribute!");
328 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
329 "%04X %s Missing attributes-charset attribute",
330 IPP_BAD_REQUEST
, con
->http
.hostname
);
335 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-natural-language attribute!");
337 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
338 "%04X %s Missing attributes-natural-language attribute",
339 IPP_BAD_REQUEST
, con
->http
.hostname
);
344 LogMessage(L_ERROR
, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
346 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
347 "%04X %s Missing printer-uri or job-uri attribute",
348 IPP_BAD_REQUEST
, con
->http
.hostname
);
351 LogMessage(L_DEBUG
, "Request attributes follow...");
353 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
354 LogMessage(L_DEBUG
, "attr \"%s\": group_tag = %x, value_tag = %x",
355 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
358 LogMessage(L_DEBUG
, "End of attributes...");
360 send_ipp_error(con
, IPP_BAD_REQUEST
);
365 * OK, all the checks pass so far; make sure requesting-user-name is
366 * not "root" from a remote host...
369 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name",
370 IPP_TAG_NAME
)) != NULL
)
373 * Check for root user...
376 if (strcmp(username
->values
[0].string
.text
, "root") == 0 &&
377 strcasecmp(con
->http
.hostname
, "localhost") != 0 &&
378 strcmp(con
->username
, "root") != 0)
381 * Remote unauthenticated user masquerading as local root...
384 SetString(&(username
->values
[0].string
.text
), RemoteRoot
);
388 if ((attr
= ippFindAttribute(con
->request
, "notify-subscription-id",
389 IPP_TAG_INTEGER
)) != NULL
)
390 sub_id
= attr
->values
[0].integer
;
395 * Then try processing the operation...
399 LogMessage(L_DEBUG2
, "ProcessIPPRequest: URI=\"%s\"",
400 uri
->values
[0].string
.text
);
402 switch (con
->request
->request
.op
.operation_id
)
408 case IPP_VALIDATE_JOB
:
409 validate_job(con
, uri
);
412 case IPP_CREATE_JOB
:
413 create_job(con
, uri
);
416 case IPP_SEND_DOCUMENT
:
417 send_document(con
, uri
);
420 case IPP_CANCEL_JOB
:
421 cancel_job(con
, uri
);
424 case IPP_GET_JOB_ATTRIBUTES
:
425 get_job_attrs(con
, uri
);
432 case IPP_GET_PRINTER_ATTRIBUTES
:
433 get_printer_attrs(con
, uri
);
440 case IPP_RELEASE_JOB
:
441 release_job(con
, uri
);
444 case IPP_RESTART_JOB
:
445 restart_job(con
, uri
);
448 case IPP_PAUSE_PRINTER
:
449 stop_printer(con
, uri
);
452 case IPP_RESUME_PRINTER
:
453 start_printer(con
, uri
);
456 case IPP_PURGE_JOBS
:
457 cancel_all_jobs(con
, uri
);
460 case IPP_SET_JOB_ATTRIBUTES
:
461 set_job_attrs(con
, uri
);
464 case CUPS_GET_DEFAULT
:
468 case CUPS_GET_PRINTERS
:
469 get_printers(con
, 0);
472 case CUPS_GET_CLASSES
:
473 get_printers(con
, CUPS_PRINTER_CLASS
);
476 case CUPS_ADD_PRINTER
:
477 add_printer(con
, uri
);
480 case CUPS_DELETE_PRINTER
:
481 delete_printer(con
, uri
);
484 case CUPS_ADD_CLASS
:
488 case CUPS_DELETE_CLASS
:
489 delete_printer(con
, uri
);
492 case CUPS_ACCEPT_JOBS
:
493 case IPP_ENABLE_PRINTER
:
494 accept_jobs(con
, uri
);
497 case CUPS_REJECT_JOBS
:
498 case IPP_DISABLE_PRINTER
:
499 reject_jobs(con
, uri
);
502 case CUPS_SET_DEFAULT
:
503 set_default(con
, uri
);
506 case CUPS_GET_DEVICES
:
518 case IPP_CREATE_PRINTER_SUBSCRIPTION
:
519 case IPP_CREATE_JOB_SUBSCRIPTION
:
520 create_subscription(con
, uri
);
523 case IPP_GET_SUBSCRIPTION_ATTRIBUTES
:
524 get_subscription_attrs(con
, sub_id
);
527 case IPP_GET_SUBSCRIPTIONS
:
528 get_subscriptions(con
, uri
);
531 case IPP_RENEW_SUBSCRIPTION
:
532 renew_subscription(con
, sub_id
);
535 case IPP_CANCEL_SUBSCRIPTION
:
536 cancel_subscription(con
, sub_id
);
539 case IPP_GET_NOTIFICATIONS
:
540 get_notifications(con
, sub_id
);
544 cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT
, NULL
, NULL
,
545 "%04X %s Operation %04X (%s) not supported",
546 IPP_OPERATION_NOT_SUPPORTED
, con
->http
.hostname
,
547 con
->request
->request
.op
.operation_id
,
548 ippOpString(con
->request
->request
.op
.operation_id
));
550 send_ipp_error(con
, IPP_OPERATION_NOT_SUPPORTED
);
560 * Sending data from the scheduler...
563 LogMessage(L_DEBUG
, "ProcessIPPRequest: %d status_code=%x (%s)",
564 con
->http
.fd
, con
->response
->request
.status
.status_code
,
565 ippErrorString(con
->response
->request
.status
.status_code
));
567 if (SendHeader(con
, HTTP_OK
, "application/ipp"))
569 if (con
->http
.version
== HTTP_1_1
)
571 con
->http
.data_encoding
= HTTP_ENCODE_CHUNKED
;
573 httpPrintf(HTTP(con
), "Transfer-Encoding: chunked\r\n\r\n");
577 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
578 con
->http
.data_remaining
= ippLength(con
->response
);
580 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
581 con
->http
.data_remaining
);
584 LogMessage(L_DEBUG2
, "ProcessIPPRequest: Adding fd %d to OutputSet...",
587 FD_SET(con
->http
.fd
, OutputSet
);
590 * Tell the caller the response header was sent successfully...
598 * Tell the caller the response header could not be sent...
607 * Sending data from a subprocess like cups-deviced; tell the caller
608 * everything is A-OK so far...
617 * 'accept_jobs()' - Accept print jobs to a printer.
621 accept_jobs(client_t
*con
, /* I - Client connection */
622 ipp_attribute_t
*uri
) /* I - Printer or class URI */
624 cups_ptype_t dtype
; /* Destination type (printer or class) */
625 char method
[HTTP_MAX_URI
], /* Method portion of URI */
626 username
[HTTP_MAX_URI
], /* Username portion of URI */
627 host
[HTTP_MAX_URI
], /* Host portion of URI */
628 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
629 int port
; /* Port portion of URI */
630 const char *name
; /* Printer name */
631 printer_t
*printer
; /* Printer data */
634 LogMessage(L_DEBUG2
, "accept_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
635 uri
->values
[0].string
.text
);
638 * Was this operation called from the correct URI?
641 if (strncmp(con
->uri
, "/admin/", 7) != 0)
643 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
645 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
650 * Is the destination valid?
653 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
655 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
661 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
662 send_ipp_error(con
, IPP_NOT_FOUND
);
670 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
672 LogMessage(L_ERROR
, "accept_jobs: not authorized!");
673 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
678 * Accept jobs sent to the printer...
681 printer
->accepting
= 1;
682 printer
->state_message
[0] = '\0';
684 AddPrinterHistory(printer
);
686 if (dtype
& CUPS_PRINTER_CLASS
)
691 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
695 * Everything was ok, so return OK status...
698 con
->response
->request
.status
.status_code
= IPP_OK
;
703 * 'add_class()' - Add a class to the system.
707 add_class(client_t
*con
, /* I - Client connection */
708 ipp_attribute_t
*uri
) /* I - URI of class */
710 int i
; /* Looping var */
711 char method
[HTTP_MAX_URI
], /* Method portion of URI */
712 username
[HTTP_MAX_URI
], /* Username portion of URI */
713 host
[HTTP_MAX_URI
], /* Host portion of URI */
714 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
715 int port
; /* Port portion of URI */
716 printer_t
*pclass
, /* Class */
717 *member
; /* Member printer/class */
718 cups_ptype_t dtype
; /* Destination type */
719 const char *dest
; /* Printer or class name */
720 ipp_attribute_t
*attr
; /* Printer attribute */
721 int modify
; /* Non-zero if we just modified */
724 LogMessage(L_DEBUG2
, "add_class(%p[%d], %s)\n", con
, con
->http
.fd
,
725 uri
->values
[0].string
.text
);
728 * Was this operation called from the correct URI?
731 if (strncmp(con
->uri
, "/admin/", 7) != 0)
733 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
735 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
740 * Do we have a valid URI?
743 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
745 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
748 * No, return an error...
751 send_ipp_error(con
, IPP_BAD_REQUEST
);
756 * Do we have a valid printer name?
759 if (!validate_name(resource
+ 9))
762 * No, return an error...
765 send_ipp_error(con
, IPP_BAD_REQUEST
);
773 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
775 LogMessage(L_ERROR
, "add_class: not authorized!");
776 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
781 * See if the class already exists; if not, create a new class...
784 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
787 * Class doesn't exist; see if we have a printer of the same name...
790 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
791 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
794 * Yes, return an error...
797 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
802 * No, add the pclass...
805 pclass
= AddClass(resource
+ 9);
808 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
811 * Rename the implicit class to "AnyClass" or remove it...
814 if (ImplicitAnyClasses
)
816 SetStringf(&pclass
->name
, "Any%s", resource
+ 9);
820 DeletePrinter(pclass
, 1);
823 * Add the class as a new local class...
826 pclass
= AddClass(resource
+ 9);
829 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
832 * Rename the remote class to "Class"...
835 DeletePrinterFilters(pclass
);
836 SetStringf(&pclass
->name
, "%s@%s", resource
+ 9, pclass
->hostname
);
837 SetPrinterAttrs(pclass
);
841 * Add the class as a new local class...
844 pclass
= AddClass(resource
+ 9);
851 * Look for attributes and copy them over as needed...
854 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
855 SetString(&pclass
->location
, attr
->values
[0].string
.text
);
857 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
858 SetString(&pclass
->info
, attr
->values
[0].string
.text
);
860 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
862 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
863 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
865 pclass
->accepting
= attr
->values
[0].boolean
;
866 AddPrinterHistory(pclass
);
868 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
870 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
871 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
873 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
874 pclass
->name
, attr
->values
[0].integer
);
875 send_ipp_error(con
, IPP_BAD_REQUEST
);
879 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
880 attr
->values
[0].integer
, pclass
->state
);
882 SetPrinterState(pclass
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
884 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
886 strlcpy(pclass
->state_message
, attr
->values
[0].string
.text
,
887 sizeof(pclass
->state_message
));
888 AddPrinterHistory(pclass
);
890 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
893 SetString(&pclass
->job_sheets
[0], attr
->values
[0].string
.text
);
894 if (attr
->num_values
> 1)
895 SetString(&pclass
->job_sheets
[1], attr
->values
[1].string
.text
);
897 SetString(&pclass
->job_sheets
[1], "none");
899 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
900 IPP_TAG_ZERO
)) != NULL
)
902 FreePrinterUsers(pclass
);
904 pclass
->deny_users
= 0;
905 if (attr
->value_tag
== IPP_TAG_NAME
&&
906 (attr
->num_values
> 1 ||
907 strcmp(attr
->values
[0].string
.text
, "all") != 0))
908 for (i
= 0; i
< attr
->num_values
; i
++)
909 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
911 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
912 IPP_TAG_ZERO
)) != NULL
)
914 FreePrinterUsers(pclass
);
916 pclass
->deny_users
= 1;
917 if (attr
->value_tag
== IPP_TAG_NAME
&&
918 (attr
->num_values
> 1 ||
919 strcmp(attr
->values
[0].string
.text
, "none") != 0))
920 for (i
= 0; i
< attr
->num_values
; i
++)
921 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
923 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
924 IPP_TAG_INTEGER
)) != NULL
)
926 LogMessage(L_DEBUG
, "add_class: Setting job-quota-period to %d...",
927 attr
->values
[0].integer
);
929 pclass
->quota_period
= attr
->values
[0].integer
;
931 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
932 IPP_TAG_INTEGER
)) != NULL
)
934 LogMessage(L_DEBUG
, "add_class: Setting job-k-limit to %d...",
935 attr
->values
[0].integer
);
937 pclass
->k_limit
= attr
->values
[0].integer
;
939 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
940 IPP_TAG_INTEGER
)) != NULL
)
942 LogMessage(L_DEBUG
, "add_class: Setting job-page-limit to %d...",
943 attr
->values
[0].integer
);
945 pclass
->page_limit
= attr
->values
[0].integer
;
947 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
949 policy_t
*p
; /* Policy */
952 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
954 LogMessage(L_DEBUG
, "add_class: Setting printer-op-policy to \"%s\"...",
955 attr
->values
[0].string
.text
);
956 SetString(&pclass
->op_policy
, attr
->values
[0].string
.text
);
957 pclass
->op_policy_ptr
= p
;
961 LogMessage(L_ERROR
, "add_class: Unknown printer-op-policy \"%s\"...",
962 attr
->values
[0].string
.text
);
963 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
967 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
969 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
970 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
971 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
973 LogMessage(L_ERROR
, "add_class: Unknown printer-error-policy \"%s\"...",
974 attr
->values
[0].string
.text
);
975 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
979 LogMessage(L_DEBUG
, "add_class: Setting printer-error-policy to \"%s\"...",
980 attr
->values
[0].string
.text
);
981 SetString(&pclass
->error_policy
, attr
->values
[0].string
.text
);
983 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
986 * Clear the printer array as needed...
989 if (pclass
->num_printers
> 0)
991 free(pclass
->printers
);
992 pclass
->num_printers
= 0;
996 * Add each printer or class that is listed...
999 for (i
= 0; i
< attr
->num_values
; i
++)
1002 * Search for the printer or class URI...
1005 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
1008 if ((dest
= ValidateDest(host
, resource
, &dtype
, &member
)) == NULL
)
1014 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
1015 send_ipp_error(con
, IPP_NOT_FOUND
);
1020 * Add it to the class...
1023 AddPrinterToClass(pclass
, member
);
1028 * Update the printer class attributes and return...
1031 SetPrinterAttrs(pclass
);
1039 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, pclass
, NULL
,
1040 "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1043 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
1048 AddPrinterHistory(pclass
);
1050 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, pclass
, NULL
,
1051 "New class \'%s\' added by \'%s\'.", pclass
->name
,
1054 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
1058 con
->response
->request
.status
.status_code
= IPP_OK
;
1063 * 'add_file()' - Add a file to a job.
1066 static int /* O - 0 on success, -1 on error */
1067 add_file(client_t
*con
, /* I - Connection to client */
1068 job_t
*job
, /* I - Job to add to */
1069 mime_type_t
*filetype
, /* I - Type of file */
1070 int compression
) /* I - Compression */
1072 mime_type_t
**filetypes
; /* New filetypes array... */
1073 int *compressions
; /* New compressions array... */
1076 LogMessage(L_DEBUG2
, "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)\n",
1077 con
, con
->http
.fd
, job
->id
, filetype
->super
, filetype
->type
,
1081 * Add the file to the job...
1084 if (job
->num_files
== 0)
1086 compressions
= (int *)malloc(sizeof(int));
1087 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
1091 compressions
= (int *)realloc(job
->compressions
,
1092 (job
->num_files
+ 1) * sizeof(int));
1093 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
1094 (job
->num_files
+ 1) *
1095 sizeof(mime_type_t
*));
1098 if (compressions
== NULL
|| filetypes
== NULL
)
1100 CancelJob(job
->id
, 1);
1101 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
1102 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1106 job
->compressions
= compressions
;
1107 job
->compressions
[job
->num_files
] = compression
;
1108 job
->filetypes
= filetypes
;
1109 job
->filetypes
[job
->num_files
] = filetype
;
1118 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
1119 * upon the job and printer state...
1123 add_job_state_reasons(client_t
*con
, /* I - Client connection */
1124 job_t
*job
) /* I - Job info */
1126 printer_t
*dest
; /* Destination printer */
1129 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
1132 switch (job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
)
1134 case IPP_JOB_PENDING
:
1135 if (job
->dtype
& CUPS_PRINTER_CLASS
)
1136 dest
= FindClass(job
->dest
);
1138 dest
= FindPrinter(job
->dest
);
1140 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
1141 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1142 "job-state-reasons", NULL
, "printer-stopped");
1144 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1145 "job-state-reasons", NULL
, "none");
1149 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
1150 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
1151 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1152 "job-state-reasons", NULL
, "job-hold-until-specified");
1154 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1155 "job-state-reasons", NULL
, "job-incoming");
1158 case IPP_JOB_PROCESSING
:
1159 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1160 "job-state-reasons", NULL
, "job-printing");
1163 case IPP_JOB_STOPPED
:
1164 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1165 "job-state-reasons", NULL
, "job-stopped");
1168 case IPP_JOB_CANCELLED
:
1169 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1170 "job-state-reasons", NULL
, "job-canceled-by-user");
1173 case IPP_JOB_ABORTED
:
1174 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1175 "job-state-reasons", NULL
, "aborted-by-system");
1178 case IPP_JOB_COMPLETED
:
1179 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
1180 "job-state-reasons", NULL
, "job-completed-successfully");
1187 * 'add_job_subscriptions()' - Add any subcriptions for a job.
1191 add_job_subscriptions(client_t
*con
, /* I - Client connection */
1192 job_t
*job
) /* I - Newly created job */
1194 int i
; /* Looping var */
1195 ipp_attribute_t
*prev
, /* Previous attribute */
1196 *next
, /* Next attribute */
1197 *attr
; /* Current attribute */
1198 cupsd_subscription_t
*sub
; /* Subscription object */
1199 const char *recipient
, /* notify-recipient-uri */
1200 *pullmethod
; /* notify-pull-method */
1201 ipp_attribute_t
*user_data
; /* notify-user-data */
1202 int interval
; /* notify-time-interval */
1203 unsigned mask
; /* notify-events */
1207 * Find the first subscription group attribute; return if we have
1211 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; prev
= attr
, attr
= attr
->next
)
1212 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
)
1219 * Process the subscription attributes in the request...
1228 mask
= CUPSD_EVENT_NONE
;
1230 while (attr
&& attr
->group_tag
!= IPP_TAG_ZERO
)
1232 if (!strcmp(attr
->name
, "notify-recipient") &&
1233 attr
->value_tag
== IPP_TAG_URI
)
1234 recipient
= attr
->values
[0].string
.text
;
1235 else if (!strcmp(attr
->name
, "notify-pull-method") &&
1236 attr
->value_tag
== IPP_TAG_KEYWORD
)
1237 pullmethod
= attr
->values
[0].string
.text
;
1238 else if (!strcmp(attr
->name
, "notify-charset") &&
1239 attr
->value_tag
== IPP_TAG_CHARSET
&&
1240 strcmp(attr
->values
[0].string
.text
, "utf-8"))
1242 send_ipp_error(con
, IPP_CHARSET
);
1245 else if (!strcmp(attr
->name
, "notify-natural-language") &&
1246 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
1247 strcmp(attr
->values
[0].string
.text
, DefaultLanguage
))
1249 send_ipp_error(con
, IPP_CHARSET
);
1252 else if (!strcmp(attr
->name
, "notify-user-data") &&
1253 attr
->value_tag
== IPP_TAG_STRING
)
1255 if (attr
->num_values
> 1 || attr
->values
[0].unknown
.length
> 63)
1257 send_ipp_error(con
, IPP_REQUEST_VALUE
);
1263 else if (!strcmp(attr
->name
, "notify-events") &&
1264 attr
->value_tag
== IPP_TAG_KEYWORD
)
1266 for (i
= 0; i
< attr
->num_values
; i
++)
1267 mask
|= cupsdEventValue(attr
->values
[i
].string
.text
);
1269 else if (!strcmp(attr
->name
, "notify-lease-time"))
1271 send_ipp_error(con
, IPP_BAD_REQUEST
);
1274 else if (!strcmp(attr
->name
, "notify-time-interval") &&
1275 attr
->value_tag
== IPP_TAG_INTEGER
)
1276 interval
= attr
->values
[0].integer
;
1281 if (!recipient
&& !pullmethod
)
1284 if (mask
== CUPSD_EVENT_NONE
)
1285 mask
= CUPSD_EVENT_JOB_COMPLETED
;
1287 sub
= cupsdAddSubscription(mask
, FindDest(job
->dest
), job
, recipient
);
1289 sub
->interval
= interval
;
1291 SetString(&sub
->owner
, job
->username
);
1295 sub
->user_data_len
= user_data
->values
[0].unknown
.length
;
1296 memcpy(sub
->user_data
, user_data
->values
[0].unknown
.data
,
1297 sub
->user_data_len
);
1305 * Remove all of the subscription attributes from the job request...
1308 for (attr
= job
->attrs
->attrs
, prev
= NULL
; attr
; attr
= next
)
1312 if (attr
->group_tag
== IPP_TAG_SUBSCRIPTION
||
1313 attr
->group_tag
== IPP_TAG_ZERO
)
1316 * Free and remove this attribute...
1319 _ipp_free_attr(attr
);
1324 job
->attrs
->attrs
= next
;
1330 job
->attrs
->last
= prev
;
1331 job
->attrs
->current
= prev
;
1336 * 'add_printer()' - Add a printer to the system.
1340 add_printer(client_t
*con
, /* I - Client connection */
1341 ipp_attribute_t
*uri
) /* I - URI of printer */
1343 int i
; /* Looping var */
1344 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1345 username
[HTTP_MAX_URI
], /* Username portion of URI */
1346 host
[HTTP_MAX_URI
], /* Host portion of URI */
1347 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1348 int port
; /* Port portion of URI */
1349 printer_t
*printer
; /* Printer/class */
1350 ipp_attribute_t
*attr
; /* Printer attribute */
1351 cups_file_t
*fp
; /* Script/PPD file */
1352 char line
[1024]; /* Line from file... */
1353 char srcfile
[1024], /* Source Script/PPD file */
1354 dstfile
[1024]; /* Destination Script/PPD file */
1355 int modify
; /* Non-zero if we are modifying */
1358 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
1359 uri
->values
[0].string
.text
);
1362 * Was this operation called from the correct URI?
1365 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1367 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
1369 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1374 * Do we have a valid URI?
1377 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1379 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1382 * No, return an error...
1385 LogMessage(L_ERROR
, "add_printer: bad printer URI \"%s\"!",
1386 uri
->values
[0].string
.text
);
1387 send_ipp_error(con
, IPP_BAD_REQUEST
);
1392 * Do we have a valid printer name?
1395 if (!validate_name(resource
+ 10))
1398 * No, return an error...
1401 send_ipp_error(con
, IPP_BAD_REQUEST
);
1409 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
1411 LogMessage(L_ERROR
, "add_printer: not authorized!");
1412 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1417 * See if the printer already exists; if not, create a new printer...
1420 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1423 * Printer doesn't exist; see if we have a class of the same name...
1426 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1427 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1430 * Yes, return an error...
1433 LogMessage(L_ERROR
, "add_printer: \"%s\" already exists as a class!",
1435 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1440 * No, add the printer...
1443 printer
= AddPrinter(resource
+ 10);
1446 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1449 * Rename the implicit printer to "AnyPrinter" or delete it...
1452 if (ImplicitAnyClasses
)
1454 SetStringf(&printer
->name
, "Any%s", resource
+ 10);
1458 DeletePrinter(printer
, 1);
1461 * Add the printer as a new local printer...
1464 printer
= AddPrinter(resource
+ 10);
1467 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1470 * Rename the remote printer to "Printer@server"...
1473 DeletePrinterFilters(printer
);
1474 SetStringf(&printer
->name
, "%s@%s", resource
+ 10, printer
->hostname
);
1475 SetPrinterAttrs(printer
);
1479 * Add the printer as a new local printer...
1482 printer
= AddPrinter(resource
+ 10);
1489 * Look for attributes and copy them over as needed...
1492 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1493 SetString(&printer
->location
, attr
->values
[0].string
.text
);
1495 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1496 SetString(&printer
->info
, attr
->values
[0].string
.text
);
1498 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1500 ipp_attribute_t
*device
; /* Current device */
1501 int methodlen
; /* Length of method string */
1505 * Do we have a valid device URI?
1508 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1510 methodlen
= strlen(method
);
1512 if (strcmp(method
, "file") == 0)
1515 * See if the administrator has enabled file devices...
1518 if (!FileDevice
&& strcmp(resource
, "/dev/null"))
1521 * File devices are disabled and the URL is not file:/dev/null...
1524 LogMessage(L_ERROR
, "add_printer: File device URIs have been disabled! "
1525 "To enable, see the FileDevice directive in cupsd.conf.");
1526 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1533 * See if the backend is listed as a device...
1536 #if 0 /* ADD THIS BACK IN SOMEHOW */
1537 for (device
= ippFindAttribute(Devices
, "device-uri", IPP_TAG_URI
);
1539 device
= ippFindNextAttribute(Devices
, "device-uri", IPP_TAG_URI
))
1540 if (strncmp(method
, device
->values
[0].string
.text
, methodlen
) == 0 &&
1541 (device
->values
[0].string
.text
[methodlen
] == ':' ||
1542 device
->values
[0].string
.text
[methodlen
] == '\0'))
1548 * Could not find device in list!
1551 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1552 attr
->values
[0].string
.text
);
1553 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1559 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1561 cupsdSanitizeURI(attr
->values
[0].string
.text
, line
, sizeof(line
)),
1562 cupsdSanitizeURI(printer
->device_uri
, resource
, sizeof(resource
)));
1564 SetString(&printer
->device_uri
, attr
->values
[0].string
.text
);
1567 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1569 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1570 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1572 printer
->accepting
= attr
->values
[0].boolean
;
1573 AddPrinterHistory(printer
);
1575 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1577 if (attr
->values
[0].integer
!= IPP_PRINTER_IDLE
&&
1578 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1580 LogMessage(L_ERROR
, "Attempt to set %s printer-state to bad value %d!",
1581 printer
->name
, attr
->values
[0].integer
);
1582 send_ipp_error(con
, IPP_BAD_REQUEST
);
1586 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1587 attr
->values
[0].integer
, printer
->state
);
1589 SetPrinterState(printer
, (ipp_pstate_t
)(attr
->values
[0].integer
), 0);
1591 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1593 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
1594 sizeof(printer
->state_message
));
1595 AddPrinterHistory(printer
);
1597 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1600 SetString(&printer
->job_sheets
[0], attr
->values
[0].string
.text
);
1601 if (attr
->num_values
> 1)
1602 SetString(&printer
->job_sheets
[1], attr
->values
[1].string
.text
);
1604 SetString(&printer
->job_sheets
[1], "none");
1606 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1607 IPP_TAG_ZERO
)) != NULL
)
1609 FreePrinterUsers(printer
);
1611 printer
->deny_users
= 0;
1612 if (attr
->value_tag
== IPP_TAG_NAME
&&
1613 (attr
->num_values
> 1 ||
1614 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1615 for (i
= 0; i
< attr
->num_values
; i
++)
1616 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1618 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1619 IPP_TAG_ZERO
)) != NULL
)
1621 FreePrinterUsers(printer
);
1623 printer
->deny_users
= 1;
1624 if (attr
->value_tag
== IPP_TAG_NAME
&&
1625 (attr
->num_values
> 1 ||
1626 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1627 for (i
= 0; i
< attr
->num_values
; i
++)
1628 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1630 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1631 IPP_TAG_INTEGER
)) != NULL
)
1633 LogMessage(L_DEBUG
, "add_printer: Setting job-quota-period to %d...",
1634 attr
->values
[0].integer
);
1635 FreeQuotas(printer
);
1636 printer
->quota_period
= attr
->values
[0].integer
;
1638 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1639 IPP_TAG_INTEGER
)) != NULL
)
1641 LogMessage(L_DEBUG
, "add_printer: Setting job-k-limit to %d...",
1642 attr
->values
[0].integer
);
1643 FreeQuotas(printer
);
1644 printer
->k_limit
= attr
->values
[0].integer
;
1646 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1647 IPP_TAG_INTEGER
)) != NULL
)
1649 LogMessage(L_DEBUG
, "add_printer: Setting job-page-limit to %d...",
1650 attr
->values
[0].integer
);
1651 FreeQuotas(printer
);
1652 printer
->page_limit
= attr
->values
[0].integer
;
1654 if ((attr
= ippFindAttribute(con
->request
, "printer-op-policy", IPP_TAG_TEXT
)) != NULL
)
1656 policy_t
*p
; /* Policy */
1659 if ((p
= FindPolicy(attr
->values
[0].string
.text
)) != NULL
)
1661 LogMessage(L_DEBUG
, "add_printer: Setting printer-op-policy to \"%s\"...",
1662 attr
->values
[0].string
.text
);
1663 SetString(&printer
->op_policy
, attr
->values
[0].string
.text
);
1664 printer
->op_policy_ptr
= p
;
1668 LogMessage(L_ERROR
, "add_printer: Unknown printer-op-policy \"%s\"...",
1669 attr
->values
[0].string
.text
);
1670 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1674 if ((attr
= ippFindAttribute(con
->request
, "printer-error-policy", IPP_TAG_TEXT
)) != NULL
)
1676 if (strcmp(attr
->values
[0].string
.text
, "abort-job") &&
1677 strcmp(attr
->values
[0].string
.text
, "retry-job") &&
1678 strcmp(attr
->values
[0].string
.text
, "stop-printer"))
1680 LogMessage(L_ERROR
, "add_printer: Unknown printer-error-policy \"%s\"...",
1681 attr
->values
[0].string
.text
);
1682 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1686 LogMessage(L_DEBUG
, "add_printer: Setting printer-error-policy to \"%s\"...",
1687 attr
->values
[0].string
.text
);
1688 SetString(&printer
->error_policy
, attr
->values
[0].string
.text
);
1692 * See if we have all required attributes...
1695 if (!printer
->device_uri
)
1696 SetString(&printer
->device_uri
, "file:/dev/null");
1699 * See if we have an interface script or PPD file attached to the request...
1704 strlcpy(srcfile
, con
->filename
, sizeof(srcfile
));
1706 if ((fp
= cupsFileOpen(srcfile
, "rb")) != NULL
)
1709 * Yes; get the first line from it...
1713 cupsFileGets(fp
, line
, sizeof(line
));
1717 * Then see what kind of file it is...
1720 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1723 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1726 * The new file is a PPD file, so remove any old interface script
1727 * that might be lying around...
1735 * This must be an interface script, so move the file over to the
1736 * interfaces directory and make it executable...
1739 if (copy_file(srcfile
, dstfile
))
1741 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1742 srcfile
, dstfile
, strerror(errno
));
1743 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1748 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1749 chmod(dstfile
, 0755);
1753 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1756 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1759 * The new file is a PPD file, so move the file over to the
1760 * ppd directory and make it readable by all...
1763 if (copy_file(srcfile
, dstfile
))
1765 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1766 srcfile
, dstfile
, strerror(errno
));
1767 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1772 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1773 chmod(dstfile
, 0644);
1779 * This must be an interface script, so remove any old PPD file that
1780 * may be lying around...
1787 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1789 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1792 * Raw driver, remove any existing PPD or interface script files.
1795 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1799 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1809 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1810 attr
->values
[0].string
.text
);
1812 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1816 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1819 if (copy_model(srcfile
, dstfile
))
1821 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1822 srcfile
, dstfile
, strerror(errno
));
1823 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1828 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1829 chmod(dstfile
, 0644);
1835 * Make this printer the default if there is none...
1838 if (DefaultPrinter
== NULL
)
1839 DefaultPrinter
= printer
;
1842 * Update the printer attributes and return...
1845 SetPrinterAttrs(printer
);
1848 if (printer
->job
!= NULL
)
1853 * Stop the current job and then restart it below...
1856 job
= (job_t
*)printer
->job
;
1858 StopJob(job
->id
, 1);
1859 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1868 cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED
, printer
, NULL
,
1869 "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1872 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1877 AddPrinterHistory(printer
);
1879 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, printer
, NULL
,
1880 "New printer \'%s\' added by \'%s\'.", printer
->name
,
1883 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1887 con
->response
->request
.status
.status_code
= IPP_OK
;
1892 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1893 * based upon the printer state...
1897 add_printer_state_reasons(
1898 client_t
*con
, /* I - Client connection */
1899 printer_t
*p
) /* I - Printer info */
1901 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1902 con
, con
->http
.fd
, p
, p
->name
);
1904 if (p
->num_reasons
== 0)
1905 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1906 "printer-state-reasons", NULL
,
1907 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
1909 ippAddStrings(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1910 "printer-state-reasons", p
->num_reasons
, NULL
,
1911 (const char * const *)p
->reasons
);
1916 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1917 * the specified printer or class.
1921 add_queued_job_count(client_t
*con
, /* I - Client connection */
1922 printer_t
*p
) /* I - Printer or class */
1924 int count
; /* Number of jobs on destination */
1927 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1928 con
, con
->http
.fd
, p
, p
->name
);
1930 count
= GetPrinterJobCount(p
->name
);
1932 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1933 "queued-job-count", count
);
1938 * 'cancel_all_jobs()' - Cancel all print jobs.
1942 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1943 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1945 const char *dest
; /* Destination */
1946 cups_ptype_t dtype
; /* Destination type */
1947 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1948 userpass
[HTTP_MAX_URI
], /* Username portion of URI */
1949 host
[HTTP_MAX_URI
], /* Host portion of URI */
1950 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1951 int port
; /* Port portion of URI */
1952 ipp_attribute_t
*attr
; /* Attribute in request */
1953 const char *username
; /* Username */
1954 int purge
; /* Purge? */
1955 printer_t
*printer
; /* Printer */
1958 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
1959 uri
->values
[0].string
.text
);
1962 * Was this operation called from the correct URI?
1965 if (strncmp(con
->uri
, "/admin/", 7) &&
1966 strncmp(con
->uri
, "/jobs/", 7))
1968 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
1970 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1975 * See if we have a printer URI...
1978 if (strcmp(uri
->name
, "printer-uri"))
1980 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
1981 uri
->name
, uri
->values
[0].string
.text
);
1982 send_ipp_error(con
, IPP_BAD_REQUEST
);
1987 * Get the username (if any) for the jobs we want to cancel (only if
1988 * "my-jobs" is specified...
1991 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
1992 attr
->values
[0].boolean
)
1994 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
1995 username
= attr
->values
[0].string
.text
;
1998 LogMessage(L_ERROR
, "cancel_all_jobs: missing requesting-user-name attribute!");
1999 send_ipp_error(con
, IPP_BAD_REQUEST
);
2007 (username
&& con
->username
[0] && strcmp(username
, con
->username
))) &&
2008 strncmp(con
->uri
, "/admin/", 7))
2010 LogMessage(L_ERROR
, "cancel_all_jobs: only administrators can cancel "
2011 "other users\' jobs!");
2012 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2017 * Look for the "purge-jobs" attribute...
2020 if ((attr
= ippFindAttribute(con
->request
, "purge-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
2021 purge
= attr
->values
[0].boolean
;
2026 * And if the destination is valid...
2029 httpSeparate(uri
->values
[0].string
.text
, method
, userpass
, host
, &port
,
2032 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2038 if (strcmp(resource
, "/printers/") != 0)
2040 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
2041 send_ipp_error(con
, IPP_NOT_FOUND
);
2049 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
2051 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2052 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2057 * Cancel all jobs on all printers...
2060 CancelJobs(NULL
, username
, purge
);
2062 LogMessage(L_INFO
, "All jobs were %s by \'%s\'.",
2063 purge
? "purged" : "cancelled", con
->username
);
2071 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
2073 LogMessage(L_ERROR
, "cancel_all_jobs: not authorized!");
2074 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2079 * Cancel all of the jobs on the named printer...
2082 CancelJobs(dest
, username
, purge
);
2084 LogMessage(L_INFO
, "All jobs on \'%s\' were %s by \'%s\'.", dest
,
2085 purge
? "purged" : "cancelled", con
->username
);
2088 con
->response
->request
.status
.status_code
= IPP_OK
;
2093 * 'cancel_job()' - Cancel a print job.
2097 cancel_job(client_t
*con
, /* I - Client connection */
2098 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
2100 ipp_attribute_t
*attr
; /* Current attribute */
2101 int jobid
; /* Job ID */
2102 char method
[HTTP_MAX_URI
], /* Method portion of URI */
2103 username
[HTTP_MAX_URI
], /* Username portion of URI */
2104 host
[HTTP_MAX_URI
], /* Host portion of URI */
2105 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2106 int port
; /* Port portion of URI */
2107 job_t
*job
; /* Job information */
2108 const char *dest
; /* Destination */
2109 cups_ptype_t dtype
; /* Destination type (printer or class) */
2110 printer_t
*printer
; /* Printer data */
2113 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2114 uri
->values
[0].string
.text
);
2117 * Verify that the POST operation was done to a valid URI.
2120 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2121 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
2122 strncmp(con
->uri
, "/printers/", 10) != 0)
2124 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
2126 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2131 * See if we have a job URI or a printer URI...
2134 if (strcmp(uri
->name
, "printer-uri") == 0)
2137 * Got a printer URI; see if we also have a job-id attribute...
2140 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
2142 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
2143 send_ipp_error(con
, IPP_BAD_REQUEST
);
2147 if ((jobid
= attr
->values
[0].integer
) == 0)
2150 * Find the current job on the specified printer...
2153 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2155 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
2161 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
2162 send_ipp_error(con
, IPP_NOT_FOUND
);
2167 * See if the printer is currently printing a job...
2171 jobid
= ((job_t
*)printer
->job
)->id
;
2175 * No, see if there are any pending jobs...
2178 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
2179 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
2180 strcasecmp(job
->dest
, dest
) == 0)
2187 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
2188 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2197 * Got a job URI; parse it to get the job ID...
2200 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2202 if (strncmp(resource
, "/jobs/", 6) != 0)
2208 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
2209 uri
->values
[0].string
.text
);
2210 send_ipp_error(con
, IPP_BAD_REQUEST
);
2214 jobid
= atoi(resource
+ 6);
2218 * See if the job exists...
2221 if ((job
= FindJob(jobid
)) == NULL
)
2224 * Nope - return a "not found" error...
2227 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
2228 send_ipp_error(con
, IPP_NOT_FOUND
);
2233 * See if the job is owned by the requesting user...
2236 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
2238 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
2239 username
, jobid
, job
->username
);
2240 send_ipp_error(con
, IPP_FORBIDDEN
);
2245 * See if the job is already completed, cancelled, or aborted; if so,
2246 * we can't cancel...
2249 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
2251 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
2253 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
2254 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
2256 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2261 * Cancel the job and return...
2264 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED
, job
->printer
, job
,
2265 "Job cancelled by \'%s\'.", username
);
2267 CancelJob(jobid
, 0);
2270 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
2272 con
->response
->request
.status
.status_code
= IPP_OK
;
2277 * 'cancel_subscription()' - Cancel a subscription.
2281 cancel_subscription(client_t
*con
, /* I - Client connection */
2282 int sub_id
) /* I - Subscription ID */
2288 * 'check_quotas()' - Check quotas for a printer and user.
2291 static int /* O - 1 if OK, 0 if not */
2292 check_quotas(client_t
*con
, /* I - Client connection */
2293 printer_t
*p
) /* I - Printer or class */
2295 int i
, j
; /* Looping vars */
2296 ipp_attribute_t
*attr
; /* Current attribute */
2297 char username
[33]; /* Username */
2298 quota_t
*q
; /* Quota data */
2299 struct passwd
*pw
; /* User password data */
2300 struct group
*grp
; /* Group data */
2303 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
2304 con
, con
->http
.fd
, p
, p
->name
);
2310 if (con
== NULL
|| p
== NULL
)
2314 * Figure out who is printing...
2317 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
2319 if (con
->username
[0])
2320 strlcpy(username
, con
->username
, sizeof(username
));
2321 else if (attr
!= NULL
)
2323 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
2324 attr
->values
[0].string
.text
);
2326 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
2329 strcpy(username
, "anonymous");
2332 * Check global active job limits for printers and users...
2335 if (MaxJobsPerPrinter
)
2338 * Check if there are too many pending jobs on this printer...
2341 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
2343 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
2351 * Check if there are too many pending jobs for this user...
2354 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
2356 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
2362 * Check against users...
2365 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
2370 pw
= getpwnam(username
);
2373 for (i
= 0; i
< p
->num_users
; i
++)
2374 if (p
->users
[i
][0] == '@')
2377 * Check group membership...
2380 grp
= getgrnam(p
->users
[i
] + 1);
2386 * Check primary group...
2389 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
2393 * Check usernames in group...
2396 for (j
= 0; grp
->gr_mem
[j
]; j
++)
2397 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
2404 else if (!strcasecmp(username
, p
->users
[i
]))
2407 if ((i
< p
->num_users
) == p
->deny_users
)
2409 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
2419 if (p
->k_limit
|| p
->page_limit
)
2421 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
2423 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
2428 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
2429 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
2431 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
2438 * If we have gotten this far, we're done!
2446 * 'copy_attribute()' - Copy a single attribute.
2449 static ipp_attribute_t
* /* O - New attribute */
2451 ipp_t
*to
, /* O - Destination request/response */
2452 ipp_attribute_t
*attr
, /* I - Attribute to copy */
2453 int quickcopy
) /* I - Do a quick copy? */
2455 int i
; /* Looping var */
2456 ipp_attribute_t
*toattr
; /* Destination attribute */
2459 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
2460 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
2463 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2466 toattr
= ippAddSeparator(to
);
2469 case IPP_TAG_INTEGER
:
2471 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2472 attr
->name
, attr
->num_values
, NULL
);
2474 for (i
= 0; i
< attr
->num_values
; i
++)
2475 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
2478 case IPP_TAG_BOOLEAN
:
2479 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
2480 attr
->num_values
, NULL
);
2482 for (i
= 0; i
< attr
->num_values
; i
++)
2483 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
2486 case IPP_TAG_STRING
:
2489 case IPP_TAG_KEYWORD
:
2491 case IPP_TAG_URISCHEME
:
2492 case IPP_TAG_CHARSET
:
2493 case IPP_TAG_LANGUAGE
:
2494 case IPP_TAG_MIMETYPE
:
2495 toattr
= ippAddStrings(to
, attr
->group_tag
,
2496 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2497 attr
->name
, attr
->num_values
, NULL
, NULL
);
2501 for (i
= 0; i
< attr
->num_values
; i
++)
2502 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2506 for (i
= 0; i
< attr
->num_values
; i
++)
2507 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2512 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
2513 attr
->values
[0].date
);
2516 case IPP_TAG_RESOLUTION
:
2517 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
2518 attr
->num_values
, IPP_RES_PER_INCH
,
2521 for (i
= 0; i
< attr
->num_values
; i
++)
2523 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
2524 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
2525 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
2529 case IPP_TAG_RANGE
:
2530 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
2531 attr
->num_values
, NULL
, NULL
);
2533 for (i
= 0; i
< attr
->num_values
; i
++)
2535 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
2536 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
2540 case IPP_TAG_TEXTLANG
:
2541 case IPP_TAG_NAMELANG
:
2542 toattr
= ippAddStrings(to
, attr
->group_tag
,
2543 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
2544 attr
->name
, attr
->num_values
, NULL
, NULL
);
2548 for (i
= 0; i
< attr
->num_values
; i
++)
2550 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
2551 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
2556 for (i
= 0; i
< attr
->num_values
; i
++)
2559 toattr
->values
[i
].string
.charset
=
2560 strdup(attr
->values
[i
].string
.charset
);
2562 toattr
->values
[i
].string
.charset
=
2563 toattr
->values
[0].string
.charset
;
2565 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
2570 case IPP_TAG_BEGIN_COLLECTION
:
2571 toattr
= ippAddCollections(to
, attr
->group_tag
, attr
->name
,
2572 attr
->num_values
, NULL
);
2574 for (i
= 0; i
< attr
->num_values
; i
++)
2576 toattr
->values
[i
].collection
= ippNew();
2577 copy_attrs(toattr
->values
[i
].collection
, attr
->values
[i
].collection
,
2578 NULL
, IPP_TAG_ZERO
, 0);
2583 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
2584 attr
->name
, attr
->num_values
, NULL
);
2586 for (i
= 0; i
< attr
->num_values
; i
++)
2588 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
2590 if (toattr
->values
[i
].unknown
.length
> 0)
2592 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
2593 toattr
->values
[i
].unknown
.length
= 0;
2595 memcpy(toattr
->values
[i
].unknown
.data
,
2596 attr
->values
[i
].unknown
.data
,
2597 toattr
->values
[i
].unknown
.length
);
2600 break; /* anti-compiler-warning-code */
2608 * 'copy_attrs()' - Copy attributes from one request to another.
2612 copy_attrs(ipp_t
*to
, /* I - Destination request */
2613 ipp_t
*from
, /* I - Source request */
2614 ipp_attribute_t
*req
, /* I - Requested attributes */
2615 ipp_tag_t group
, /* I - Group to copy */
2616 int quickcopy
) /* I - Do a quick copy? */
2618 int i
; /* Looping var */
2619 ipp_attribute_t
*fromattr
; /* Source attribute */
2622 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2624 if (to
== NULL
|| from
== NULL
)
2627 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2628 req
= NULL
; /* "all" means no filter... */
2630 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2633 * Filter attributes as needed...
2636 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2637 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2640 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2642 for (i
= 0; i
< req
->num_values
; i
++)
2643 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2646 if (i
== req
->num_values
)
2650 copy_attribute(to
, fromattr
, quickcopy
);
2656 * 'copy_banner()' - Copy a banner file to the requests directory for the
2660 static int /* O - Size of banner file in kbytes */
2661 copy_banner(client_t
*con
, /* I - Client connection */
2662 job_t
*job
, /* I - Job information */
2663 const char *name
) /* I - Name of banner */
2665 int i
; /* Looping var */
2666 int kbytes
; /* Size of banner file in kbytes */
2667 char filename
[1024]; /* Job filename */
2668 banner_t
*banner
; /* Pointer to banner */
2669 cups_file_t
*in
; /* Input file */
2670 cups_file_t
*out
; /* Output file */
2671 int ch
; /* Character from file */
2672 char attrname
[255], /* Name of attribute */
2673 *s
; /* Pointer into name */
2674 ipp_attribute_t
*attr
; /* Attribute */
2677 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2678 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2681 * Find the banner; return if not found or "none"...
2685 strcmp(name
, "none") == 0 ||
2686 (banner
= FindBanner(name
)) == NULL
)
2690 * Open the banner and job files...
2693 if (add_file(con
, job
, banner
->filetype
, 0))
2696 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2698 if ((out
= cupsFileOpen(filename
, "w")) == NULL
)
2700 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2701 filename
, strerror(errno
));
2706 fchmod(cupsFileNumber(out
), 0640);
2707 fchown(cupsFileNumber(out
), RunUser
, Group
);
2712 * Try the localized banner file under the subdirectory...
2715 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2716 con
->language
->language
, name
);
2718 if (access(filename
, 0) && con
->language
->language
[2])
2721 * Wasn't able to find "ll_CC" locale file; try the non-national
2722 * localization banner directory.
2725 attrname
[0] = con
->language
->language
[0];
2726 attrname
[1] = con
->language
->language
[1];
2729 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2733 if (access(filename
, 0))
2736 * Use the non-localized banner file.
2739 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2745 * Use the non-localized banner file.
2748 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2751 if ((in
= cupsFileOpen(filename
, "r")) == NULL
)
2755 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2756 filename
, strerror(errno
));
2762 * Parse the file to the end...
2765 while ((ch
= cupsFileGetChar(in
)) != EOF
)
2769 * Get an attribute name...
2772 for (s
= attrname
; (ch
= cupsFileGetChar(in
)) != EOF
;)
2773 if (!isalpha(ch
& 255) && ch
!= '-' && ch
!= '?')
2775 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2785 * Ignore { followed by stuff that is not an attribute name...
2788 cupsFilePrintf(out
, "{%s%c", attrname
, ch
);
2793 * See if it is defined...
2796 if (attrname
[0] == '?')
2801 if (strcmp(s
, "printer-name") == 0)
2803 cupsFilePuts(out
, job
->dest
);
2806 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2809 * See if we have a leading question mark...
2812 if (attrname
[0] != '?')
2815 * Nope, write to file as-is; probably a PostScript procedure...
2818 cupsFilePrintf(out
, "{%s}", attrname
);
2825 * Output value(s)...
2828 for (i
= 0; i
< attr
->num_values
; i
++)
2831 cupsFilePutChar(out
, ',');
2833 switch (attr
->value_tag
)
2835 case IPP_TAG_INTEGER
:
2837 if (strncmp(s
, "time-at-", 8) == 0)
2838 cupsFilePuts(out
, GetDateTime(attr
->values
[i
].integer
));
2840 cupsFilePrintf(out
, "%d", attr
->values
[i
].integer
);
2843 case IPP_TAG_BOOLEAN
:
2844 cupsFilePrintf(out
, "%d", attr
->values
[i
].boolean
);
2847 case IPP_TAG_NOVALUE
:
2848 cupsFilePuts(out
, "novalue");
2851 case IPP_TAG_RANGE
:
2852 cupsFilePrintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2853 attr
->values
[i
].range
.upper
);
2856 case IPP_TAG_RESOLUTION
:
2857 cupsFilePrintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2858 attr
->values
[i
].resolution
.yres
,
2859 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2864 case IPP_TAG_STRING
:
2867 case IPP_TAG_KEYWORD
:
2868 case IPP_TAG_CHARSET
:
2869 case IPP_TAG_LANGUAGE
:
2870 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2873 * Need to quote strings for PS banners...
2878 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2880 if (*p
== '(' || *p
== ')' || *p
== '\\')
2882 cupsFilePutChar(out
, '\\');
2883 cupsFilePutChar(out
, *p
);
2885 else if (*p
< 32 || *p
> 126)
2886 cupsFilePrintf(out
, "\\%03o", *p
& 255);
2888 cupsFilePutChar(out
, *p
);
2892 cupsFilePuts(out
, attr
->values
[i
].string
.text
);
2896 break; /* anti-compiler-warning-code */
2900 else if (ch
== '\\') /* Quoted char */
2902 ch
= cupsFileGetChar(in
);
2904 if (ch
!= '{') /* Only do special handling for \{ */
2905 cupsFilePutChar(out
, '\\');
2907 cupsFilePutChar(out
, ch
);
2910 cupsFilePutChar(out
, ch
);
2914 kbytes
= (cupsFileTell(out
) + 1023) / 1024;
2916 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2917 attr
->values
[0].integer
+= kbytes
;
2926 * 'copy_file()' - Copy a PPD file or interface script...
2929 static int /* O - 0 = success, -1 = error */
2930 copy_file(const char *from
, /* I - Source file */
2931 const char *to
) /* I - Destination file */
2933 cups_file_t
*src
, /* Source file */
2934 *dst
; /* Destination file */
2935 int bytes
; /* Bytes to read/write */
2936 char buffer
[2048]; /* Copy buffer */
2939 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
2942 * Open the source and destination file for a copy...
2945 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
2948 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
2955 * Copy the source file to the destination...
2958 while ((bytes
= cupsFileRead(src
, buffer
, sizeof(buffer
))) > 0)
2959 if (cupsFileWrite(dst
, buffer
, bytes
) < bytes
)
2967 * Close both files and return...
2972 return (cupsFileClose(dst
));
2977 * 'copy_model()' - Copy a PPD model file, substituting default values
2981 static int /* O - 0 = success, -1 = error */
2982 copy_model(const char *from
, /* I - Source file */
2983 const char *to
) /* I - Destination file */
2985 cups_file_t
*src
, /* Source file */
2986 *dst
; /* Destination file */
2987 char buffer
[2048]; /* Copy buffer */
2988 int i
; /* Looping var */
2989 char option
[PPD_MAX_NAME
], /* Option name */
2990 choice
[PPD_MAX_NAME
]; /* Choice name */
2991 int num_defaults
; /* Number of default options */
2992 ppd_default_t
*defaults
; /* Default options */
2993 char cups_protocol
[PPD_MAX_LINE
];
2994 /* cupsProtocol attribute */
2995 #ifdef HAVE_LIBPAPER
2996 char *paper_result
; /* Paper size name from libpaper */
2997 char system_paper
[64]; /* Paper size name buffer */
2998 #endif /* HAVE_LIBPAPER */
3001 LogMessage(L_DEBUG2
, "copy_model(\"%s\", \"%s\")\n", from
, to
);
3004 * Open the destination (if possible) and set the default options...
3009 cups_protocol
[0] = '\0';
3011 if ((dst
= cupsFileOpen(to
, "rb")) != NULL
)
3014 * Read all of the default lines from the old PPD...
3017 while (cupsFileGets(dst
, buffer
, sizeof(buffer
)) != NULL
)
3018 if (!strncmp(buffer
, "*Default", 8))
3021 * Add the default option...
3024 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3025 choice
, sizeof(choice
)))
3026 num_defaults
= ppd_add_default(option
, choice
, num_defaults
,
3029 else if (!strncmp(buffer
, "*cupsProtocol:", 14))
3030 strlcpy(cups_protocol
, buffer
, sizeof(cups_protocol
));
3034 #ifdef HAVE_LIBPAPER
3035 else if ((paper_result
= systempapername()) != NULL
)
3038 * Set the default media sizes from the systemwide default...
3041 strlcpy(system_paper
, paper_result
, sizeof(system_paper
));
3042 system_paper
[0] = toupper(system_paper
[0] & 255);
3044 num_defaults
= ppd_add_default("PageSize", system_paper
,
3045 num_defaults
, &defaults
);
3046 num_defaults
= ppd_add_default("PageRegion", system_paper
,
3047 num_defaults
, &defaults
);
3048 num_defaults
= ppd_add_default("PaperDimension", system_paper
,
3049 num_defaults
, &defaults
);
3050 num_defaults
= ppd_add_default("ImageableArea", system_paper
,
3051 num_defaults
, &defaults
);
3053 #endif /* HAVE_LIBPAPER */
3057 * Add the default media sizes...
3059 * Note: These values are generally not valid for large-format devices
3060 * like plotters, however it is probably safe to say that those
3061 * users will configure the media size after initially adding
3062 * the device anyways...
3065 if (!DefaultLanguage
||
3066 !strcasecmp(DefaultLanguage
, "C") ||
3067 !strcasecmp(DefaultLanguage
, "POSIX") ||
3068 !strcasecmp(DefaultLanguage
, "en") ||
3069 !strncasecmp(DefaultLanguage
, "en_US", 5) ||
3070 !strncasecmp(DefaultLanguage
, "en_CA", 5) ||
3071 !strncasecmp(DefaultLanguage
, "fr_CA", 5))
3074 * These are the only locales that will default to "letter" size...
3077 num_defaults
= ppd_add_default("PageSize", "Letter", num_defaults
,
3079 num_defaults
= ppd_add_default("PageRegion", "Letter", num_defaults
,
3081 num_defaults
= ppd_add_default("PaperDimension", "Letter", num_defaults
,
3083 num_defaults
= ppd_add_default("ImageableArea", "Letter", num_defaults
,
3089 * The rest default to "a4" size...
3092 num_defaults
= ppd_add_default("PageSize", "A4", num_defaults
,
3094 num_defaults
= ppd_add_default("PageRegion", "A4", num_defaults
,
3096 num_defaults
= ppd_add_default("PaperDimension", "A4", num_defaults
,
3098 num_defaults
= ppd_add_default("ImageableArea", "A4", num_defaults
,
3104 * Open the source and destination file for a copy...
3107 if ((src
= cupsFileOpen(from
, "rb")) == NULL
)
3109 if (num_defaults
> 0)
3115 if ((dst
= cupsFileOpen(to
, "wb")) == NULL
)
3117 if (num_defaults
> 0)
3125 * Copy the source file to the destination...
3128 while (cupsFileGets(src
, buffer
, sizeof(buffer
)) != NULL
)
3130 if (!strncmp(buffer
, "*Default", 8))
3133 * Check for an previous default option choice...
3136 if (!ppd_parse_line(buffer
, option
, sizeof(option
),
3137 choice
, sizeof(choice
)))
3139 for (i
= 0; i
< num_defaults
; i
++)
3140 if (!strcmp(option
, defaults
[i
].option
))
3143 * Substitute the previous choice...
3146 snprintf(buffer
, sizeof(buffer
), "*Default%s: %s", option
,
3147 defaults
[i
].choice
);
3153 cupsFilePrintf(dst
, "%s\n", buffer
);
3156 if (cups_protocol
[0])
3157 cupsFilePrintf(dst
, "%s\n", cups_protocol
);
3159 if (num_defaults
> 0)
3163 * Close both files and return...
3168 return (cupsFileClose(dst
));
3173 * 'create_job()' - Print a file to a printer or class.
3177 create_job(client_t
*con
, /* I - Client connection */
3178 ipp_attribute_t
*uri
) /* I - Printer URI */
3180 ipp_attribute_t
*attr
; /* Current attribute */
3181 const char *dest
; /* Destination */
3182 cups_ptype_t dtype
; /* Destination type (printer or class) */
3183 int priority
; /* Job priority */
3184 char *title
; /* Job name/title */
3185 job_t
*job
; /* Current job */
3186 char job_uri
[HTTP_MAX_URI
], /* Job URI */
3187 method
[HTTP_MAX_URI
], /* Method portion of URI */
3188 username
[HTTP_MAX_URI
], /* Username portion of URI */
3189 host
[HTTP_MAX_URI
], /* Host portion of URI */
3190 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3191 int port
; /* Port portion of URI */
3192 printer_t
*printer
; /* Printer data */
3193 int kbytes
; /* Size of print file */
3194 int i
; /* Looping var */
3195 int lowerpagerange
; /* Page range bound */
3198 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3199 uri
->values
[0].string
.text
);
3202 * Verify that the POST operation was done to a valid URI.
3205 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3206 strncmp(con
->uri
, "/printers/", 10) != 0)
3208 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
3210 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3215 * Is the destination valid?
3218 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3220 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3226 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
3227 send_ipp_error(con
, IPP_NOT_FOUND
);
3235 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3237 LogMessage(L_ERROR
, "create_job: not authorized!");
3238 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3243 * See if the printer is accepting jobs...
3246 if (!printer
->accepting
)
3248 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
3250 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3255 * Validate job template attributes; for now just copies and page-ranges...
3258 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
3260 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
3262 LogMessage(L_INFO
, "create_job: bad copies value %d.",
3263 attr
->values
[0].integer
);
3264 send_ipp_error(con
, IPP_BAD_REQUEST
);
3269 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
3271 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
3273 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
3274 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3276 LogMessage(L_ERROR
, "create_job: bad page-ranges values %d-%d.",
3277 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3278 send_ipp_error(con
, IPP_BAD_REQUEST
);
3282 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
3287 * Make sure we aren't over our limit...
3290 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3293 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3295 LogMessage(L_INFO
, "create_job: too many jobs.");
3296 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3300 if (!check_quotas(con
, printer
))
3302 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3307 * Create the job and set things up...
3310 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3311 priority
= attr
->values
[0].integer
;
3313 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3316 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3317 title
= attr
->values
[0].string
.text
;
3319 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3320 title
= "Untitled");
3322 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3324 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
3326 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3331 job
->attrs
= con
->request
;
3332 con
->request
= NULL
;
3334 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3336 if (con
->username
[0])
3337 SetString(&job
->username
, con
->username
);
3338 else if (attr
!= NULL
)
3340 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
3341 attr
->values
[0].string
.text
);
3343 SetString(&job
->username
, attr
->values
[0].string
.text
);
3346 SetString(&job
->username
, "anonymous");
3349 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3350 NULL
, job
->username
);
3353 attr
->group_tag
= IPP_TAG_JOB
;
3354 SetString(&attr
->name
, "job-originating-user-name");
3357 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
3358 IPP_TAG_ZERO
)) != NULL
)
3361 * Request contains a job-originating-host-name attribute; validate it...
3364 if (attr
->value_tag
!= IPP_TAG_NAME
||
3365 attr
->num_values
!= 1 ||
3366 strcmp(con
->http
.hostname
, "localhost") != 0)
3369 * Can't override the value if we aren't connected via localhost.
3370 * Also, we can only have 1 value and it must be a name value.
3373 switch (attr
->value_tag
)
3375 case IPP_TAG_STRING
:
3376 case IPP_TAG_TEXTLANG
:
3377 case IPP_TAG_NAMELANG
:
3380 case IPP_TAG_KEYWORD
:
3382 case IPP_TAG_URISCHEME
:
3383 case IPP_TAG_CHARSET
:
3384 case IPP_TAG_LANGUAGE
:
3385 case IPP_TAG_MIMETYPE
:
3387 * Free old strings...
3390 for (i
= 0; i
< attr
->num_values
; i
++)
3392 free(attr
->values
[i
].string
.text
);
3393 attr
->values
[i
].string
.text
= NULL
;
3394 if (attr
->values
[i
].string
.charset
)
3396 free(attr
->values
[i
].string
.charset
);
3397 attr
->values
[i
].string
.charset
= NULL
;
3406 * Use the default connection hostname instead...
3409 attr
->value_tag
= IPP_TAG_NAME
;
3410 attr
->num_values
= 1;
3411 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
3414 attr
->group_tag
= IPP_TAG_JOB
;
3419 * No job-originating-host-name attribute, so use the hostname from
3423 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3424 "job-originating-host-name", NULL
, con
->http
.hostname
);
3427 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3429 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3430 "time-at-processing", 0);
3431 attr
->value_tag
= IPP_TAG_NOVALUE
;
3432 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3433 "time-at-completed", 0);
3434 attr
->value_tag
= IPP_TAG_NOVALUE
;
3437 * Add remaining job attributes...
3440 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3441 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3442 "job-state", IPP_JOB_STOPPED
);
3443 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3444 "job-media-sheets-completed", 0);
3445 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3447 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3450 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
3451 attr
->values
[0].integer
= 0;
3453 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3456 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3457 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3459 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
3460 "job-hold-until", NULL
, "no-hold");
3461 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
3462 !(printer
->type
& CUPS_PRINTER_REMOTE
))
3465 * Hold job until specified time...
3468 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3471 job
->hold_until
= time(NULL
) + 60;
3473 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
3475 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
3479 * Add job sheets options...
3482 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
3484 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
3485 printer
->job_sheets
[0], printer
->job_sheets
[1]);
3487 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
3489 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
3490 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
3493 job
->job_sheets
= attr
;
3496 * Enforce classification level if set...
3501 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
3502 Classification
? Classification
: "(null)", ClassifyOverride
);
3504 if (ClassifyOverride
)
3506 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
3507 (attr
->num_values
== 1 ||
3508 strcmp(attr
->values
[1].string
.text
, "none") == 0))
3511 * Force the leading banner to have the classification on it...
3514 SetString(&attr
->values
[0].string
.text
, Classification
);
3516 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3517 "job-sheets=\"%s,none\", "
3518 "job-originating-user-name=\"%s\"",
3519 job
->id
, Classification
,
3522 else if (attr
->num_values
== 2 &&
3523 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
3524 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
3525 strcmp(attr
->values
[1].string
.text
, "none") != 0)
3528 * Can't put two different security markings on the same document!
3531 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
3533 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3534 "job-sheets=\"%s,%s\", "
3535 "job-originating-user-name=\"%s\"",
3536 job
->id
, attr
->values
[0].string
.text
,
3537 attr
->values
[1].string
.text
,
3540 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
3541 strcmp(attr
->values
[0].string
.text
, "none") &&
3542 (attr
->num_values
== 1 ||
3543 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
3544 strcmp(attr
->values
[1].string
.text
, "none"))))
3546 if (attr
->num_values
== 1)
3547 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3548 "job-sheets=\"%s\", "
3549 "job-originating-user-name=\"%s\"",
3550 job
->id
, attr
->values
[0].string
.text
,
3553 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
3554 "job-sheets=\"%s,%s\",fffff "
3555 "job-originating-user-name=\"%s\"",
3556 job
->id
, attr
->values
[0].string
.text
,
3557 attr
->values
[1].string
.text
,
3561 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
3562 (attr
->num_values
== 1 ||
3563 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
3566 * Force the banner to have the classification on it...
3569 if (attr
->num_values
> 1 &&
3570 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
3572 SetString(&(attr
->values
[0].string
.text
), Classification
);
3573 SetString(&(attr
->values
[1].string
.text
), Classification
);
3577 if (attr
->num_values
== 1 ||
3578 strcmp(attr
->values
[0].string
.text
, "none"))
3579 SetString(&(attr
->values
[0].string
.text
), Classification
);
3581 if (attr
->num_values
> 1 &&
3582 strcmp(attr
->values
[1].string
.text
, "none"))
3583 SetString(&(attr
->values
[1].string
.text
), Classification
);
3586 if (attr
->num_values
> 1)
3587 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3588 "job-sheets=\"%s,%s\", "
3589 "job-originating-user-name=\"%s\"",
3590 job
->id
, attr
->values
[0].string
.text
,
3591 attr
->values
[1].string
.text
,
3594 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
3595 "job-sheets=\"%s\", "
3596 "job-originating-user-name=\"%s\"",
3597 job
->id
, Classification
,
3603 * See if we need to add the starting sheet...
3606 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
3608 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
3609 attr
->values
[0].string
.text
, job
->id
);
3611 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
3613 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3616 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
3620 * Add any job subscriptions...
3623 add_job_subscriptions(con
, job
);
3626 * Set all but the first two attributes to the job attributes group...
3629 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
3630 attr
->group_tag
= IPP_TAG_JOB
;
3633 * Save and log the job...
3638 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
3639 job
->dest
, job
->username
);
3641 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
3644 * Fill in the response info...
3647 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3648 LocalPort
, job
->id
);
3650 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
3652 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3654 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
3655 job
->state
->values
[0].integer
);
3657 con
->response
->request
.status
.status_code
= IPP_OK
;
3662 * 'create_subscription()' - Create a notification subscription.
3666 create_subscription(
3667 client_t
*con
, /* I - Client connection */
3668 ipp_attribute_t
*uri
) /* I - Printer URI */
3674 * 'delete_printer()' - Remove a printer or class from the system.
3678 delete_printer(client_t
*con
, /* I - Client connection */
3679 ipp_attribute_t
*uri
) /* I - URI of printer or class */
3681 const char *dest
; /* Destination */
3682 cups_ptype_t dtype
; /* Destination type (printer or class) */
3683 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3684 username
[HTTP_MAX_URI
], /* Username portion of URI */
3685 host
[HTTP_MAX_URI
], /* Host portion of URI */
3686 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3687 int port
; /* Port portion of URI */
3688 printer_t
*printer
; /* Printer/class */
3689 char filename
[1024]; /* Script/PPD filename */
3692 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
3693 uri
->values
[0].string
.text
);
3696 * Was this operation called from the correct URI?
3699 if (strncmp(con
->uri
, "/admin/", 7) != 0)
3701 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
3703 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3708 * Do we have a valid URI?
3711 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3713 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3719 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
3720 send_ipp_error(con
, IPP_NOT_FOUND
);
3728 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3730 LogMessage(L_ERROR
, "delete_printer: not authorized!");
3731 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3736 * Remove old jobs...
3739 CancelJobs(dest
, NULL
, 1);
3742 * Remove old subscriptions and send a "deleted printer" event...
3745 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, printer
, NULL
,
3746 "%s \'%s\' deleted by \'%s\'.",
3747 (dtype
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
3748 dest
, con
->username
);
3750 cupsdExpireSubscriptions(printer
, NULL
);
3753 * Remove any old PPD or script files...
3756 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
3759 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
3762 if (dtype
& CUPS_PRINTER_CLASS
)
3764 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
3767 DeletePrinter(printer
, 0);
3772 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
3775 DeletePrinter(printer
, 0);
3780 * Return with no errors...
3783 con
->response
->request
.status
.status_code
= IPP_OK
;
3788 * 'get_default()' - Get the default destination.
3792 get_default(client_t
*con
) /* I - Client connection */
3794 int i
; /* Looping var */
3795 ipp_attribute_t
*requested
, /* requested-attributes */
3796 *history
; /* History collection */
3797 int need_history
; /* Need to send history collection? */
3800 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
3806 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3808 LogMessage(L_ERROR
, "get_default: not authorized!");
3809 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3813 if (DefaultPrinter
!= NULL
)
3815 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3818 copy_attrs(con
->response
, DefaultPrinter
->attrs
, requested
, IPP_TAG_ZERO
, 0);
3819 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
3823 if (MaxPrinterHistory
> 0 && DefaultPrinter
->num_history
> 0 && requested
)
3825 for (i
= 0; i
< requested
->num_values
; i
++)
3826 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
3827 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
3836 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
3837 "printer-state-history",
3838 DefaultPrinter
->num_history
, NULL
);
3840 for (i
= 0; i
< DefaultPrinter
->num_history
; i
++)
3841 copy_attrs(history
->values
[i
].collection
= ippNew(),
3842 DefaultPrinter
->history
[i
],
3843 NULL
, IPP_TAG_ZERO
, 0);
3846 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
3849 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
3854 * 'get_devices()' - Get the list of available devices on the local system.
3858 get_devices(client_t
*con
) /* I - Client connection */
3860 ipp_attribute_t
*limit
; /* Limit attribute */
3861 char command
[1024], /* cups-deviced command */
3862 options
[1024]; /* Options to pass to command */
3865 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
3871 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3873 LogMessage(L_ERROR
, "get_devices: not authorized!");
3874 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3879 * Run cups-deviced command with the given options...
3882 limit
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
);
3884 snprintf(command
, sizeof(command
), "%s/daemon/cups-deviced", ServerBin
);
3885 snprintf(options
, sizeof(options
), "cups-deviced %d+%d",
3886 con
->request
->request
.op
.request_id
,
3887 limit
? limit
->values
[0].integer
: 0);
3889 if (SendCommand(con
, command
, options
))
3892 * Command started successfully, don't send an IPP response here...
3895 ippDelete(con
->response
);
3896 con
->response
= NULL
;
3901 * Command failed, return "internal error" so the user knows something
3905 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3911 * 'get_jobs()' - Get a list of jobs for the specified printer.
3915 get_jobs(client_t
*con
, /* I - Client connection */
3916 ipp_attribute_t
*uri
) /* I - Printer URI */
3918 ipp_attribute_t
*attr
, /* Current attribute */
3919 *requested
; /* Requested attributes */
3920 const char *dest
; /* Destination */
3921 cups_ptype_t dtype
; /* Destination type (printer or class) */
3922 cups_ptype_t dmask
; /* Destination type mask */
3923 char method
[HTTP_MAX_URI
], /* Method portion of URI */
3924 username
[HTTP_MAX_URI
], /* Username portion of URI */
3925 host
[HTTP_MAX_URI
], /* Host portion of URI */
3926 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
3927 int port
; /* Port portion of URI */
3928 int completed
; /* Completed jobs? */
3929 int limit
; /* Maximum number of jobs to return */
3930 int count
; /* Number of jobs that match */
3931 job_t
*job
; /* Current job pointer */
3932 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
3933 printer_t
*printer
; /* Printer */
3936 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
3937 uri
->values
[0].string
.text
);
3940 * Is the destination valid?
3943 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3945 if (strcmp(resource
, "/") == 0 ||
3946 (strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6))
3949 dtype
= (cups_ptype_t
)0;
3950 dmask
= (cups_ptype_t
)0;
3953 else if (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10)
3956 dtype
= (cups_ptype_t
)0;
3957 dmask
= CUPS_PRINTER_CLASS
;
3960 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
3963 dtype
= CUPS_PRINTER_CLASS
;
3964 dmask
= CUPS_PRINTER_CLASS
;
3967 else if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
3973 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
3974 send_ipp_error(con
, IPP_NOT_FOUND
);
3978 dmask
= CUPS_PRINTER_CLASS
;
3986 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
3988 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3989 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3993 else if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
3995 LogMessage(L_ERROR
, "get_jobs: not authorized!");
3996 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4001 * See if the "which-jobs" attribute have been specified...
4004 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
4005 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
4011 * See if they want to limit the number of jobs reported...
4014 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4015 limit
= attr
->values
[0].integer
;
4020 * See if we only want to see jobs for a specific user...
4023 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
4024 attr
->values
[0].boolean
)
4026 if (con
->username
[0])
4027 strlcpy(username
, con
->username
, sizeof(username
));
4028 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4029 strlcpy(username
, attr
->values
[0].string
.text
, sizeof(username
));
4031 strcpy(username
, "anonymous");
4036 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4040 * OK, build a list of jobs for this printer...
4043 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
4046 * Filter out jobs that don't match...
4049 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
4051 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0) &&
4052 (job
->printer
== NULL
|| dest
== NULL
||
4053 strcmp(job
->printer
->name
, dest
) != 0))
4055 if ((job
->dtype
& dmask
) != dtype
&&
4056 (job
->printer
== NULL
|| (job
->printer
->type
& dmask
) != dtype
))
4058 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
4061 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
4063 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4068 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
4071 * Send the requested attributes for each job...
4074 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4075 LocalPort
, job
->id
);
4077 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4078 "job-more-info", NULL
, job_uri
);
4080 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4081 "job-uri", NULL
, job_uri
);
4083 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4084 "job-printer-up-time", time(NULL
));
4087 * Copy the job attributes to the response using the requested-attributes
4088 * attribute that may be provided by the client.
4091 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4093 add_job_state_reasons(con
, job
);
4095 ippAddSeparator(con
->response
);
4098 if (requested
!= NULL
)
4099 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4101 con
->response
->request
.status
.status_code
= IPP_OK
;
4106 * 'get_job_attrs()' - Get job attributes.
4110 get_job_attrs(client_t
*con
, /* I - Client connection */
4111 ipp_attribute_t
*uri
) /* I - Job URI */
4113 ipp_attribute_t
*attr
, /* Current attribute */
4114 *requested
; /* Requested attributes */
4115 int jobid
; /* Job ID */
4116 job_t
*job
; /* Current job */
4117 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4118 username
[HTTP_MAX_URI
], /* Username portion of URI */
4119 host
[HTTP_MAX_URI
], /* Host portion of URI */
4120 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4121 int port
; /* Port portion of URI */
4122 char job_uri
[HTTP_MAX_URI
]; /* Job URI... */
4125 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4126 uri
->values
[0].string
.text
);
4129 * See if we have a job URI or a printer URI...
4132 if (strcmp(uri
->name
, "printer-uri") == 0)
4135 * Got a printer URI; see if we also have a job-id attribute...
4138 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4140 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
4141 send_ipp_error(con
, IPP_BAD_REQUEST
);
4145 jobid
= attr
->values
[0].integer
;
4150 * Got a job URI; parse it to get the job ID...
4153 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4155 if (strncmp(resource
, "/jobs/", 6) != 0)
4161 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
4162 uri
->values
[0].string
.text
);
4163 send_ipp_error(con
, IPP_BAD_REQUEST
);
4167 jobid
= atoi(resource
+ 6);
4171 * See if the job exists...
4174 if ((job
= FindJob(jobid
)) == NULL
)
4177 * Nope - return a "not found" error...
4180 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
4181 send_ipp_error(con
, IPP_NOT_FOUND
);
4189 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4191 LogMessage(L_ERROR
, "get_job_attrs: not authorized!");
4192 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4197 * Put out the standard attributes...
4200 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
4201 ServerName
, LocalPort
, job
->id
);
4203 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4205 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4206 "job-more-info", NULL
, job_uri
);
4208 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
4209 "job-uri", NULL
, job_uri
);
4211 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4212 "job-printer-up-time", time(NULL
));
4215 * Copy the job attributes to the response using the requested-attributes
4216 * attribute that may be provided by the client.
4219 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4222 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
, 0);
4224 add_job_state_reasons(con
, job
);
4226 if (requested
!= NULL
)
4227 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
4229 con
->response
->request
.status
.status_code
= IPP_OK
;
4234 * 'get_notifications()' - Get events for a subscription.
4238 get_notifications(client_t
*con
, /* I - Client connection */
4239 int id
) /* I - Subscription ID */
4245 * 'get_ppds()' - Get the list of PPD files on the local system.
4249 get_ppds(client_t
*con
) /* I - Client connection */
4251 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
4257 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4259 LogMessage(L_ERROR
, "get_ppds: not authorized!");
4260 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4265 * Copy the PPD attributes to the response using the requested-attributes
4266 * attribute that may be provided by the client.
4269 copy_attrs(con
->response
, PPDs
,
4270 ippFindAttribute(con
->request
, "requested-attributes",
4271 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
, IPP_TAG_COPY
);
4273 con
->response
->request
.status
.status_code
= IPP_OK
;
4278 * 'get_printer_attrs()' - Get printer attributes.
4282 get_printer_attrs(client_t
*con
, /* I - Client connection */
4283 ipp_attribute_t
*uri
) /* I - Printer URI */
4285 const char *dest
; /* Destination */
4286 cups_ptype_t dtype
; /* Destination type (printer or class) */
4287 char method
[HTTP_MAX_URI
],
4288 /* Method portion of URI */
4289 username
[HTTP_MAX_URI
],
4290 /* Username portion of URI */
4292 /* Host portion of URI */
4293 resource
[HTTP_MAX_URI
];
4294 /* Resource portion of URI */
4295 int port
; /* Port portion of URI */
4296 printer_t
*printer
; /* Printer/class */
4297 time_t curtime
; /* Current time */
4298 int i
; /* Looping var */
4299 ipp_attribute_t
*requested
, /* requested-attributes */
4300 *history
; /* History collection */
4301 int need_history
; /* Need to send history collection? */
4304 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4305 uri
->values
[0].string
.text
);
4308 * Is the destination valid?
4311 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4313 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4319 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
4320 send_ipp_error(con
, IPP_NOT_FOUND
);
4328 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4330 LogMessage(L_ERROR
, "get_printer_attrs: not authorized!");
4331 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4335 curtime
= time(NULL
);
4338 * Copy the printer attributes to the response using requested-attributes
4339 * and document-format attributes that may be provided by the client.
4342 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
4345 add_printer_state_reasons(con
, printer
);
4347 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4348 "printer-state-message", NULL
, printer
->state_message
);
4350 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4351 printer
->accepting
);
4353 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4354 "printer-up-time", curtime
);
4355 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4356 "printer-state-time", printer
->state_time
);
4357 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4358 ippTimeToDate(curtime
));
4360 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4361 "printer-error-policy", NULL
, printer
->op_policy
);
4362 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4363 "printer-op-policy", NULL
, printer
->op_policy
);
4365 add_queued_job_count(con
, printer
);
4367 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4370 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4371 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
, IPP_TAG_COPY
);
4375 if (MaxPrinterHistory
> 0 && printer
->num_history
> 0 && requested
)
4377 for (i
= 0; i
< requested
->num_values
; i
++)
4378 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4379 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4388 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4389 "printer-state-history",
4390 printer
->num_history
, NULL
);
4392 for (i
= 0; i
< printer
->num_history
; i
++)
4393 copy_attrs(history
->values
[i
].collection
= ippNew(), printer
->history
[i
],
4394 NULL
, IPP_TAG_ZERO
, 0);
4397 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4402 * 'get_printers()' - Get a list of printers or classes.
4406 get_printers(client_t
*con
, /* I - Client connection */
4407 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
4409 int i
; /* Looping var */
4410 ipp_attribute_t
*requested
, /* requested-attributes */
4411 *history
, /* History collection */
4412 *attr
; /* Current attribute */
4413 int need_history
; /* Need to send history collection? */
4414 int limit
; /* Maximum number of printers to return */
4415 int count
; /* Number of printers that match */
4416 printer_t
*printer
; /* Current printer pointer */
4417 time_t curtime
; /* Current time */
4418 int printer_type
, /* printer-type attribute */
4419 printer_mask
; /* printer-type-mask attribute */
4420 char *location
; /* Location string */
4421 char name
[IPP_MAX_NAME
], /* Printer name */
4422 *nameptr
; /* Pointer into name */
4423 printer_t
*iclass
; /* Implicit class */
4424 const char *username
; /* Current user */
4427 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
4433 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
4435 LogMessage(L_ERROR
, "get_printers: not authorized!");
4436 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4441 * See if they want to limit the number of printers reported...
4444 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
4445 limit
= attr
->values
[0].integer
;
4450 * Support filtering...
4453 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
4454 printer_type
= attr
->values
[0].integer
;
4458 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
4459 printer_mask
= attr
->values
[0].integer
;
4463 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
4464 location
= attr
->values
[0].string
.text
;
4468 if (con
->username
[0])
4469 username
= con
->username
;
4470 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
4471 username
= attr
->values
[0].string
.text
;
4475 requested
= ippFindAttribute(con
->request
, "requested-attributes",
4480 if (MaxPrinterHistory
> 0 && requested
)
4482 for (i
= 0; i
< requested
->num_values
; i
++)
4483 if (!strcmp(requested
->values
[i
].string
.text
, "all") ||
4484 !strcmp(requested
->values
[i
].string
.text
, "printer-state-history"))
4492 * OK, build a list of printers for this printer...
4495 curtime
= time(NULL
);
4497 for (count
= 0, printer
= Printers
;
4498 count
< limit
&& printer
!= NULL
;
4499 printer
= printer
->next
)
4500 if ((printer
->type
& CUPS_PRINTER_CLASS
) == type
&&
4501 (printer
->type
& printer_mask
) == printer_type
&&
4502 (location
== NULL
|| printer
->location
== NULL
||
4503 strcasecmp(printer
->location
, location
) == 0))
4506 * If HideImplicitMembers is enabled, see if this printer or class
4507 * is a member of an implicit class...
4510 if (ImplicitClasses
&& HideImplicitMembers
&&
4511 (printer
->type
& CUPS_PRINTER_REMOTE
))
4514 * Make a copy of the printer name...
4517 strlcpy(name
, printer
->name
, sizeof(name
));
4519 if ((nameptr
= strchr(name
, '@')) != NULL
)
4522 * Strip trailing @server...
4528 * Find the core printer, if any...
4531 if ((iclass
= FindPrinter(name
)) != NULL
&&
4532 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
4538 * If a username is specified, see if it is allowed or denied
4542 if (printer
->num_users
&& username
&& !user_allowed(printer
, username
))
4546 * Add the group separator as needed...
4550 ippAddSeparator(con
->response
);
4555 * Send the following attributes for each printer:
4558 * printer-state-message
4559 * printer-is-accepting-jobs
4560 * + all printer attributes
4563 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
4564 "printer-state", printer
->state
);
4566 add_printer_state_reasons(con
, printer
);
4568 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
4569 "printer-state-message", NULL
, printer
->state_message
);
4571 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
4572 printer
->accepting
);
4574 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4575 "printer-up-time", curtime
);
4576 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
4577 "printer-state-time", printer
->state_time
);
4578 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
4579 ippTimeToDate(curtime
));
4581 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4582 "printer-error-policy", NULL
, printer
->op_policy
);
4583 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
4584 "printer-op-policy", NULL
, printer
->op_policy
);
4586 add_queued_job_count(con
, printer
);
4588 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
, 0);
4590 copy_attrs(con
->response
, CommonData
, requested
, IPP_TAG_ZERO
,
4593 if (need_history
&& printer
->num_history
> 0)
4595 history
= ippAddCollections(con
->response
, IPP_TAG_PRINTER
,
4596 "printer-state-history",
4597 printer
->num_history
, NULL
);
4599 for (i
= 0; i
< printer
->num_history
; i
++)
4600 copy_attrs(history
->values
[i
].collection
= ippNew(),
4601 printer
->history
[i
], NULL
, IPP_TAG_ZERO
, 0);
4605 con
->response
->request
.status
.status_code
= requested
? IPP_OK_SUBST
: IPP_OK
;
4610 * 'get_subscription_attrs()' - Get subscription attributes.
4614 get_subscription_attrs(client_t
*con
, /* I - Client connection */
4615 int sub_id
) /* I - Subscription ID */
4621 * 'get_subscriptions()' - Get subscriptions.
4625 get_subscriptions(client_t
*con
, /* I - Client connection */
4626 ipp_attribute_t
*uri
) /* I - Printer URI */
4632 * 'hold_job()' - Hold a print job.
4636 hold_job(client_t
*con
, /* I - Client connection */
4637 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4639 ipp_attribute_t
*attr
, /* Current job-hold-until */
4640 *newattr
; /* New job-hold-until */
4641 int jobid
; /* Job ID */
4642 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4643 username
[HTTP_MAX_URI
], /* Username portion of URI */
4644 host
[HTTP_MAX_URI
], /* Host portion of URI */
4645 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4646 int port
; /* Port portion of URI */
4647 job_t
*job
; /* Job information */
4650 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4651 uri
->values
[0].string
.text
);
4654 * Verify that the POST operation was done to a valid URI.
4657 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4658 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4659 strncmp(con
->uri
, "/printers/", 10) != 0)
4661 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
4663 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4668 * See if we have a job URI or a printer URI...
4671 if (strcmp(uri
->name
, "printer-uri") == 0)
4674 * Got a printer URI; see if we also have a job-id attribute...
4677 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4679 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
4680 send_ipp_error(con
, IPP_BAD_REQUEST
);
4684 jobid
= attr
->values
[0].integer
;
4689 * Got a job URI; parse it to get the job ID...
4692 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4694 if (strncmp(resource
, "/jobs/", 6) != 0)
4700 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
4701 uri
->values
[0].string
.text
);
4702 send_ipp_error(con
, IPP_BAD_REQUEST
);
4706 jobid
= atoi(resource
+ 6);
4710 * See if the job exists...
4713 if ((job
= FindJob(jobid
)) == NULL
)
4716 * Nope - return a "not found" error...
4719 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
4720 send_ipp_error(con
, IPP_NOT_FOUND
);
4725 * See if the job is owned by the requesting user...
4728 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4730 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
4731 username
, jobid
, job
->username
);
4732 send_ipp_error(con
, IPP_FORBIDDEN
);
4737 * Hold the job and return...
4742 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4743 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
4745 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4746 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4751 * Free the old hold value and copy the new one over...
4754 free(attr
->values
[0].string
.text
);
4756 if (newattr
!= NULL
)
4758 attr
->value_tag
= newattr
->value_tag
;
4759 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
4763 attr
->value_tag
= IPP_TAG_KEYWORD
;
4764 attr
->values
[0].string
.text
= strdup("indefinite");
4768 * Hold job until specified time...
4771 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4774 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
4776 con
->response
->request
.status
.status_code
= IPP_OK
;
4781 * 'move_job()' - Move a job to a new destination.
4785 move_job(client_t
*con
, /* I - Client connection */
4786 ipp_attribute_t
*uri
) /* I - Job URI */
4788 ipp_attribute_t
*attr
; /* Current attribute */
4789 int jobid
; /* Job ID */
4790 job_t
*job
; /* Current job */
4791 const char *dest
; /* Destination */
4792 cups_ptype_t dtype
; /* Destination type (printer or class) */
4793 char method
[HTTP_MAX_URI
], /* Method portion of URI */
4794 username
[HTTP_MAX_URI
], /* Username portion of URI */
4795 host
[HTTP_MAX_URI
], /* Host portion of URI */
4796 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
4797 int port
; /* Port portion of URI */
4798 printer_t
*printer
; /* Printer */
4801 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4802 uri
->values
[0].string
.text
);
4805 * See if we have a job URI or a printer URI...
4808 if (strcmp(uri
->name
, "printer-uri") == 0)
4811 * Got a printer URI; see if we also have a job-id attribute...
4814 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4816 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
4817 send_ipp_error(con
, IPP_BAD_REQUEST
);
4821 jobid
= attr
->values
[0].integer
;
4826 * Got a job URI; parse it to get the job ID...
4829 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4831 if (strncmp(resource
, "/jobs/", 6) != 0)
4837 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
4838 uri
->values
[0].string
.text
);
4839 send_ipp_error(con
, IPP_BAD_REQUEST
);
4843 jobid
= atoi(resource
+ 6);
4847 * See if the job exists...
4850 if ((job
= FindJob(jobid
)) == NULL
)
4853 * Nope - return a "not found" error...
4856 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
4857 send_ipp_error(con
, IPP_NOT_FOUND
);
4862 * See if the job has been completed...
4865 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4868 * Return a "not-possible" error...
4871 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
4872 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4877 * See if the job is owned by the requesting user...
4880 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
4882 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
4883 username
, jobid
, job
->username
);
4884 send_ipp_error(con
, IPP_FORBIDDEN
);
4888 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
4891 * Need job-printer-uri...
4894 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
4895 send_ipp_error(con
, IPP_BAD_REQUEST
);
4900 * Get the new printer or class...
4903 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
4905 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
4911 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
4912 send_ipp_error(con
, IPP_NOT_FOUND
);
4920 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
4922 LogMessage(L_ERROR
, "move_job: not authorized!");
4923 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4928 * Move the job to a different printer or class...
4931 MoveJob(jobid
, dest
);
4934 * Start jobs if possible...
4940 * Return with "everything is OK" status...
4943 con
->response
->request
.status
.status_code
= IPP_OK
;
4948 * 'ppd_add_default()' - Add a PPD default choice.
4951 static int /* O - Number of defaults */
4953 const char *option
, /* I - Option name */
4954 const char *choice
, /* I - Choice name */
4955 int num_defaults
, /* I - Number of defaults */
4956 ppd_default_t
**defaults
) /* IO - Defaults */
4958 int i
; /* Looping var */
4959 ppd_default_t
*temp
; /* Temporary defaults array */
4963 * First check if the option already has a default value; the PPD spec
4964 * says that the first one is used...
4967 for (i
= 0, temp
= *defaults
; i
< num_defaults
; i
++)
4968 if (!strcmp(option
, temp
[i
].option
))
4969 return (num_defaults
);
4972 * Now add the option...
4975 if (num_defaults
== 0)
4976 temp
= malloc(sizeof(ppd_default_t
));
4978 temp
= realloc(*defaults
, (num_defaults
+ 1) * sizeof(ppd_default_t
));
4982 LogMessage(L_ERROR
, "ppd_add_default: Unable to add default value for \"%s\" - %s",
4983 option
, strerror(errno
));
4984 return (num_defaults
);
4988 temp
+= num_defaults
;
4990 strlcpy(temp
->option
, option
, sizeof(temp
->option
));
4991 strlcpy(temp
->choice
, choice
, sizeof(temp
->choice
));
4993 return (num_defaults
+ 1);
4998 * 'ppd_parse_line()' - Parse a PPD default line.
5001 static int /* O - 0 on success, -1 on failure */
5002 ppd_parse_line(const char *line
, /* I - Line */
5003 char *option
, /* O - Option name */
5004 int olen
, /* I - Size of option name */
5005 char *choice
, /* O - Choice name */
5006 int clen
) /* I - Size of choice name */
5009 * Verify this is a default option line...
5012 if (strncmp(line
, "*Default", 8))
5016 * Read the option name...
5019 for (line
+= 8, olen
--; isalnum(*line
& 255); line
++)
5029 * Skip everything else up to the colon (:)...
5032 while (*line
&& *line
!= ':')
5041 * Now grab the option choice, skipping leading whitespace...
5044 while (isspace(*line
& 255))
5047 for (clen
--; isalnum(*line
& 255); line
++)
5057 * Return with no errors...
5065 * 'print_job()' - Print a file to a printer or class.
5069 print_job(client_t
*con
, /* I - Client connection */
5070 ipp_attribute_t
*uri
) /* I - Printer URI */
5072 ipp_attribute_t
*attr
; /* Current attribute */
5073 ipp_attribute_t
*format
; /* Document-format attribute */
5074 const char *dest
; /* Destination */
5075 cups_ptype_t dtype
; /* Destination type (printer or class) */
5076 int priority
; /* Job priority */
5077 char *title
; /* Job name/title */
5078 job_t
*job
; /* Current job */
5079 int jobid
; /* Job ID number */
5080 char job_uri
[HTTP_MAX_URI
], /* Job URI */
5081 method
[HTTP_MAX_URI
], /* Method portion of URI */
5082 username
[HTTP_MAX_URI
], /* Username portion of URI */
5083 host
[HTTP_MAX_URI
], /* Host portion of URI */
5084 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5085 filename
[1024]; /* Job filename */
5086 int port
; /* Port portion of URI */
5087 mime_type_t
*filetype
; /* Type of file */
5088 char super
[MIME_MAX_SUPER
], /* Supertype of file */
5089 type
[MIME_MAX_TYPE
], /* Subtype of file */
5090 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
5091 /* Textual name of mime type */
5092 printer_t
*printer
; /* Printer data */
5093 struct stat fileinfo
; /* File information */
5094 int kbytes
; /* Size of file */
5095 int i
; /* Looping var */
5096 int lowerpagerange
; /* Page range bound */
5097 int compression
; /* Document compression */
5100 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5101 uri
->values
[0].string
.text
);
5104 * Verify that the POST operation was done to a valid URI.
5107 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5108 strncmp(con
->uri
, "/printers/", 10) != 0)
5110 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
5112 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5117 * Validate job template attributes; for now just copies and page-ranges...
5120 if ((attr
= ippFindAttribute(con
->request
, "copies", IPP_TAG_INTEGER
)) != NULL
)
5122 if (attr
->values
[0].integer
< 1 || attr
->values
[0].integer
> MaxCopies
)
5124 LogMessage(L_INFO
, "print_job: bad copies value %d.",
5125 attr
->values
[0].integer
);
5126 send_ipp_error(con
, IPP_BAD_REQUEST
);
5131 if ((attr
= ippFindAttribute(con
->request
, "page-ranges", IPP_TAG_RANGE
)) != NULL
)
5133 for (i
= 0, lowerpagerange
= 1; i
< attr
->num_values
; i
++)
5135 if (attr
->values
[i
].range
.lower
< lowerpagerange
||
5136 attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5138 LogMessage(L_ERROR
, "print_job: bad page-ranges values %d-%d.",
5139 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
5140 send_ipp_error(con
, IPP_BAD_REQUEST
);
5144 lowerpagerange
= attr
->values
[i
].range
.upper
+ 1;
5149 * OK, see if the client is sending the document compressed - CUPS
5150 * only supports "none" and "gzip".
5153 compression
= CUPS_FILE_NONE
;
5155 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
5157 if (strcmp(attr
->values
[0].string
.text
, "none")
5159 && strcmp(attr
->values
[0].string
.text
, "gzip")
5160 #endif /* HAVE_LIBZ */
5163 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
5164 attr
->values
[0].string
.text
);
5165 send_ipp_error(con
, IPP_ATTRIBUTES
);
5166 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5167 "compression", NULL
, attr
->values
[0].string
.text
);
5172 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
5173 compression
= CUPS_FILE_GZIP
;
5174 #endif /* HAVE_LIBZ */
5178 * Do we have a file to print?
5183 LogMessage(L_ERROR
, "print_job: No file!?!");
5184 send_ipp_error(con
, IPP_BAD_REQUEST
);
5189 * Is it a format we support?
5192 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5195 * Grab format from client...
5198 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5200 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
5201 format
->values
[0].string
.text
);
5202 send_ipp_error(con
, IPP_BAD_REQUEST
);
5209 * No document format attribute? Auto-type it!
5212 strcpy(super
, "application");
5213 strcpy(type
, "octet-stream");
5216 if (strcmp(super
, "application") == 0 &&
5217 strcmp(type
, "octet-stream") == 0)
5220 * Auto-type the file...
5223 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
5225 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
5227 if (filetype
!= NULL
)
5230 * Replace the document-format attribute value with the auto-typed one.
5233 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
5238 free(format
->values
[0].string
.text
);
5239 format
->values
[0].string
.text
= strdup(mimetype
);
5242 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
5243 "document-format", NULL
, mimetype
);
5246 filetype
= mimeType(MimeDatabase
, super
, type
);
5249 filetype
= mimeType(MimeDatabase
, super
, type
);
5251 if (filetype
== NULL
)
5253 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
5255 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
5256 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5259 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5260 "document-format", NULL
, format
->values
[0].string
.text
);
5265 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
5266 filetype
->super
, filetype
->type
);
5269 * Read any embedded job ticket info from PS files...
5272 if (strcasecmp(filetype
->super
, "application") == 0 &&
5273 strcasecmp(filetype
->type
, "postscript") == 0)
5274 read_ps_job_ticket(con
);
5277 * Is the destination valid?
5280 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5282 if ((dest
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5288 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
5289 send_ipp_error(con
, IPP_NOT_FOUND
);
5297 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5299 LogMessage(L_ERROR
, "print_job: not authorized!");
5300 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5305 * See if the printer is accepting jobs...
5308 if (!printer
->accepting
)
5310 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
5312 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
5317 * Make sure we aren't over our limit...
5320 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5323 if (NumJobs
>= MaxJobs
&& MaxJobs
)
5325 LogMessage(L_INFO
, "print_job: too many jobs - %d jobs, max jobs is %d.",
5327 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5331 if (!check_quotas(con
, printer
))
5333 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5338 * Create the job and set things up...
5341 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
5342 priority
= attr
->values
[0].integer
;
5344 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
5347 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
5348 title
= attr
->values
[0].string
.text
;
5350 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5351 title
= "Untitled");
5353 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
5355 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
5357 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
5362 job
->attrs
= con
->request
;
5363 con
->request
= NULL
;
5366 * Copy the rest of the job info...
5369 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
5371 if (con
->username
[0])
5372 SetString(&job
->username
, con
->username
);
5373 else if (attr
!= NULL
)
5375 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
5376 attr
->values
[0].string
.text
);
5378 SetString(&job
->username
, attr
->values
[0].string
.text
);
5381 SetString(&job
->username
, "anonymous");
5384 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
5385 NULL
, job
->username
);
5388 attr
->group_tag
= IPP_TAG_JOB
;
5389 SetString(&attr
->name
, "job-originating-user-name");
5393 * Add remaining job attributes...
5396 if ((attr
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
5397 IPP_TAG_ZERO
)) != NULL
)
5400 * Request contains a job-originating-host-name attribute; validate it...
5403 if (attr
->value_tag
!= IPP_TAG_NAME
||
5404 attr
->num_values
!= 1 ||
5405 strcmp(con
->http
.hostname
, "localhost") != 0)
5408 * Can't override the value if we aren't connected via localhost.
5409 * Also, we can only have 1 value and it must be a name value.
5412 switch (attr
->value_tag
)
5414 case IPP_TAG_STRING
:
5415 case IPP_TAG_TEXTLANG
:
5416 case IPP_TAG_NAMELANG
:
5419 case IPP_TAG_KEYWORD
:
5421 case IPP_TAG_URISCHEME
:
5422 case IPP_TAG_CHARSET
:
5423 case IPP_TAG_LANGUAGE
:
5424 case IPP_TAG_MIMETYPE
:
5426 * Free old strings...
5429 for (i
= 0; i
< attr
->num_values
; i
++)
5431 free(attr
->values
[i
].string
.text
);
5432 attr
->values
[i
].string
.text
= NULL
;
5433 if (attr
->values
[i
].string
.charset
)
5435 free(attr
->values
[i
].string
.charset
);
5436 attr
->values
[i
].string
.charset
= NULL
;
5445 * Use the default connection hostname instead...
5448 attr
->value_tag
= IPP_TAG_NAME
;
5449 attr
->num_values
= 1;
5450 attr
->values
[0].string
.text
= strdup(con
->http
.hostname
);
5453 attr
->group_tag
= IPP_TAG_JOB
;
5458 * No job-originating-host-name attribute, so use the hostname from
5462 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
5463 "job-originating-host-name", NULL
, con
->http
.hostname
);
5466 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
5467 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
5468 "job-state", IPP_JOB_PENDING
);
5469 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5470 "job-media-sheets-completed", 0);
5471 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
5473 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
5476 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
5477 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5480 if (stat(con
->filename
, &fileinfo
))
5483 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
5485 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5486 attr
->values
[0].integer
+= kbytes
;
5488 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
5490 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5491 "time-at-processing", 0);
5492 attr
->value_tag
= IPP_TAG_NOVALUE
;
5493 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
5494 "time-at-completed", 0);
5495 attr
->value_tag
= IPP_TAG_NOVALUE
;
5497 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
5498 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
5500 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
5501 "job-hold-until", NULL
, "no-hold");
5503 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
5504 !(printer
->type
& CUPS_PRINTER_REMOTE
))
5507 * Hold job until specified time...
5510 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
5511 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5514 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) ||
5518 * Add job sheets options...
5521 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
5523 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
5524 printer
->job_sheets
[0], printer
->job_sheets
[1]);
5526 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
5528 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
5529 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
5532 job
->job_sheets
= attr
;
5535 * Enforce classification level if set...
5540 LogMessage(L_INFO
, "Classification=\"%s\", ClassifyOverride=%d",
5541 Classification
? Classification
: "(null)", ClassifyOverride
);
5543 if (ClassifyOverride
)
5545 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
5546 (attr
->num_values
== 1 ||
5547 strcmp(attr
->values
[1].string
.text
, "none") == 0))
5550 * Force the leading banner to have the classification on it...
5553 SetString(&attr
->values
[0].string
.text
, Classification
);
5555 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5556 "job-sheets=\"%s,none\", "
5557 "job-originating-user-name=\"%s\"",
5558 job
->id
, Classification
,
5561 else if (attr
->num_values
== 2 &&
5562 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
5563 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
5564 strcmp(attr
->values
[1].string
.text
, "none") != 0)
5567 * Can't put two different security markings on the same document!
5570 SetString(&attr
->values
[1].string
.text
, attr
->values
[0].string
.text
);
5572 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5573 "job-sheets=\"%s,%s\", "
5574 "job-originating-user-name=\"%s\"",
5575 job
->id
, attr
->values
[0].string
.text
,
5576 attr
->values
[1].string
.text
,
5579 else if (strcmp(attr
->values
[0].string
.text
, Classification
) &&
5580 strcmp(attr
->values
[0].string
.text
, "none") &&
5581 (attr
->num_values
== 1 ||
5582 (strcmp(attr
->values
[1].string
.text
, Classification
) &&
5583 strcmp(attr
->values
[1].string
.text
, "none"))))
5585 if (attr
->num_values
== 1)
5586 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5587 "job-sheets=\"%s\", "
5588 "job-originating-user-name=\"%s\"",
5589 job
->id
, attr
->values
[0].string
.text
,
5592 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION OVERRIDDEN "
5593 "job-sheets=\"%s,%s\", "
5594 "job-originating-user-name=\"%s\"",
5595 job
->id
, attr
->values
[0].string
.text
,
5596 attr
->values
[1].string
.text
,
5600 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
5601 (attr
->num_values
== 1 ||
5602 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
5605 * Force the banner to have the classification on it...
5608 if (attr
->num_values
> 1 &&
5609 !strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
))
5611 SetString(&(attr
->values
[0].string
.text
), Classification
);
5612 SetString(&(attr
->values
[1].string
.text
), Classification
);
5616 if (attr
->num_values
== 1 ||
5617 strcmp(attr
->values
[0].string
.text
, "none"))
5618 SetString(&(attr
->values
[0].string
.text
), Classification
);
5620 if (attr
->num_values
> 1 &&
5621 strcmp(attr
->values
[1].string
.text
, "none"))
5622 SetString(&(attr
->values
[1].string
.text
), Classification
);
5625 if (attr
->num_values
> 1)
5626 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5627 "job-sheets=\"%s,%s\", "
5628 "job-originating-user-name=\"%s\"",
5629 job
->id
, attr
->values
[0].string
.text
,
5630 attr
->values
[1].string
.text
,
5633 LogMessage(L_NOTICE
, "[Job %d] CLASSIFICATION FORCED "
5634 "job-sheets=\"%s\", "
5635 "job-originating-user-name=\"%s\"",
5636 job
->id
, Classification
,
5642 * Add the starting sheet...
5645 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)))
5647 LogMessage(L_INFO
, "Adding start banner page \"%s\" to job %d.",
5648 attr
->values
[0].string
.text
, job
->id
);
5650 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
5652 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5655 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
5659 * Add the job file...
5662 if (add_file(con
, job
, filetype
, compression
))
5665 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
5667 rename(con
->filename
, filename
);
5668 ClearString(&con
->filename
);
5671 * See if we need to add the ending sheet...
5674 if (!(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
5675 attr
->num_values
> 1)
5681 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
5682 attr
->values
[1].string
.text
, job
->id
);
5684 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
5686 UpdateQuota(printer
, job
->username
, 0, kbytes
);
5690 * Add any job subscriptions...
5693 add_job_subscriptions(con
, job
);
5696 * Set all but the first two attributes to the job attributes group...
5699 for (attr
= job
->attrs
->attrs
->next
->next
; attr
; attr
= attr
->next
)
5700 attr
->group_tag
= IPP_TAG_JOB
;
5703 * Log and save the job...
5706 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
5707 job
->dest
, job
->username
);
5708 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, (int)job
->hold_until
);
5712 cupsdAddEvent(CUPSD_EVENT_JOB_CREATED
, printer
, job
, "Job created.");
5715 * Start the job if possible... Since CheckJobs() can cancel a job if it
5716 * doesn't print, we need to re-find the job afterwards...
5723 job
= FindJob(jobid
);
5726 * Fill in the response info...
5729 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
5732 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
5734 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
5736 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
5737 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
5738 add_job_state_reasons(con
, job
);
5740 con
->response
->request
.status
.status_code
= IPP_OK
;
5745 * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
5747 * This function only gets called when printing a single PostScript
5748 * file using the Print-Job operation. It doesn't work for Create-Job +
5749 * Send-File, since the job attributes need to be set at job creation
5750 * time for banners to work. The embedded PS job ticket stuff is here
5751 * only to allow the Windows printer driver for CUPS to pass in JCL
5752 * options and IPP attributes which otherwise would be lost.
5754 * The format of a PS job ticket is simple:
5756 * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
5758 * %cupsJobTicket: attr1=value1
5759 * %cupsJobTicket: attr2=value2
5761 * %cupsJobTicket: attrN=valueN
5763 * Job ticket lines must appear immediately after the first line that
5764 * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
5765 * looking for job ticket info when it finds a line that does not begin
5766 * with "%cupsJobTicket:".
5768 * The maximum length of a job ticket line, including the prefix, is
5769 * 255 characters to conform with the Adobe DSC.
5771 * Read-only attributes are rejected with a notice to the error log in
5772 * case a malicious user tries anything. Since the job ticket is read
5773 * prior to attribute validation in print_job(), job ticket attributes
5774 * will go through the same validation as IPP attributes...
5778 read_ps_job_ticket(client_t
*con
) /* I - Client connection */
5780 cups_file_t
*fp
; /* File to read from */
5781 char line
[256]; /* Line data */
5782 int num_options
; /* Number of options */
5783 cups_option_t
*options
; /* Options */
5784 ipp_t
*ticket
; /* New attributes */
5785 ipp_attribute_t
*attr
, /* Current attribute */
5786 *attr2
, /* Job attribute */
5787 *prev2
; /* Previous job attribute */
5791 * First open the print file...
5794 if ((fp
= cupsFileOpen(con
->filename
, "rb")) == NULL
)
5796 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to open PostScript print file - %s",
5802 * Skip the first line...
5805 if (cupsFileGets(fp
, line
, sizeof(line
)) == NULL
)
5807 LogMessage(L_ERROR
, "read_ps_job_ticket: Unable to read from PostScript print file - %s",
5813 if (strncmp(line
, "%!PS-Adobe-", 11) != 0)
5816 * Not a DSC-compliant file, so no job ticket info will be available...
5824 * Read job ticket info from the file...
5830 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
5833 * Stop at the first non-ticket line...
5836 if (strncmp(line
, "%cupsJobTicket:", 15) != 0)
5840 * Add the options to the option array...
5843 num_options
= cupsParseOptions(line
+ 15, num_options
, &options
);
5847 * Done with the file; see if we have any options...
5852 if (num_options
== 0)
5856 * OK, convert the options to an attribute list, and apply them to
5861 cupsEncodeOptions(ticket
, num_options
, options
);
5864 * See what the user wants to change.
5867 for (attr
= ticket
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5869 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
5872 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
5873 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
5874 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
5875 strcmp(attr
->name
, "job-k-octets") == 0 ||
5876 strcmp(attr
->name
, "job-id") == 0 ||
5877 strncmp(attr
->name
, "job-state", 9) == 0 ||
5878 strncmp(attr
->name
, "time-at-", 8) == 0)
5879 continue; /* Read-only attrs */
5881 if ((attr2
= ippFindAttribute(con
->request
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
5884 * Some other value; first free the old value...
5887 if (con
->request
->attrs
== attr2
)
5889 con
->request
->attrs
= attr2
->next
;
5894 for (prev2
= con
->request
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
5895 if (prev2
->next
== attr2
)
5897 prev2
->next
= attr2
->next
;
5902 if (con
->request
->last
== attr2
)
5903 con
->request
->last
= prev2
;
5905 _ipp_free_attr(attr2
);
5909 * Add new option by copying it...
5912 copy_attribute(con
->request
, attr
, 0);
5916 * Then free the attribute list and option array...
5920 cupsFreeOptions(num_options
, options
);
5925 * 'reject_jobs()' - Reject print jobs to a printer.
5929 reject_jobs(client_t
*con
, /* I - Client connection */
5930 ipp_attribute_t
*uri
) /* I - Printer or class URI */
5932 cups_ptype_t dtype
; /* Destination type (printer or class) */
5933 char method
[HTTP_MAX_URI
], /* Method portion of URI */
5934 username
[HTTP_MAX_URI
], /* Username portion of URI */
5935 host
[HTTP_MAX_URI
], /* Host portion of URI */
5936 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
5937 int port
; /* Port portion of URI */
5938 const char *name
; /* Printer name */
5939 printer_t
*printer
; /* Printer data */
5940 ipp_attribute_t
*attr
; /* printer-state-message text */
5943 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
5944 uri
->values
[0].string
.text
);
5947 * Was this operation called from the correct URI?
5950 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5952 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
5954 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5959 * Is the destination valid?
5962 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5964 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
5970 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
5971 send_ipp_error(con
, IPP_NOT_FOUND
);
5979 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
5981 LogMessage(L_ERROR
, "reject_jobs: not authorized!");
5982 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5987 * Reject jobs sent to the printer...
5990 printer
->accepting
= 0;
5992 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
5993 IPP_TAG_TEXT
)) == NULL
)
5994 strcpy(printer
->state_message
, "Rejecting Jobs");
5996 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
5997 sizeof(printer
->state_message
));
5999 AddPrinterHistory(printer
);
6001 if (dtype
& CUPS_PRINTER_CLASS
)
6005 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
6012 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
6017 * Everything was ok, so return OK status...
6020 con
->response
->request
.status
.status_code
= IPP_OK
;
6025 * 'release_job()' - Release a held print job.
6029 release_job(client_t
*con
, /* I - Client connection */
6030 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6032 ipp_attribute_t
*attr
; /* Current attribute */
6033 int jobid
; /* Job ID */
6034 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6035 username
[HTTP_MAX_URI
], /* Username portion of URI */
6036 host
[HTTP_MAX_URI
], /* Host portion of URI */
6037 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6038 int port
; /* Port portion of URI */
6039 job_t
*job
; /* Job information */
6042 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6043 uri
->values
[0].string
.text
);
6046 * Verify that the POST operation was done to a valid URI.
6049 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6050 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6051 strncmp(con
->uri
, "/printers/", 10) != 0)
6053 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
6055 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6060 * See if we have a job URI or a printer URI...
6063 if (strcmp(uri
->name
, "printer-uri") == 0)
6066 * Got a printer URI; see if we also have a job-id attribute...
6069 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6071 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
6072 send_ipp_error(con
, IPP_BAD_REQUEST
);
6076 jobid
= attr
->values
[0].integer
;
6081 * Got a job URI; parse it to get the job ID...
6084 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6086 if (strncmp(resource
, "/jobs/", 6) != 0)
6092 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
6093 uri
->values
[0].string
.text
);
6094 send_ipp_error(con
, IPP_BAD_REQUEST
);
6098 jobid
= atoi(resource
+ 6);
6102 * See if the job exists...
6105 if ((job
= FindJob(jobid
)) == NULL
)
6108 * Nope - return a "not found" error...
6111 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
6112 send_ipp_error(con
, IPP_NOT_FOUND
);
6117 * See if job is "held"...
6120 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
6123 * Nope - return a "not possible" error...
6126 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
6127 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6132 * See if the job is owned by the requesting user...
6135 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6137 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
6138 username
, jobid
, job
->username
);
6139 send_ipp_error(con
, IPP_FORBIDDEN
);
6144 * Reset the job-hold-until value to "no-hold"...
6147 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6148 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6152 free(attr
->values
[0].string
.text
);
6153 attr
->value_tag
= IPP_TAG_KEYWORD
;
6154 attr
->values
[0].string
.text
= strdup("no-hold");
6158 * Release the job and return...
6163 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
6165 con
->response
->request
.status
.status_code
= IPP_OK
;
6170 * 'renew_subscription()' - Renew an existing subscription...
6174 renew_subscription(client_t
*con
, /* I - Client connection */
6175 int sub_id
) /* I - Subscription ID */
6181 * 'restart_job()' - Restart an old print job.
6185 restart_job(client_t
*con
, /* I - Client connection */
6186 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
6188 ipp_attribute_t
*attr
; /* Current attribute */
6189 int jobid
; /* Job ID */
6190 char method
[HTTP_MAX_URI
], /* Method portion of URI */
6191 username
[HTTP_MAX_URI
], /* Username portion of URI */
6192 host
[HTTP_MAX_URI
], /* Host portion of URI */
6193 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
6194 int port
; /* Port portion of URI */
6195 job_t
*job
; /* Job information */
6198 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
6199 uri
->values
[0].string
.text
);
6202 * Verify that the POST operation was done to a valid URI.
6205 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6206 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
6207 strncmp(con
->uri
, "/printers/", 10) != 0)
6209 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
6211 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6216 * See if we have a job URI or a printer URI...
6219 if (strcmp(uri
->name
, "printer-uri") == 0)
6222 * Got a printer URI; see if we also have a job-id attribute...
6225 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6227 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
6228 send_ipp_error(con
, IPP_BAD_REQUEST
);
6232 jobid
= attr
->values
[0].integer
;
6237 * Got a job URI; parse it to get the job ID...
6240 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6242 if (strncmp(resource
, "/jobs/", 6) != 0)
6248 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
6249 uri
->values
[0].string
.text
);
6250 send_ipp_error(con
, IPP_BAD_REQUEST
);
6254 jobid
= atoi(resource
+ 6);
6258 * See if the job exists...
6261 if ((job
= FindJob(jobid
)) == NULL
)
6264 * Nope - return a "not found" error...
6267 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
6268 send_ipp_error(con
, IPP_NOT_FOUND
);
6273 * See if job is in any of the "completed" states...
6276 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
6279 * Nope - return a "not possible" error...
6282 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
6283 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6288 * See if we have retained the job files...
6291 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6294 * Nope - return a "not possible" error...
6297 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
6298 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6303 * See if the job is owned by the requesting user...
6306 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6308 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
6309 username
, jobid
, job
->username
);
6310 send_ipp_error(con
, IPP_FORBIDDEN
);
6315 * Restart the job and return...
6320 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
6322 con
->response
->request
.status
.status_code
= IPP_OK
;
6327 * 'send_document()' - Send a file to a printer or class.
6331 send_document(client_t
*con
, /* I - Client connection */
6332 ipp_attribute_t
*uri
) /* I - Printer URI */
6334 ipp_attribute_t
*attr
; /* Current attribute */
6335 ipp_attribute_t
*format
; /* Document-format attribute */
6336 int jobid
; /* Job ID number */
6337 job_t
*job
; /* Current job */
6338 char job_uri
[HTTP_MAX_URI
],
6340 method
[HTTP_MAX_URI
],
6341 /* Method portion of URI */
6342 username
[HTTP_MAX_URI
],
6343 /* Username portion of URI */
6345 /* Host portion of URI */
6346 resource
[HTTP_MAX_URI
];
6347 /* Resource portion of URI */
6348 int port
; /* Port portion of URI */
6349 mime_type_t
*filetype
; /* Type of file */
6350 char super
[MIME_MAX_SUPER
],
6351 /* Supertype of file */
6352 type
[MIME_MAX_TYPE
],
6353 /* Subtype of file */
6354 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
6355 /* Textual name of mime type */
6356 char filename
[1024]; /* Job filename */
6357 printer_t
*printer
; /* Current printer */
6358 struct stat fileinfo
; /* File information */
6359 int kbytes
; /* Size of file */
6360 int compression
; /* Type of compression */
6363 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
6364 uri
->values
[0].string
.text
);
6367 * Verify that the POST operation was done to a valid URI.
6370 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
6371 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
6372 strncmp(con
->uri
, "/printers/", 10) != 0)
6374 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
6376 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6381 * See if we have a job URI or a printer URI...
6384 if (strcmp(uri
->name
, "printer-uri") == 0)
6387 * Got a printer URI; see if we also have a job-id attribute...
6390 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6392 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
6393 send_ipp_error(con
, IPP_BAD_REQUEST
);
6397 jobid
= attr
->values
[0].integer
;
6402 * Got a job URI; parse it to get the job ID...
6405 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6407 if (strncmp(resource
, "/jobs/", 6) != 0)
6413 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
6414 uri
->values
[0].string
.text
);
6415 send_ipp_error(con
, IPP_BAD_REQUEST
);
6419 jobid
= atoi(resource
+ 6);
6423 * See if the job exists...
6426 if ((job
= FindJob(jobid
)) == NULL
)
6429 * Nope - return a "not found" error...
6432 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
6433 send_ipp_error(con
, IPP_NOT_FOUND
);
6438 * See if the job is owned by the requesting user...
6441 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6443 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
6444 username
, jobid
, job
->username
);
6445 send_ipp_error(con
, IPP_FORBIDDEN
);
6450 * OK, see if the client is sending the document compressed - CUPS
6451 * only supports "none" and "gzip".
6454 compression
= CUPS_FILE_NONE
;
6456 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
)
6458 if (strcmp(attr
->values
[0].string
.text
, "none")
6460 && strcmp(attr
->values
[0].string
.text
, "gzip")
6461 #endif /* HAVE_LIBZ */
6464 LogMessage(L_ERROR
, "print_job: Unsupported compression \"%s\"!",
6465 attr
->values
[0].string
.text
);
6466 send_ipp_error(con
, IPP_ATTRIBUTES
);
6467 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
6468 "compression", NULL
, attr
->values
[0].string
.text
);
6473 if (!strcmp(attr
->values
[0].string
.text
, "gzip"))
6474 compression
= CUPS_FILE_GZIP
;
6475 #endif /* HAVE_LIBZ */
6479 * Do we have a file to print?
6484 LogMessage(L_ERROR
, "send_document: No file!?!");
6485 send_ipp_error(con
, IPP_BAD_REQUEST
);
6490 * Is it a format we support?
6493 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
6496 * Grab format from client...
6499 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
6501 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
6502 format
->values
[0].string
.text
);
6503 send_ipp_error(con
, IPP_BAD_REQUEST
);
6510 * No document format attribute? Auto-type it!
6513 strcpy(super
, "application");
6514 strcpy(type
, "octet-stream");
6517 if (strcmp(super
, "application") == 0 &&
6518 strcmp(type
, "octet-stream") == 0)
6521 * Auto-type the file...
6524 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
6526 filetype
= mimeFileType(MimeDatabase
, con
->filename
, &compression
);
6528 if (filetype
!= NULL
)
6531 * Replace the document-format attribute value with the auto-typed one.
6534 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
6539 free(format
->values
[0].string
.text
);
6540 format
->values
[0].string
.text
= strdup(mimetype
);
6543 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
6544 "document-format", NULL
, mimetype
);
6547 filetype
= mimeType(MimeDatabase
, super
, type
);
6550 filetype
= mimeType(MimeDatabase
, super
, type
);
6552 if (filetype
== NULL
)
6554 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
6556 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
6557 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
6560 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
6561 "document-format", NULL
, format
->values
[0].string
.text
);
6566 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
6567 filetype
->super
, filetype
->type
);
6570 * Add the file to the job...
6573 if (add_file(con
, job
, filetype
, compression
))
6576 if (job
->dtype
& CUPS_PRINTER_CLASS
)
6577 printer
= FindClass(job
->dest
);
6579 printer
= FindPrinter(job
->dest
);
6581 if (stat(con
->filename
, &fileinfo
))
6584 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
6586 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6588 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
6589 attr
->values
[0].integer
+= kbytes
;
6591 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
6593 rename(con
->filename
, filename
);
6595 ClearString(&con
->filename
);
6597 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
6598 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
6601 * Start the job if this is the last document...
6604 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
6605 attr
->values
[0].boolean
)
6608 * See if we need to add the ending sheet...
6611 if (printer
!= NULL
&&
6612 !(printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
)) &&
6613 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
6614 attr
->num_values
> 1)
6620 LogMessage(L_INFO
, "Adding end banner page \"%s\" to job %d.",
6621 attr
->values
[1].string
.text
, job
->id
);
6623 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
6625 UpdateQuota(printer
, job
->username
, 0, kbytes
);
6628 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
6629 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6630 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
6632 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6633 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6635 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6636 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
6642 * Start the job if possible... Since CheckJobs() can cancel a job if it
6643 * doesn't print, we need to re-find the job afterwards...
6650 job
= FindJob(jobid
);
6654 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
6655 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
6657 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
6659 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
6660 job
->hold_until
= time(NULL
) + 60;
6666 * Fill in the response info...
6669 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
6672 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
6675 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", jobid
);
6677 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
6678 job
? job
->state
->values
[0].integer
: IPP_JOB_CANCELLED
);
6679 add_job_state_reasons(con
, job
);
6681 con
->response
->request
.status
.status_code
= IPP_OK
;
6686 * 'send_ipp_error()' - Send an error status back to the IPP client.
6690 send_ipp_error(client_t
*con
, /* I - Client connection */
6691 ipp_status_t status
) /* I - IPP status code */
6693 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
6696 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
6698 con
->response
->request
.status
.status_code
= status
;
6700 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
6701 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
6702 "attributes-charset", NULL
, DefaultCharset
);
6704 if (ippFindAttribute(con
->response
, "attributes-natural-language",
6705 IPP_TAG_ZERO
) == NULL
)
6706 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
6707 "attributes-natural-language", NULL
, DefaultLanguage
);
6712 * 'set_default()' - Set the default destination...
6716 set_default(client_t
*con
, /* I - Client connection */
6717 ipp_attribute_t
*uri
) /* I - Printer URI */
6719 cups_ptype_t dtype
; /* Destination type (printer or class) */
6720 char method
[HTTP_MAX_URI
],
6721 /* Method portion of URI */
6722 username
[HTTP_MAX_URI
],
6723 /* Username portion of URI */
6725 /* Host portion of URI */
6726 resource
[HTTP_MAX_URI
];
6727 /* Resource portion of URI */
6728 int port
; /* Port portion of URI */
6729 const char *name
; /* Printer name */
6730 printer_t
*printer
; /* Printer */
6733 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
6734 uri
->values
[0].string
.text
);
6737 * Was this operation called from the correct URI?
6740 if (strncmp(con
->uri
, "/admin/", 7) != 0)
6742 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
6744 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6749 * Is the destination valid?
6752 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6754 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
6760 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
6761 send_ipp_error(con
, IPP_NOT_FOUND
);
6769 if (!CheckPolicy(DefaultPolicyPtr
, con
, NULL
))
6771 LogMessage(L_ERROR
, "set_default: not authorized!");
6772 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
6777 * Set it as the default...
6780 DefaultPrinter
= printer
;
6785 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
6789 * Everything was ok, so return OK status...
6792 con
->response
->request
.status
.status_code
= IPP_OK
;
6797 * 'set_job_attrs()' - Set job attributes.
6801 set_job_attrs(client_t
*con
, /* I - Client connection */
6802 ipp_attribute_t
*uri
) /* I - Job URI */
6804 ipp_attribute_t
*attr
, /* Current attribute */
6805 *attr2
, /* Job attribute */
6806 *prev2
; /* Previous job attribute */
6807 int jobid
; /* Job ID */
6808 job_t
*job
; /* Current job */
6809 char method
[HTTP_MAX_URI
],
6810 /* Method portion of URI */
6811 username
[HTTP_MAX_URI
],
6812 /* Username portion of URI */
6814 /* Host portion of URI */
6815 resource
[HTTP_MAX_URI
];
6816 /* Resource portion of URI */
6817 int port
; /* Port portion of URI */
6820 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
6821 uri
->values
[0].string
.text
);
6824 * Start with "everything is OK" status...
6827 con
->response
->request
.status
.status_code
= IPP_OK
;
6830 * See if we have a job URI or a printer URI...
6833 if (strcmp(uri
->name
, "printer-uri") == 0)
6836 * Got a printer URI; see if we also have a job-id attribute...
6839 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
6841 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
6842 send_ipp_error(con
, IPP_BAD_REQUEST
);
6846 jobid
= attr
->values
[0].integer
;
6851 * Got a job URI; parse it to get the job ID...
6854 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
6856 if (strncmp(resource
, "/jobs/", 6) != 0)
6862 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
6863 uri
->values
[0].string
.text
);
6864 send_ipp_error(con
, IPP_BAD_REQUEST
);
6868 jobid
= atoi(resource
+ 6);
6872 * See if the job exists...
6875 if ((job
= FindJob(jobid
)) == NULL
)
6878 * Nope - return a "not found" error...
6881 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
6882 send_ipp_error(con
, IPP_NOT_FOUND
);
6887 * See if the job has been completed...
6890 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
6893 * Return a "not-possible" error...
6896 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
6897 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6902 * See if the job is owned by the requesting user...
6905 if (!validate_user(job
, con
, job
->username
, username
, sizeof(username
)))
6907 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
6908 username
, jobid
, job
->username
);
6909 send_ipp_error(con
, IPP_FORBIDDEN
);
6914 * See what the user wants to change.
6917 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6919 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
6922 if (!strcmp(attr
->name
, "attributes-charset") ||
6923 !strcmp(attr
->name
, "attributes-natural-language") ||
6924 !strcmp(attr
->name
, "document-compression") ||
6925 !strcmp(attr
->name
, "document-format") ||
6926 !strcmp(attr
->name
, "job-detailed-status-messages") ||
6927 !strcmp(attr
->name
, "job-document-access-errors") ||
6928 !strcmp(attr
->name
, "job-id") ||
6929 !strcmp(attr
->name
, "job-k-octets") ||
6930 !strcmp(attr
->name
, "job-originating-host-name") ||
6931 !strcmp(attr
->name
, "job-originating-user-name") ||
6932 !strcmp(attr
->name
, "job-printer-up-time") ||
6933 !strcmp(attr
->name
, "job-printer-uri") ||
6934 !strcmp(attr
->name
, "job-sheets") ||
6935 !strcmp(attr
->name
, "job-state-message") ||
6936 !strcmp(attr
->name
, "job-state-reasons") ||
6937 !strcmp(attr
->name
, "job-uri") ||
6938 !strcmp(attr
->name
, "number-of-documents") ||
6939 !strcmp(attr
->name
, "number-of-intervening-jobs") ||
6940 !strcmp(attr
->name
, "output-device-assigned") ||
6941 !strncmp(attr
->name
, "date-time-at-", 13) ||
6942 !strncmp(attr
->name
, "job-impressions", 15) ||
6943 !strncmp(attr
->name
, "job-k-octets", 12) ||
6944 !strncmp(attr
->name
, "job-media-sheets", 16) ||
6945 !strncmp(attr
->name
, "time-at-", 8))
6951 send_ipp_error(con
, IPP_ATTRIBUTES_NOT_SETTABLE
);
6953 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6954 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6959 if (!strcmp(attr
->name
, "job-priority"))
6962 * Change the job priority...
6965 if (attr
->value_tag
!= IPP_TAG_INTEGER
)
6967 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6969 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6970 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6972 else if (job
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
6974 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
6977 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
6978 SetJobPriority(jobid
, attr
->values
[0].integer
);
6980 else if (!strcmp(attr
->name
, "job-state"))
6983 * Change the job state...
6986 if (attr
->value_tag
!= IPP_TAG_ENUM
)
6988 send_ipp_error(con
, IPP_REQUEST_VALUE
);
6990 if ((attr2
= copy_attribute(con
->response
, attr
, 0)) != NULL
)
6991 attr2
->group_tag
= IPP_TAG_UNSUPPORTED_GROUP
;
6995 switch (attr
->values
[0].integer
)
6997 case IPP_JOB_PENDING
:
6999 if (job
->state
->values
[0].integer
> IPP_JOB_HELD
)
7001 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7004 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7005 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7008 case IPP_JOB_PROCESSING
:
7009 case IPP_JOB_STOPPED
:
7010 if (job
->state
->values
[0].integer
!= attr
->values
[0].integer
)
7012 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7017 case IPP_JOB_CANCELLED
:
7018 case IPP_JOB_ABORTED
:
7019 case IPP_JOB_COMPLETED
:
7020 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
)
7022 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
7025 else if (con
->response
->request
.status
.status_code
== IPP_OK
)
7027 CancelJob(job
->id
, 0);
7031 job
->state
->values
[0].integer
= attr
->values
[0].integer
;
7039 else if (con
->response
->request
.status
.status_code
!= IPP_OK
)
7041 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
7044 * Some other value; first free the old value...
7047 if (job
->attrs
->attrs
== attr2
)
7049 job
->attrs
->attrs
= attr2
->next
;
7054 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
7055 if (prev2
->next
== attr2
)
7057 prev2
->next
= attr2
->next
;
7062 if (job
->attrs
->last
== attr2
)
7063 job
->attrs
->last
= prev2
;
7065 _ipp_free_attr(attr2
);
7068 * Then copy the attribute...
7071 copy_attribute(job
->attrs
, attr
, 0);
7074 * See if the job-name or job-hold-until is being changed.
7077 if (strcmp(attr
->name
, "job-hold-until") == 0)
7079 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
7081 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
7082 ReleaseJob(job
->id
);
7087 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
7090 * Delete the attribute...
7093 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
7095 prev2
= attr2
, attr2
= attr2
->next
)
7096 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
7102 prev2
->next
= attr2
->next
;
7104 job
->attrs
->attrs
= attr2
->next
;
7106 if (attr2
== job
->attrs
->last
)
7107 job
->attrs
->last
= prev2
;
7109 _ipp_free_attr(attr2
);
7115 * Add new option by copying it...
7118 copy_attribute(job
->attrs
, attr
, 0);
7129 * Start jobs if possible...
7137 * 'start_printer()' - Start a printer.
7141 start_printer(client_t
*con
, /* I - Client connection */
7142 ipp_attribute_t
*uri
) /* I - Printer URI */
7144 cups_ptype_t dtype
; /* Destination type (printer or class) */
7145 char method
[HTTP_MAX_URI
],
7146 /* Method portion of URI */
7147 username
[HTTP_MAX_URI
],
7148 /* Username portion of URI */
7150 /* Host portion of URI */
7151 resource
[HTTP_MAX_URI
];
7152 /* Resource portion of URI */
7153 int port
; /* Port portion of URI */
7154 const char *name
; /* Printer name */
7155 printer_t
*printer
; /* Printer data */
7158 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7159 uri
->values
[0].string
.text
);
7162 * Was this operation called from the correct URI?
7165 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7167 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
7169 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7174 * Is the destination valid?
7177 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7179 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7185 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
7186 send_ipp_error(con
, IPP_NOT_FOUND
);
7194 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7196 LogMessage(L_ERROR
, "start_printer: not authorized!");
7197 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7202 * Start the printer...
7205 printer
->state_message
[0] = '\0';
7207 StartPrinter(printer
, 1);
7209 if (dtype
& CUPS_PRINTER_CLASS
)
7210 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
7212 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
7218 * Everything was ok, so return OK status...
7221 con
->response
->request
.status
.status_code
= IPP_OK
;
7226 * 'stop_printer()' - Stop a printer.
7230 stop_printer(client_t
*con
, /* I - Client connection */
7231 ipp_attribute_t
*uri
) /* I - Printer URI */
7233 cups_ptype_t dtype
; /* Destination type (printer or class) */
7234 char method
[HTTP_MAX_URI
],
7235 /* Method portion of URI */
7236 username
[HTTP_MAX_URI
],
7237 /* Username portion of URI */
7239 /* Host portion of URI */
7240 resource
[HTTP_MAX_URI
];
7241 /* Resource portion of URI */
7242 int port
; /* Port portion of URI */
7243 const char *name
; /* Printer name */
7244 printer_t
*printer
; /* Printer data */
7245 ipp_attribute_t
*attr
; /* printer-state-message attribute */
7248 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
7249 uri
->values
[0].string
.text
);
7252 * Was this operation called from the correct URI?
7255 if (strncmp(con
->uri
, "/admin/", 7) != 0)
7257 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
7259 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7264 * Is the destination valid?
7267 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7269 if ((name
= ValidateDest(host
, resource
, &dtype
, &printer
)) == NULL
)
7275 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
7276 send_ipp_error(con
, IPP_NOT_FOUND
);
7284 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7286 LogMessage(L_ERROR
, "stop_printer: not authorized!");
7287 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7292 * Stop the printer...
7295 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
7296 IPP_TAG_TEXT
)) == NULL
)
7297 strcpy(printer
->state_message
, "Paused");
7300 strlcpy(printer
->state_message
, attr
->values
[0].string
.text
,
7301 sizeof(printer
->state_message
));
7304 StopPrinter(printer
, 1);
7306 if (dtype
& CUPS_PRINTER_CLASS
)
7307 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
7310 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
7314 * Everything was ok, so return OK status...
7317 con
->response
->request
.status
.status_code
= IPP_OK
;
7322 * 'user_allowed()' - See if a user is allowed to print to a queue.
7325 static int /* O - 0 if not allowed, 1 if allowed */
7326 user_allowed(printer_t
*p
, /* I - Printer or class */
7327 const char *username
) /* I - Username */
7329 int i
, j
; /* Looping vars */
7330 struct passwd
*pw
; /* User password data */
7331 struct group
*grp
; /* Group data */
7334 if (p
->num_users
== 0)
7337 if (!strcmp(username
, "root"))
7340 pw
= getpwnam(username
);
7343 for (i
= 0; i
< p
->num_users
; i
++)
7345 if (p
->users
[i
][0] == '@')
7348 * Check group membership...
7351 grp
= getgrnam(p
->users
[i
] + 1);
7357 * Check primary group...
7360 if (pw
&& grp
->gr_gid
== pw
->pw_gid
)
7364 * Check usernames in group...
7367 for (j
= 0; grp
->gr_mem
[j
]; j
++)
7368 if (!strcasecmp(username
, grp
->gr_mem
[j
]))
7375 else if (!strcasecmp(username
, p
->users
[i
]))
7379 return ((i
< p
->num_users
) != p
->deny_users
);
7384 * 'validate_job()' - Validate printer options and destination.
7388 validate_job(client_t
*con
, /* I - Client connection */
7389 ipp_attribute_t
*uri
) /* I - Printer URI */
7391 ipp_attribute_t
*attr
; /* Current attribute */
7392 ipp_attribute_t
*format
; /* Document-format attribute */
7393 cups_ptype_t dtype
; /* Destination type (printer or class) */
7394 char method
[HTTP_MAX_URI
],
7395 /* Method portion of URI */
7396 username
[HTTP_MAX_URI
],
7397 /* Username portion of URI */
7399 /* Host portion of URI */
7400 resource
[HTTP_MAX_URI
];
7401 /* Resource portion of URI */
7402 int port
; /* Port portion of URI */
7403 char super
[MIME_MAX_SUPER
],
7404 /* Supertype of file */
7405 type
[MIME_MAX_TYPE
];
7406 /* Subtype of file */
7407 printer_t
*printer
; /* Printer */
7410 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
7411 uri
->values
[0].string
.text
);
7414 * Verify that the POST operation was done to a valid URI.
7417 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
7418 strncmp(con
->uri
, "/printers/", 10) != 0)
7420 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
7422 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7427 * OK, see if the client is sending the document compressed - CUPS
7428 * doesn't support compression yet...
7431 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
7432 strcmp(attr
->values
[0].string
.text
, "none") == 0)
7434 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
7435 attr
->values
[0].string
.text
);
7436 send_ipp_error(con
, IPP_ATTRIBUTES
);
7437 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
7438 "compression", NULL
, attr
->values
[0].string
.text
);
7443 * Is it a format we support?
7446 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
7448 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
7450 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
7451 format
->values
[0].string
.text
);
7452 send_ipp_error(con
, IPP_BAD_REQUEST
);
7456 if ((strcmp(super
, "application") != 0 ||
7457 strcmp(type
, "octet-stream") != 0) &&
7458 mimeType(MimeDatabase
, super
, type
) == NULL
)
7460 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
7461 format
->values
[0].string
.text
);
7462 LogMessage(L_INFO
, "Hint: Do you have the raw file printing rules enabled?");
7463 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
7464 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
7465 "document-format", NULL
, format
->values
[0].string
.text
);
7471 * Is the destination valid?
7474 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
7476 if (ValidateDest(host
, resource
, &dtype
, &printer
) == NULL
)
7482 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
7483 send_ipp_error(con
, IPP_NOT_FOUND
);
7491 if (!CheckPolicy(printer
->op_policy_ptr
, con
, NULL
))
7493 LogMessage(L_ERROR
, "validate_job: not authorized!");
7494 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
7499 * Everything was ok, so return OK status...
7502 con
->response
->request
.status
.status_code
= IPP_OK
;
7507 * 'validate_name()' - Make sure the printer name only contains valid chars.
7510 static int /* O - 0 if name is no good, 1 if name is good */
7511 validate_name(const char *name
) /* I - Name to check */
7513 const char *ptr
; /* Pointer into name */
7517 * Scan the whole name...
7520 for (ptr
= name
; *ptr
; ptr
++)
7521 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
7525 * All the characters are good; validate the length, too...
7528 return ((ptr
- name
) < 128);
7533 * 'validate_user()' - Validate the user for the request.
7536 static int /* O - 1 if permitted, 0 otherwise */
7537 validate_user(job_t
*job
, /* I - Job */
7538 client_t
*con
, /* I - Client connection */
7539 const char *owner
, /* I - Owner of job/resource */
7540 char *username
, /* O - Authenticated username */
7541 int userlen
) /* I - Length of username */
7543 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
7544 printer_t
*printer
; /* Printer for job */
7547 LogMessage(L_DEBUG2
, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=%d)\n",
7548 job
? job
->id
: 0, con
->http
.fd
, owner
? owner
: "(null)",
7555 if (!con
|| !owner
|| !username
|| userlen
<= 0)
7559 * Get the best authenticated username that is available.
7562 if (con
->username
[0])
7563 strlcpy(username
, con
->username
, userlen
);
7564 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
7565 strlcpy(username
, attr
->values
[0].string
.text
, userlen
);
7567 strlcpy(username
, "anonymous", userlen
);
7570 * Check the username against the owner...
7573 if (job
->dtype
& CUPS_PRINTER_CLASS
)
7574 printer
= FindClass(job
->dest
);
7576 printer
= FindPrinter(job
->dest
);
7579 return (CheckPolicy(printer
->op_policy_ptr
, con
, owner
));
7581 return (CheckPolicy(DefaultPolicyPtr
, con
, owner
));