2 * "$Id: ipp.c,v 1.146 2001/10/22 21:04:08 mike Exp $"
4 * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 1997-2001 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-3111 USA
20 * Voice: (301) 373-9603
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_printer() - Add a printer to the system.
33 * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
34 * based upon the printer state...
35 * add_queued_job_count() - Add the "queued-job-count" attribute for
36 * cancel_all_jobs() - Cancel all print jobs.
37 * cancel_job() - Cancel a print job.
38 * check_quotas() - Check quotas for a printer and user.
39 * copy_attribute() - Copy a single attribute.
40 * copy_attrs() - Copy attributes from one request to another.
41 * create_job() - Print a file to a printer or class.
42 * copy_banner() - Copy a banner file to the requests directory
43 * for the specified job.
44 * copy_file() - Copy a PPD file or interface script...
45 * delete_printer() - Remove a printer or class from the system.
46 * get_default() - Get the default destination.
47 * get_devices() - Get the list of available devices on the
49 * get_jobs() - Get a list of jobs for the specified printer.
50 * get_job_attrs() - Get job attributes.
51 * get_ppds() - Get the list of PPD files on the local
53 * get_printer_attrs() - Get printer attributes.
54 * get_printers() - Get a list of printers.
55 * hold_job() - Hold a print job.
56 * move_job() - Move a job.
57 * print_job() - Print a file to a printer or class.
58 * reject_jobs() - Reject print jobs to a printer.
59 * release_job() - Release a held print job.
60 * restart_job() - Restart an old print job.
61 * send_document() - Send a file to a printer or class.
62 * send_ipp_error() - Send an error status back to the IPP client.
63 * set_default() - Set the default destination...
64 * set_job_attrs() - Set job attributes.
65 * start_printer() - Start a printer.
66 * stop_printer() - Stop a printer.
67 * validate_job() - Validate printer options and destination.
68 * validate_user() - Validate the user for the request.
72 * Include necessary headers...
80 #endif /* HAVE_LIBZ */
87 static void accept_jobs(client_t
*con
, ipp_attribute_t
*uri
);
88 static void add_class(client_t
*con
, ipp_attribute_t
*uri
);
89 static int add_file(client_t
*con
, job_t
*job
, mime_type_t
*filetype
);
90 static void add_job_state_reasons(client_t
*con
, job_t
*job
);
91 static void add_printer(client_t
*con
, ipp_attribute_t
*uri
);
92 static void add_printer_state_reasons(client_t
*con
, printer_t
*p
);
93 static void add_queued_job_count(client_t
*con
, printer_t
*p
);
94 static void cancel_all_jobs(client_t
*con
, ipp_attribute_t
*uri
);
95 static void cancel_job(client_t
*con
, ipp_attribute_t
*uri
);
96 static int check_quotas(client_t
*con
, printer_t
*p
);
97 static void copy_attribute(ipp_t
*to
, ipp_attribute_t
*attr
,
99 static void copy_attrs(ipp_t
*to
, ipp_t
*from
, ipp_attribute_t
*req
,
101 static int copy_banner(client_t
*con
, job_t
*job
, const char *name
);
102 static int copy_file(const char *from
, const char *to
);
103 static void create_job(client_t
*con
, ipp_attribute_t
*uri
);
104 static void delete_printer(client_t
*con
, ipp_attribute_t
*uri
);
105 static void get_default(client_t
*con
);
106 static void get_devices(client_t
*con
);
107 static void get_jobs(client_t
*con
, ipp_attribute_t
*uri
);
108 static void get_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
109 static void get_ppds(client_t
*con
);
110 static void get_printers(client_t
*con
, int type
);
111 static void get_printer_attrs(client_t
*con
, ipp_attribute_t
*uri
);
112 static void hold_job(client_t
*con
, ipp_attribute_t
*uri
);
113 static void move_job(client_t
*con
, ipp_attribute_t
*uri
);
114 static void print_job(client_t
*con
, ipp_attribute_t
*uri
);
115 static void reject_jobs(client_t
*con
, ipp_attribute_t
*uri
);
116 static void release_job(client_t
*con
, ipp_attribute_t
*uri
);
117 static void restart_job(client_t
*con
, ipp_attribute_t
*uri
);
118 static void send_document(client_t
*con
, ipp_attribute_t
*uri
);
119 static void send_ipp_error(client_t
*con
, ipp_status_t status
);
120 static void set_default(client_t
*con
, ipp_attribute_t
*uri
);
121 static void set_job_attrs(client_t
*con
, ipp_attribute_t
*uri
);
122 static void start_printer(client_t
*con
, ipp_attribute_t
*uri
);
123 static void stop_printer(client_t
*con
, ipp_attribute_t
*uri
);
124 static void validate_job(client_t
*con
, ipp_attribute_t
*uri
);
125 static int validate_user(client_t
*con
, const char *owner
, char *username
,
130 * 'ProcessIPPRequest()' - Process an incoming IPP request...
134 ProcessIPPRequest(client_t
*con
) /* I - Client connection */
136 ipp_tag_t group
; /* Current group tag */
137 ipp_attribute_t
*attr
; /* Current attribute */
138 ipp_attribute_t
*charset
; /* Character set attribute */
139 ipp_attribute_t
*language
; /* Language attribute */
140 ipp_attribute_t
*uri
; /* Printer URI attribute */
141 ipp_attribute_t
*username
; /* requesting-user-name attr */
144 LogMessage(L_DEBUG2
, "ProcessIPPRequest(%p[%d]): operation_id = %04x",
145 con
, con
->http
.fd
, con
->request
->request
.op
.operation_id
);
148 * First build an empty response message for this request...
151 con
->response
= ippNew();
153 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
154 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
155 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
158 * Then validate the request header and required attributes...
161 if (con
->request
->request
.any
.version
[0] != 1)
164 * Return an error, since we only support IPP 1.x.
167 LogMessage(L_ERROR
, "ProcessIPPRequest: bad request version (%d.%d)!",
168 con
->request
->request
.any
.version
[0],
169 con
->request
->request
.any
.version
[1]);
171 send_ipp_error(con
, IPP_VERSION_NOT_SUPPORTED
);
173 else if (con
->request
->attrs
== NULL
)
175 LogMessage(L_ERROR
, "ProcessIPPRequest: no attributes in request!");
176 send_ipp_error(con
, IPP_BAD_REQUEST
);
181 * Make sure that the attributes are provided in the correct order and
182 * don't repeat groups...
185 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
188 if (attr
->group_tag
< group
)
191 * Out of order; return an error...
194 LogMessage(L_ERROR
, "ProcessIPPRequest: attribute groups are out of order!");
195 send_ipp_error(con
, IPP_BAD_REQUEST
);
199 group
= attr
->group_tag
;
204 * Then make sure that the first three attributes are:
207 * attributes-natural-language
208 * printer-uri/job-uri
211 attr
= con
->request
->attrs
;
212 if (attr
!= NULL
&& strcmp(attr
->name
, "attributes-charset") == 0 &&
213 attr
->value_tag
== IPP_TAG_CHARSET
)
220 if (attr
!= NULL
&& strcmp(attr
->name
, "attributes-natural-language") == 0 &&
221 attr
->value_tag
== IPP_TAG_LANGUAGE
)
226 if ((attr
= ippFindAttribute(con
->request
, "printer-uri", IPP_TAG_URI
)) != NULL
)
228 else if ((attr
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
)) != NULL
)
234 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
235 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
237 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
238 "attributes-charset", NULL
, DefaultCharset
);
241 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
242 "attributes-natural-language", NULL
,
243 language
->values
[0].string
.text
);
245 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
246 "attributes-natural-language", NULL
, DefaultLanguage
);
248 if (charset
== NULL
|| language
== NULL
||
250 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
251 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
252 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
253 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
254 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
257 * Return an error, since attributes-charset,
258 * attributes-natural-language, and printer-uri/job-uri are required
259 * for all operations.
263 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-charset attribute!");
265 if (language
== NULL
)
266 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-natural-language attribute!");
269 LogMessage(L_ERROR
, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
271 LogMessage(L_DEBUG
, "Request attributes follow...");
273 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
274 LogMessage(L_DEBUG
, "attr \"%s\": group_tag = %x, value_tag = %x",
275 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
278 LogMessage(L_DEBUG
, "End of attributes...");
280 send_ipp_error(con
, IPP_BAD_REQUEST
);
285 * OK, all the checks pass so far; make sure requesting-user-name is
286 * not "root" from a remote host...
289 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
292 * Check for root user...
295 if (strcmp(username
->values
[0].string
.text
, "root") == 0 &&
296 ntohl(con
->http
.hostaddr
.sin_addr
.s_addr
) != 0x7f000001 &&
297 strcmp(con
->username
, "root") != 0)
300 * Remote unauthenticated user masquerading as local root...
303 free(username
->values
[0].string
.text
);
304 username
->values
[0].string
.text
= strdup(RemoteRoot
);
309 * Then try processing the operation...
312 switch (con
->request
->request
.op
.operation_id
)
318 case IPP_VALIDATE_JOB
:
319 validate_job(con
, uri
);
322 case IPP_CREATE_JOB
:
323 create_job(con
, uri
);
326 case IPP_SEND_DOCUMENT
:
327 send_document(con
, uri
);
330 case IPP_CANCEL_JOB
:
331 cancel_job(con
, uri
);
334 case IPP_GET_JOB_ATTRIBUTES
:
335 get_job_attrs(con
, uri
);
342 case IPP_GET_PRINTER_ATTRIBUTES
:
343 get_printer_attrs(con
, uri
);
350 case IPP_RELEASE_JOB
:
351 release_job(con
, uri
);
354 case IPP_RESTART_JOB
:
355 restart_job(con
, uri
);
358 case IPP_PAUSE_PRINTER
:
359 stop_printer(con
, uri
);
362 case IPP_RESUME_PRINTER
:
363 start_printer(con
, uri
);
366 case IPP_PURGE_JOBS
:
367 cancel_all_jobs(con
, uri
);
370 case IPP_SET_JOB_ATTRIBUTES
:
371 set_job_attrs(con
, uri
);
374 case CUPS_GET_DEFAULT
:
378 case CUPS_GET_PRINTERS
:
379 get_printers(con
, 0);
382 case CUPS_GET_CLASSES
:
383 get_printers(con
, CUPS_PRINTER_CLASS
);
386 case CUPS_ADD_PRINTER
:
387 add_printer(con
, uri
);
390 case CUPS_DELETE_PRINTER
:
391 delete_printer(con
, uri
);
394 case CUPS_ADD_CLASS
:
398 case CUPS_DELETE_CLASS
:
399 delete_printer(con
, uri
);
402 case CUPS_ACCEPT_JOBS
:
403 case IPP_ENABLE_PRINTER
:
404 accept_jobs(con
, uri
);
407 case CUPS_REJECT_JOBS
:
408 case IPP_DISABLE_PRINTER
:
409 reject_jobs(con
, uri
);
412 case CUPS_SET_DEFAULT
:
413 set_default(con
, uri
);
416 case CUPS_GET_DEVICES
:
429 send_ipp_error(con
, IPP_OPERATION_NOT_SUPPORTED
);
435 SendHeader(con
, HTTP_OK
, "application/ipp");
437 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
438 con
->http
.data_remaining
= ippLength(con
->response
);
440 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
441 con
->http
.data_remaining
);
443 FD_SET(con
->http
.fd
, &OutputSet
);
448 * 'accept_jobs()' - Accept print jobs to a printer.
452 accept_jobs(client_t
*con
, /* I - Client connection */
453 ipp_attribute_t
*uri
) /* I - Printer or class URI */
455 cups_ptype_t dtype
; /* Destination type (printer or class) */
456 char method
[HTTP_MAX_URI
],
457 /* Method portion of URI */
458 username
[HTTP_MAX_URI
],
459 /* Username portion of URI */
461 /* Host portion of URI */
462 resource
[HTTP_MAX_URI
];
463 /* Resource portion of URI */
464 int port
; /* Port portion of URI */
465 const char *name
; /* Printer name */
466 printer_t
*printer
; /* Printer data */
469 LogMessage(L_DEBUG2
, "accept_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
470 uri
->values
[0].string
.text
);
473 * Was this operation called from the correct URI?
476 if (strncmp(con
->uri
, "/admin/", 7) != 0)
478 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
480 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
485 * Is the destination valid?
488 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
490 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
496 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
497 send_ipp_error(con
, IPP_NOT_FOUND
);
502 * Accept jobs sent to the printer...
505 if (dtype
== CUPS_PRINTER_CLASS
)
506 printer
= FindClass(name
);
508 printer
= FindPrinter(name
);
510 printer
->accepting
= 1;
511 printer
->state_message
[0] = '\0';
513 if (dtype
== CUPS_PRINTER_CLASS
)
518 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
522 * Everything was ok, so return OK status...
525 con
->response
->request
.status
.status_code
= IPP_OK
;
530 * 'add_class()' - Add a class to the system.
534 add_class(client_t
*con
, /* I - Client connection */
535 ipp_attribute_t
*uri
) /* I - URI of class */
537 int i
; /* Looping var */
538 char method
[HTTP_MAX_URI
],
539 /* Method portion of URI */
540 username
[HTTP_MAX_URI
],
541 /* Username portion of URI */
543 /* Host portion of URI */
544 resource
[HTTP_MAX_URI
];
545 /* Resource portion of URI */
546 int port
; /* Port portion of URI */
547 printer_t
*pclass
; /* Class */
548 cups_ptype_t dtype
; /* Destination type */
549 const char *dest
; /* Printer or class name */
550 ipp_attribute_t
*attr
; /* Printer attribute */
551 int modify
; /* Non-zero if we just modified */
554 LogMessage(L_DEBUG2
, "add_class(%p[%d], %s)\n", con
, con
->http
.fd
,
555 uri
->values
[0].string
.text
);
558 * Was this operation called from the correct URI?
561 if (strncmp(con
->uri
, "/admin/", 7) != 0)
563 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
565 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
570 * Do we have a valid URI?
573 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
575 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
578 * No, return an error...
581 send_ipp_error(con
, IPP_BAD_REQUEST
);
586 * See if the class already exists; if not, create a new class...
589 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
592 * Class doesn't exist; see if we have a printer of the same name...
595 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
596 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
599 * Yes, return an error...
602 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
607 * No, add the pclass...
610 pclass
= AddClass(resource
+ 9);
613 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
616 * Rename the implicit class to "AnyClass" or remove it...
619 if (ImplicitAnyClasses
)
621 snprintf(pclass
->name
, sizeof(pclass
->name
), "Any%s", resource
+ 9);
625 DeletePrinter(pclass
);
628 * Add the class as a new local class...
631 pclass
= AddClass(resource
+ 9);
634 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
637 * Rename the remote class to "Class"...
640 DeletePrinterFilters(pclass
);
641 snprintf(pclass
->name
, sizeof(pclass
->name
), "%s@%s", resource
+ 9,
643 SetPrinterAttrs(pclass
);
647 * Add the class as a new local class...
650 pclass
= AddClass(resource
+ 9);
657 * Look for attributes and copy them over as needed...
660 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
662 strncpy(pclass
->location
, attr
->values
[0].string
.text
, sizeof(pclass
->location
) - 1);
663 pclass
->location
[sizeof(pclass
->location
) - 1] = '\0';
666 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
668 strncpy(pclass
->info
, attr
->values
[0].string
.text
, sizeof(pclass
->info
) - 1);
669 pclass
->info
[sizeof(pclass
->info
) - 1] = '\0';
672 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
674 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
675 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
677 pclass
->accepting
= attr
->values
[0].boolean
;
679 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
681 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
682 attr
->values
[0].integer
, pclass
->state
);
684 if (pclass
->state
== IPP_PRINTER_STOPPED
&&
685 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
686 pclass
->state
= IPP_PRINTER_IDLE
;
687 else if (pclass
->state
!= IPP_PRINTER_STOPPED
&&
688 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
690 if (pclass
->state
== IPP_PRINTER_PROCESSING
)
691 StopJob(((job_t
*)pclass
->job
)->id
);
693 pclass
->state
= IPP_PRINTER_STOPPED
;
696 pclass
->browse_time
= 0;
698 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
700 strncpy(pclass
->state_message
, attr
->values
[0].string
.text
,
701 sizeof(pclass
->state_message
) - 1);
702 pclass
->state_message
[sizeof(pclass
->state_message
) - 1] = '\0';
704 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
707 strncpy(pclass
->job_sheets
[0], attr
->values
[0].string
.text
,
708 sizeof(pclass
->job_sheets
[0]) - 1);
709 if (attr
->num_values
> 1)
710 strncpy(pclass
->job_sheets
[1], attr
->values
[1].string
.text
,
711 sizeof(pclass
->job_sheets
[1]) - 1);
713 strcpy(pclass
->job_sheets
[1], "none");
715 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
716 IPP_TAG_ZERO
)) != NULL
)
718 FreePrinterUsers(pclass
);
720 pclass
->deny_users
= 0;
721 if (attr
->value_tag
== IPP_TAG_NAME
&&
722 (attr
->num_values
> 1 ||
723 strcmp(attr
->values
[0].string
.text
, "all") != 0))
724 for (i
= 0; i
< attr
->num_values
; i
++)
725 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
727 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
728 IPP_TAG_ZERO
)) != NULL
)
730 FreePrinterUsers(pclass
);
732 pclass
->deny_users
= 1;
733 if (attr
->value_tag
== IPP_TAG_NAME
&&
734 (attr
->num_values
> 1 ||
735 strcmp(attr
->values
[0].string
.text
, "none") != 0))
736 for (i
= 0; i
< attr
->num_values
; i
++)
737 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
739 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
740 IPP_TAG_INTEGER
)) != NULL
)
743 pclass
->quota_period
= attr
->values
[0].integer
;
745 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
746 IPP_TAG_INTEGER
)) != NULL
)
749 pclass
->k_limit
= attr
->values
[0].integer
;
751 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
752 IPP_TAG_INTEGER
)) != NULL
)
755 pclass
->page_limit
= attr
->values
[0].integer
;
758 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
761 * Clear the printer array as needed...
764 if (pclass
->num_printers
> 0)
766 free(pclass
->printers
);
767 pclass
->num_printers
= 0;
771 * Add each printer or class that is listed...
774 for (i
= 0; i
< attr
->num_values
; i
++)
777 * Search for the printer or class URI...
780 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
783 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
789 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
790 send_ipp_error(con
, IPP_NOT_FOUND
);
795 * Add it to the class...
798 if (dtype
== CUPS_PRINTER_CLASS
)
800 AddPrinterToClass(pclass
, FindClass(dest
));
802 LogMessage(L_DEBUG
, "add_class: Added class \"%s\" to class \"%s\"...",
807 AddPrinterToClass(pclass
, FindPrinter(dest
));
809 LogMessage(L_DEBUG
, "add_class: Added printer \"%s\" to class \"%s\"...",
816 * Update the printer class attributes and return...
819 SetPrinterAttrs(pclass
);
824 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
827 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
830 con
->response
->request
.status
.status_code
= IPP_OK
;
835 * 'add_file()' - Add a file to a job.
838 static int /* O - 0 on success, -1 on error */
839 add_file(client_t
*con
, /* I - Connection to client */
840 job_t
*job
, /* I - Job to add to */
841 mime_type_t
*filetype
) /* I - Type of file */
843 mime_type_t
**filetypes
; /* New filetypes array... */
846 LogMessage(L_DEBUG2
, "add_file(%p[%d], %d, %s/%s)\n", con
, con
->http
.fd
,
847 job
->id
, filetype
->super
, filetype
->type
);
850 * Add the file to the job...
853 if (job
->num_files
== 0)
854 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
856 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
857 (job
->num_files
+ 1) *
858 sizeof(mime_type_t
));
860 if (filetypes
== NULL
)
862 CancelJob(job
->id
, 1);
863 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
864 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
868 job
->filetypes
= filetypes
;
869 job
->filetypes
[job
->num_files
] = filetype
;
878 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
879 * upon the job and printer state...
883 add_job_state_reasons(client_t
*con
, /* I - Client connection */
884 job_t
*job
) /* I - Job info */
886 printer_t
*dest
; /* Destination printer */
889 LogMessage(L_DEBUG2
, "add_job_state_reasons(%p[%d], %d)\n", con
, con
->http
.fd
,
892 switch (job
->state
->values
[0].integer
)
894 case IPP_JOB_PENDING
:
895 if (job
->dtype
& CUPS_PRINTER_CLASS
)
896 dest
= FindClass(job
->dest
);
898 dest
= FindPrinter(job
->dest
);
900 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
901 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
902 "job-state-reasons", NULL
, "printer-stopped");
904 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
905 "job-state-reasons", NULL
, "none");
909 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
910 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
911 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
912 "job-state-reasons", NULL
, "job-hold-until-specified");
914 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
915 "job-state-reasons", NULL
, "job-incoming");
918 case IPP_JOB_PROCESSING
:
919 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
920 "job-state-reasons", NULL
, "job-printing");
923 case IPP_JOB_STOPPED
:
924 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
925 "job-state-reasons", NULL
, "job-stopped");
928 case IPP_JOB_CANCELLED
:
929 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
930 "job-state-reasons", NULL
, "job-canceled-by-user");
933 case IPP_JOB_ABORTED
:
934 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
935 "job-state-reasons", NULL
, "aborted-by-system");
938 case IPP_JOB_COMPLETED
:
939 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
940 "job-state-reasons", NULL
, "job-completed-successfully");
947 * 'add_printer()' - Add a printer to the system.
951 add_printer(client_t
*con
, /* I - Client connection */
952 ipp_attribute_t
*uri
) /* I - URI of printer */
954 int i
; /* Looping var */
955 char method
[HTTP_MAX_URI
],
956 /* Method portion of URI */
957 username
[HTTP_MAX_URI
],
958 /* Username portion of URI */
960 /* Host portion of URI */
961 resource
[HTTP_MAX_URI
];
962 /* Resource portion of URI */
963 int port
; /* Port portion of URI */
964 printer_t
*printer
; /* Printer/class */
965 ipp_attribute_t
*attr
; /* Printer attribute */
967 gzFile fp
; /* Script/PPD file */
969 FILE *fp
; /* Script/PPD file */
970 #endif /* HAVE_LIBZ */
971 char line
[1024]; /* Line from file... */
972 char srcfile
[1024], /* Source Script/PPD file */
973 dstfile
[1024]; /* Destination Script/PPD file */
974 int modify
; /* Non-zero if we are modifying */
977 LogMessage(L_DEBUG2
, "add_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
978 uri
->values
[0].string
.text
);
981 * Was this operation called from the correct URI?
984 if (strncmp(con
->uri
, "/admin/", 7) != 0)
986 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
988 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
993 * Do we have a valid URI?
996 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
998 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
1001 * No, return an error...
1004 send_ipp_error(con
, IPP_BAD_REQUEST
);
1009 * See if the printer already exists; if not, create a new printer...
1012 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
1015 * Printer doesn't exist; see if we have a class of the same name...
1018 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1019 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1022 * Yes, return an error...
1025 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1030 * No, add the printer...
1033 printer
= AddPrinter(resource
+ 10);
1036 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1039 * Rename the implicit printer to "AnyPrinter" or delete it...
1042 if (ImplicitAnyClasses
)
1044 snprintf(printer
->name
, sizeof(printer
->name
), "Any%s", resource
+ 10);
1048 DeletePrinter(printer
);
1051 * Add the printer as a new local printer...
1054 printer
= AddPrinter(resource
+ 10);
1057 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1060 * Rename the remote printer to "Printer@server"...
1063 DeletePrinterFilters(printer
);
1064 snprintf(printer
->name
, sizeof(printer
->name
), "%s@%s", resource
+ 10,
1066 SetPrinterAttrs(printer
);
1070 * Add the printer as a new local printer...
1073 printer
= AddPrinter(resource
+ 10);
1080 * Look for attributes and copy them over as needed...
1083 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1085 strncpy(printer
->location
, attr
->values
[0].string
.text
, sizeof(printer
->location
) - 1);
1086 printer
->location
[sizeof(printer
->location
) - 1] = '\0';
1089 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1091 strncpy(printer
->info
, attr
->values
[0].string
.text
, sizeof(printer
->info
) - 1);
1092 printer
->info
[sizeof(printer
->info
) - 1] = '\0';
1095 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1097 ipp_attribute_t
*device
; /* Current device */
1098 int methodlen
; /* Length of method string */
1102 * Do we have a valid device URI?
1105 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1107 methodlen
= strlen(method
);
1109 if (strcmp(method
, "file") != 0)
1112 * See if the backend is listed as a device...
1115 for (device
= ippFindAttribute(Devices
, "device-uri", IPP_TAG_URI
);
1117 device
= ippFindNextAttribute(Devices
, "device-uri", IPP_TAG_URI
))
1118 if (strncmp(method
, device
->values
[0].string
.text
, methodlen
) == 0 &&
1119 (device
->values
[0].string
.text
[methodlen
] == ':' ||
1120 device
->values
[0].string
.text
[methodlen
] == '\0'))
1126 * Could not find device in list!
1129 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1130 attr
->values
[0].string
.text
);
1131 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1136 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1137 printer
->name
, attr
->values
[0].string
.text
, printer
->device_uri
);
1139 strncpy(printer
->device_uri
, attr
->values
[0].string
.text
,
1140 sizeof(printer
->device_uri
) - 1);
1141 printer
->device_uri
[sizeof(printer
->device_uri
) - 1] = '\0';
1144 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1146 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1147 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1149 printer
->accepting
= attr
->values
[0].boolean
;
1151 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1153 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1154 attr
->values
[0].integer
, printer
->state
);
1156 if (printer
->state
== IPP_PRINTER_STOPPED
&&
1157 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
1158 printer
->state
= IPP_PRINTER_IDLE
;
1159 else if (printer
->state
!= IPP_PRINTER_STOPPED
&&
1160 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1162 if (printer
->state
== IPP_PRINTER_PROCESSING
)
1163 StopJob(((job_t
*)printer
->job
)->id
);
1165 printer
->state
= IPP_PRINTER_STOPPED
;
1168 printer
->browse_time
= 0;
1170 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1172 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
1173 sizeof(printer
->state_message
) - 1);
1174 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
1176 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1179 strncpy(printer
->job_sheets
[0], attr
->values
[0].string
.text
,
1180 sizeof(printer
->job_sheets
[0]) - 1);
1181 if (attr
->num_values
> 1)
1182 strncpy(printer
->job_sheets
[1], attr
->values
[1].string
.text
,
1183 sizeof(printer
->job_sheets
[1]) - 1);
1185 strcpy(printer
->job_sheets
[1], "none");
1187 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1188 IPP_TAG_ZERO
)) != NULL
)
1190 FreePrinterUsers(printer
);
1192 printer
->deny_users
= 0;
1193 if (attr
->value_tag
== IPP_TAG_NAME
)
1194 for (i
= 0; i
< attr
->num_values
; i
++)
1195 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1197 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1198 IPP_TAG_ZERO
)) != NULL
)
1200 FreePrinterUsers(printer
);
1202 printer
->deny_users
= 1;
1203 if (attr
->value_tag
== IPP_TAG_NAME
)
1204 for (i
= 0; i
< attr
->num_values
; i
++)
1205 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1207 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1208 IPP_TAG_INTEGER
)) != NULL
)
1210 FreeQuotas(printer
);
1211 printer
->quota_period
= attr
->values
[0].integer
;
1213 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1214 IPP_TAG_INTEGER
)) != NULL
)
1216 FreeQuotas(printer
);
1217 printer
->k_limit
= attr
->values
[0].integer
;
1219 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1220 IPP_TAG_INTEGER
)) != NULL
)
1222 FreeQuotas(printer
);
1223 printer
->page_limit
= attr
->values
[0].integer
;
1227 * See if we have all required attributes...
1230 if (printer
->device_uri
[0] == '\0')
1231 strcpy(printer
->device_uri
, "file:/dev/null");
1234 * See if we have an interface script or PPD file attached to the request...
1237 if (con
->filename
[0])
1239 strncpy(srcfile
, con
->filename
, sizeof(srcfile
) - 1);
1240 srcfile
[sizeof(srcfile
) - 1] = '\0';
1242 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1244 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1245 strcpy(srcfile
, "raw");
1247 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1248 attr
->values
[0].string
.text
);
1253 LogMessage(L_DEBUG
, "add_printer: srcfile = \"%s\"", srcfile
);
1255 if (strcmp(srcfile
, "raw") == 0)
1258 * Raw driver, remove any existing PPD or interface script files.
1261 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1265 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1270 else if (srcfile
[0] && (fp
= gzopen(srcfile
, "rb")) != NULL
)
1272 else if (srcfile
[0] && (fp
= fopen(srcfile
, "rb")) != NULL
)
1273 #endif /* HAVE_LIBZ */
1276 * Yes; get the first line from it...
1281 gzgets(fp
, line
, sizeof(line
));
1284 fgets(line
, sizeof(line
), fp
);
1286 #endif /* HAVE_LIBZ */
1289 * Then see what kind of file it is...
1292 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1295 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1298 * The new file is a PPD file, so remove any old interface script
1299 * that might be lying around...
1307 * This must be an interface script, so move the file over to the
1308 * interfaces directory and make it executable...
1311 if (copy_file(srcfile
, dstfile
))
1313 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1314 srcfile
, dstfile
, strerror(errno
));
1315 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1320 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1321 chmod(dstfile
, 0755);
1325 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1328 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1331 * The new file is a PPD file, so move the file over to the
1332 * ppd directory and make it readable by all...
1335 if (copy_file(srcfile
, dstfile
))
1337 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1338 srcfile
, dstfile
, strerror(errno
));
1339 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1344 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1345 chmod(dstfile
, 0644);
1351 * This must be an interface script, so remove any old PPD file that
1352 * may be lying around...
1360 * Make this printer the default if there is none...
1363 if (DefaultPrinter
== NULL
)
1364 DefaultPrinter
= printer
;
1367 * Update the printer attributes and return...
1370 SetPrinterAttrs(printer
);
1373 if (printer
->job
!= NULL
)
1376 * Stop the current job and then restart it below...
1379 StopJob(((job_t
*)printer
->job
)->id
);
1385 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1388 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1391 con
->response
->request
.status
.status_code
= IPP_OK
;
1396 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1397 * based upon the printer state...
1401 add_printer_state_reasons(client_t
*con
, /* I - Client connection */
1402 printer_t
*p
) /* I - Printer info */
1404 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%p[%d], %p[%s])\n",
1405 con
, con
->http
.fd
, p
, p
->name
);
1409 case IPP_PRINTER_STOPPED
:
1410 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1411 "printer-state-reasons", NULL
, "paused");
1415 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1416 "printer-state-reasons", NULL
, "none");
1423 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1424 * the specified printer or class.
1428 add_queued_job_count(client_t
*con
, /* I - Client connection */
1429 printer_t
*p
) /* I - Printer or class */
1431 int count
; /* Number of jobs on destination */
1434 LogMessage(L_DEBUG2
, "add_queued_job_count(%p[%d], %p[%s])\n",
1435 con
, con
->http
.fd
, p
, p
->name
);
1437 count
= GetPrinterJobCount(p
->name
);
1439 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1440 "queued-job-count", count
);
1445 * 'cancel_all_jobs()' - Cancel all print jobs.
1449 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1450 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1452 const char *dest
; /* Destination */
1453 cups_ptype_t dtype
; /* Destination type */
1454 char method
[HTTP_MAX_URI
],
1455 /* Method portion of URI */
1456 username
[HTTP_MAX_URI
],
1457 /* Username portion of URI */
1459 /* Host portion of URI */
1460 resource
[HTTP_MAX_URI
];
1461 /* Resource portion of URI */
1462 int port
; /* Port portion of URI */
1463 printer_t
*printer
; /* Current printer */
1466 LogMessage(L_DEBUG2
, "cancel_all_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
1467 uri
->values
[0].string
.text
);
1470 * Was this operation called from the correct URI?
1473 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1475 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
1477 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1482 * See if we have a printer URI...
1485 if (strcmp(uri
->name
, "printer-uri") != 0)
1487 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
1488 uri
->name
, uri
->values
[0].string
.text
);
1489 send_ipp_error(con
, IPP_BAD_REQUEST
);
1494 * And if the destination is valid...
1497 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
,
1500 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
1506 if (strcmp(resource
, "/printers/") != 0)
1508 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
1509 send_ipp_error(con
, IPP_NOT_FOUND
);
1514 * Cancel all jobs on all printers...
1517 for (printer
= Printers
; printer
; printer
= printer
->next
)
1519 CancelJobs(printer
->name
);
1520 LogMessage(L_INFO
, "All jobs on \'%s\' were cancelled by \'%s\'.",
1521 printer
->name
, con
->username
);
1527 * Cancel all of the jobs on the named printer...
1531 LogMessage(L_INFO
, "All jobs on \'%s\' were cancelled by \'%s\'.", dest
,
1535 con
->response
->request
.status
.status_code
= IPP_OK
;
1540 * 'cancel_job()' - Cancel a print job.
1544 cancel_job(client_t
*con
, /* I - Client connection */
1545 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1547 ipp_attribute_t
*attr
; /* Current attribute */
1548 int jobid
; /* Job ID */
1549 char method
[HTTP_MAX_URI
],
1550 /* Method portion of URI */
1551 username
[HTTP_MAX_URI
],
1552 /* Username portion of URI */
1554 /* Host portion of URI */
1555 resource
[HTTP_MAX_URI
];
1556 /* Resource portion of URI */
1557 int port
; /* Port portion of URI */
1558 job_t
*job
; /* Job information */
1559 const char *dest
; /* Destination */
1560 cups_ptype_t dtype
; /* Destination type (printer or class) */
1561 printer_t
*printer
; /* Printer data */
1564 LogMessage(L_DEBUG2
, "cancel_job(%p[%d], %s)\n", con
, con
->http
.fd
,
1565 uri
->values
[0].string
.text
);
1568 * Verify that the POST operation was done to a valid URI.
1571 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
1572 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
1573 strncmp(con
->uri
, "/printers/", 10) != 0)
1575 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
1577 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1582 * See if we have a job URI or a printer URI...
1585 if (strcmp(uri
->name
, "printer-uri") == 0)
1588 * Got a printer URI; see if we also have a job-id attribute...
1591 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1593 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
1594 send_ipp_error(con
, IPP_BAD_REQUEST
);
1598 if ((jobid
= attr
->values
[0].integer
) == 0)
1601 * Find the current job on the specified printer...
1604 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1606 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
1612 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
1613 send_ipp_error(con
, IPP_NOT_FOUND
);
1617 if (dtype
& CUPS_PRINTER_CLASS
)
1618 printer
= FindClass(dest
);
1620 printer
= FindPrinter(dest
);
1623 * See if the printer is currently printing a job...
1627 jobid
= ((job_t
*)printer
->job
)->id
;
1631 * No, see if there are any pending jobs...
1634 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
1635 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
1636 strcasecmp(job
->dest
, dest
) == 0)
1643 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
1644 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1653 * Got a job URI; parse it to get the job ID...
1656 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1658 if (strncmp(resource
, "/jobs/", 6) != 0)
1664 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
1665 uri
->values
[0].string
.text
);
1666 send_ipp_error(con
, IPP_BAD_REQUEST
);
1670 jobid
= atoi(resource
+ 6);
1674 * See if the job exists...
1677 if ((job
= FindJob(jobid
)) == NULL
)
1680 * Nope - return a "not found" error...
1683 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
1684 send_ipp_error(con
, IPP_NOT_FOUND
);
1689 * See if the job is owned by the requesting user...
1692 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
1694 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
1695 username
, jobid
, job
->username
);
1696 send_ipp_error(con
, IPP_FORBIDDEN
);
1701 * See if the job is already completed, cancelled, or aborted; if so,
1702 * we can't cancel...
1705 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
1707 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
1709 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
1710 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
1712 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1717 * Cancel the job and return...
1720 CancelJob(jobid
, 0);
1723 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
1725 con
->response
->request
.status
.status_code
= IPP_OK
;
1730 * 'check_quotas()' - Check quotas for a printer and user.
1733 static int /* O - 1 if OK, 0 if not */
1734 check_quotas(client_t
*con
, /* I - Client connection */
1735 printer_t
*p
) /* I - Printer or class */
1737 int i
; /* Looping var */
1738 ipp_attribute_t
*attr
; /* Current attribute */
1739 char username
[33]; /* Username */
1740 quota_t
*q
; /* Quota data */
1743 LogMessage(L_DEBUG2
, "check_quotas(%p[%d], %p[%s])\n",
1744 con
, con
->http
.fd
, p
, p
->name
);
1750 if (con
== NULL
|| p
== NULL
)
1754 * Figure out who is printing...
1757 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1759 if (con
->username
[0])
1761 strncpy(username
, con
->username
, sizeof(username
) - 1);
1762 username
[sizeof(username
) - 1] = '\0';
1764 else if (attr
!= NULL
)
1766 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
1767 attr
->values
[0].string
.text
);
1769 strncpy(username
, attr
->values
[0].string
.text
, sizeof(username
) - 1);
1770 username
[sizeof(username
) - 1] = '\0';
1773 strcpy(username
, "anonymous");
1776 * Check global active job limits for printers and users...
1779 if (MaxJobsPerPrinter
)
1782 * Check if there are too many pending jobs on this printer...
1785 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
1787 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
1795 * Check if there are too many pending jobs for this user...
1798 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
1800 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
1806 * Check against users...
1809 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
1814 for (i
= 0; i
< p
->num_users
; i
++)
1815 if (strcasecmp(username
, p
->users
[i
]) == 0)
1818 if ((i
< p
->num_users
) == p
->deny_users
)
1820 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
1830 if (p
->k_limit
|| p
->page_limit
)
1832 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
1834 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
1839 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
1840 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
1842 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
1849 * If we have gotten this far, we're done!
1857 * 'copy_attribute()' - Copy a single attribute.
1861 copy_attribute(ipp_t
*to
, /* O - Destination request/response */
1862 ipp_attribute_t
*attr
, /* I - Attribute to copy */
1863 int quickcopy
)/* I - Do a quick copy? */
1865 int i
; /* Looping var */
1866 ipp_attribute_t
*toattr
; /* Destination attribute */
1869 LogMessage(L_DEBUG2
, "copy_attribute(%p, %p[%s,%x,%x])\n", to
, attr
,
1870 attr
->name
? attr
->name
: "(null)", attr
->group_tag
,
1873 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
1876 ippAddSeparator(to
);
1879 case IPP_TAG_INTEGER
:
1881 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
1882 attr
->name
, attr
->num_values
, NULL
);
1884 for (i
= 0; i
< attr
->num_values
; i
++)
1885 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
1888 case IPP_TAG_BOOLEAN
:
1889 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
1890 attr
->num_values
, NULL
);
1892 for (i
= 0; i
< attr
->num_values
; i
++)
1893 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
1896 case IPP_TAG_STRING
:
1899 case IPP_TAG_KEYWORD
:
1901 case IPP_TAG_URISCHEME
:
1902 case IPP_TAG_CHARSET
:
1903 case IPP_TAG_LANGUAGE
:
1904 case IPP_TAG_MIMETYPE
:
1905 toattr
= ippAddStrings(to
, attr
->group_tag
,
1906 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
1907 attr
->name
, attr
->num_values
, NULL
, NULL
);
1911 for (i
= 0; i
< attr
->num_values
; i
++)
1912 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
1916 for (i
= 0; i
< attr
->num_values
; i
++)
1917 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
1922 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
1923 attr
->values
[0].date
);
1926 case IPP_TAG_RESOLUTION
:
1927 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
1928 attr
->num_values
, IPP_RES_PER_INCH
,
1931 for (i
= 0; i
< attr
->num_values
; i
++)
1933 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
1934 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
1935 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
1939 case IPP_TAG_RANGE
:
1940 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
1941 attr
->num_values
, NULL
, NULL
);
1943 for (i
= 0; i
< attr
->num_values
; i
++)
1945 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
1946 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
1950 case IPP_TAG_TEXTLANG
:
1951 case IPP_TAG_NAMELANG
:
1952 toattr
= ippAddStrings(to
, attr
->group_tag
,
1953 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
1954 attr
->name
, attr
->num_values
, NULL
, NULL
);
1958 for (i
= 0; i
< attr
->num_values
; i
++)
1960 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
1961 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
1966 for (i
= 0; i
< attr
->num_values
; i
++)
1969 toattr
->values
[i
].string
.charset
=
1970 strdup(attr
->values
[i
].string
.charset
);
1972 toattr
->values
[i
].string
.charset
=
1973 toattr
->values
[0].string
.charset
;
1975 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
1981 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
1982 attr
->name
, attr
->num_values
, NULL
);
1984 for (i
= 0; i
< attr
->num_values
; i
++)
1986 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
1988 if (toattr
->values
[i
].unknown
.length
> 0)
1990 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
1991 toattr
->values
[i
].unknown
.length
= 0;
1993 memcpy(toattr
->values
[i
].unknown
.data
,
1994 attr
->values
[i
].unknown
.data
,
1995 toattr
->values
[i
].unknown
.length
);
1998 break; /* anti-compiler-warning-code */
2004 * 'copy_attrs()' - Copy attributes from one request to another.
2008 copy_attrs(ipp_t
*to
, /* I - Destination request */
2009 ipp_t
*from
, /* I - Source request */
2010 ipp_attribute_t
*req
, /* I - Requested attributes */
2011 ipp_tag_t group
) /* I - Group to copy */
2013 int i
; /* Looping var */
2014 ipp_attribute_t
*fromattr
; /* Source attribute */
2017 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2019 if (to
== NULL
|| from
== NULL
)
2022 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2023 req
= NULL
; /* "all" means no filter... */
2025 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2028 * Filter attributes as needed...
2031 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2032 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2035 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2037 for (i
= 0; i
< req
->num_values
; i
++)
2038 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2041 if (i
== req
->num_values
)
2045 copy_attribute(to
, fromattr
, IPP_TAG_COPY
);
2051 * 'create_job()' - Print a file to a printer or class.
2055 create_job(client_t
*con
, /* I - Client connection */
2056 ipp_attribute_t
*uri
) /* I - Printer URI */
2058 ipp_attribute_t
*attr
; /* Current attribute */
2059 const char *dest
; /* Destination */
2060 cups_ptype_t dtype
; /* Destination type (printer or class) */
2061 int priority
; /* Job priority */
2062 char *title
; /* Job name/title */
2063 job_t
*job
; /* Current job */
2064 char job_uri
[HTTP_MAX_URI
],
2066 printer_uri
[HTTP_MAX_URI
],
2068 method
[HTTP_MAX_URI
],
2069 /* Method portion of URI */
2070 username
[HTTP_MAX_URI
],
2071 /* Username portion of URI */
2073 /* Host portion of URI */
2074 resource
[HTTP_MAX_URI
];
2075 /* Resource portion of URI */
2076 int port
; /* Port portion of URI */
2077 printer_t
*printer
; /* Printer data */
2078 int kbytes
; /* Size of print file */
2081 LogMessage(L_DEBUG2
, "create_job(%p[%d], %s)\n", con
, con
->http
.fd
,
2082 uri
->values
[0].string
.text
);
2085 * Verify that the POST operation was done to a valid URI.
2088 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2089 strncmp(con
->uri
, "/printers/", 10) != 0)
2091 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
2093 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2098 * Is the destination valid?
2101 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2103 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2109 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
2110 send_ipp_error(con
, IPP_NOT_FOUND
);
2115 * See if the printer is accepting jobs...
2118 if (dtype
== CUPS_PRINTER_CLASS
)
2120 printer
= FindClass(dest
);
2121 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
2122 ServerName
, ntohs(con
->http
.hostaddr
.sin_port
), dest
);
2126 printer
= FindPrinter(dest
);
2128 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
2129 ServerName
, ntohs(con
->http
.hostaddr
.sin_port
), dest
);
2132 if (!printer
->accepting
)
2134 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
2136 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
2141 * Make sure we aren't over our limit...
2144 if (NumJobs
>= MaxJobs
&& MaxJobs
)
2147 if (NumJobs
>= MaxJobs
&& MaxJobs
)
2149 LogMessage(L_INFO
, "create_job: too many jobs.");
2150 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2154 if (!check_quotas(con
, printer
))
2156 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2161 * Create the job and set things up...
2164 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
2165 priority
= attr
->values
[0].integer
;
2167 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
2170 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
2171 title
= attr
->values
[0].string
.text
;
2173 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
2174 title
= "Untitled");
2176 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
2178 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
2180 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
2185 job
->attrs
= con
->request
;
2186 con
->request
= NULL
;
2188 strncpy(job
->title
, title
, sizeof(job
->title
) - 1);
2190 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
2192 if (con
->username
[0])
2194 strncpy(job
->username
, con
->username
, sizeof(job
->username
) - 1);
2195 job
->username
[sizeof(job
->username
) - 1] = '\0';
2197 else if (attr
!= NULL
)
2199 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
2200 attr
->values
[0].string
.text
);
2202 strncpy(job
->username
, attr
->values
[0].string
.text
,
2203 sizeof(job
->username
) - 1);
2204 job
->username
[sizeof(job
->username
) - 1] = '\0';
2207 strcpy(job
->username
, "anonymous");
2210 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
2211 NULL
, job
->username
);
2214 attr
->group_tag
= IPP_TAG_JOB
;
2216 attr
->name
= strdup("job-originating-user-name");
2219 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
2220 "job-originating-host-name", NULL
, con
->http
.hostname
);
2221 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
2223 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2224 "time-at-processing", 0);
2225 attr
->value_tag
= IPP_TAG_NOVALUE
;
2226 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2227 "time-at-completed", 0);
2228 attr
->value_tag
= IPP_TAG_NOVALUE
;
2231 * Add remaining job attributes...
2234 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
2235 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
2236 "job-state", IPP_JOB_STOPPED
);
2237 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2238 "job-media-sheets-completed", 0);
2239 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
2241 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
2244 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2245 attr
->values
[0].integer
= 0;
2247 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2250 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
2251 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
2253 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
2254 "job-hold-until", NULL
, "no-hold");
2255 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
2256 !(printer
->type
& CUPS_PRINTER_REMOTE
))
2259 * Hold job until specified time...
2262 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
2265 job
->hold_until
= time(NULL
) + 60;
2267 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
2269 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) || Classification
[0])
2272 * Add job sheets options...
2275 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
2277 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
2279 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
2280 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
2283 job
->job_sheets
= attr
;
2286 * Enforce classification level if set...
2289 if (Classification
[0])
2291 if (ClassifyOverride
)
2293 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
2294 (attr
->num_values
== 1 ||
2295 strcmp(attr
->values
[1].string
.text
, "none") == 0))
2298 * Force the leading banner to have the classification on it...
2301 free(attr
->values
[0].string
.text
);
2302 attr
->values
[0].string
.text
= strdup(Classification
);
2304 else if (attr
->num_values
== 2 &&
2305 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
2306 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
2307 strcmp(attr
->values
[1].string
.text
, "none") != 0)
2310 * Can't put two different security markings on the same document!
2313 free(attr
->values
[1].string
.text
);
2314 attr
->values
[1].string
.text
= strdup(attr
->values
[0].string
.text
);
2317 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
2318 (attr
->num_values
== 1 ||
2319 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
2322 * Force the leading banner to have the classification on it...
2325 free(attr
->values
[0].string
.text
);
2326 attr
->values
[0].string
.text
= strdup(Classification
);
2331 * See if we need to add the starting sheet...
2334 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
2336 UpdateQuota(printer
, job
->username
, 0, kbytes
);
2340 * Save and log the job...
2345 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
2346 job
->dest
, job
->username
);
2349 * Fill in the response info...
2352 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
2353 ntohs(con
->http
.hostaddr
.sin_port
), job
->id
);
2354 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
2356 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
2358 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
2359 job
->state
->values
[0].integer
);
2361 con
->response
->request
.status
.status_code
= IPP_OK
;
2366 * 'copy_banner()' - Copy a banner file to the requests directory for the
2370 static int /* O - Size of banner file in kbytes */
2371 copy_banner(client_t
*con
, /* I - Client connection */
2372 job_t
*job
, /* I - Job information */
2373 const char *name
) /* I - Name of banner */
2375 int i
; /* Looping var */
2376 int kbytes
; /* Size of banner file in kbytes */
2377 char filename
[1024]; /* Job filename */
2378 banner_t
*banner
; /* Pointer to banner */
2379 FILE *in
; /* Input file */
2380 FILE *out
; /* Output file */
2381 int ch
; /* Character from file */
2382 char attrname
[255], /* Name of attribute */
2383 *s
; /* Pointer into name */
2384 ipp_attribute_t
*attr
; /* Attribute */
2387 LogMessage(L_DEBUG2
, "copy_banner(%p[%d], %p[%d], %s)",
2388 con
, con
->http
.fd
, job
, job
->id
, name
? name
: "(null)");
2391 * Find the banner; return if not found or "none"...
2395 strcmp(name
, "none") == 0 ||
2396 (banner
= FindBanner(name
)) == NULL
)
2400 * Open the banner and job files...
2403 if (add_file(con
, job
, banner
->filetype
))
2406 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2408 if ((out
= fopen(filename
, "w")) == NULL
)
2410 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2411 filename
, strerror(errno
));
2416 fchmod(fileno(out
), 0640);
2417 fchown(fileno(out
), User
, Group
);
2422 * Try the localized banner file under the subdirectory...
2425 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2426 con
->language
->language
, name
);
2428 if (access(filename
, 0) && con
->language
->language
[2])
2431 * Wasn't able to find "ll_CC" locale file; try the non-national
2432 * localization banner directory.
2435 attrname
[0] = con
->language
->language
[0];
2436 attrname
[1] = con
->language
->language
[1];
2439 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2443 if (access(filename
, 0))
2446 * Use the non-localized banner file.
2449 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2455 * Use the non-localized banner file.
2458 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2461 if ((in
= fopen(filename
, "r")) == NULL
)
2465 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2466 filename
, strerror(errno
));
2472 * Parse the file to the end...
2475 while ((ch
= getc(in
)) != EOF
)
2479 * Get an attribute name...
2482 for (s
= attrname
; (ch
= getc(in
)) != EOF
;)
2483 if (ch
== '}' || isspace(ch
))
2485 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2488 if (isspace(ch
) && s
== attrname
)
2491 * Ignore { followed by whitespace...
2502 * See if it is defined...
2505 if (strcmp(attrname
, "printer-name") == 0)
2507 fputs(job
->dest
, out
);
2510 else if ((attr
= ippFindAttribute(job
->attrs
, attrname
, IPP_TAG_ZERO
)) == NULL
)
2511 continue; /* Nope */
2514 * Output value(s)...
2517 for (i
= 0; i
< attr
->num_values
; i
++)
2522 switch (attr
->value_tag
)
2524 case IPP_TAG_INTEGER
:
2526 if (strncmp(attrname
, "time-at-", 8) == 0)
2527 fputs(GetDateTime(attr
->values
[i
].integer
), out
);
2529 fprintf(out
, "%d", attr
->values
[i
].integer
);
2532 case IPP_TAG_BOOLEAN
:
2533 fprintf(out
, "%d", attr
->values
[i
].boolean
);
2536 case IPP_TAG_NOVALUE
:
2537 fputs("novalue", out
);
2540 case IPP_TAG_RANGE
:
2541 fprintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2542 attr
->values
[i
].range
.upper
);
2545 case IPP_TAG_RESOLUTION
:
2546 fprintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2547 attr
->values
[i
].resolution
.yres
,
2548 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2553 case IPP_TAG_STRING
:
2556 case IPP_TAG_KEYWORD
:
2557 case IPP_TAG_CHARSET
:
2558 case IPP_TAG_LANGUAGE
:
2559 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2562 * Need to quote strings for PS banners...
2567 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2569 if (*p
== '(' || *p
== ')' || *p
== '\\')
2574 else if (*p
< 32 || *p
> 126)
2575 fprintf(out
, "\\%03o", *p
);
2581 fputs(attr
->values
[i
].string
.text
, out
);
2585 break; /* anti-compiler-warning-code */
2589 else if (ch
== '\\') /* Quoted char */
2590 putc(getc(in
), out
);
2596 kbytes
= (ftell(out
) + 1023) / 1024;
2598 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2599 attr
->values
[0].integer
+= kbytes
;
2608 * 'copy_file()' - Copy a PPD file or interface script...
2611 static int /* O - 0 = success, -1 = error */
2612 copy_file(const char *from
, /* I - Source file */
2613 const char *to
) /* I - Destination file */
2616 gzFile src
; /* Source file */
2618 int src
; /* Source file */
2619 #endif /* HAVE_LIBZ */
2620 int dst
, /* Destination file */
2621 bytes
; /* Bytes to read/write */
2622 char buffer
[8192]; /* Copy buffer */
2625 LogMessage(L_DEBUG2
, "copy_file(\"%s\", \"%s\")\n", from
, to
);
2628 if ((src
= gzopen(from
, "rb")) == NULL
)
2631 if ((src
= open(from
, O_RDONLY
)) < 0)
2633 #endif /* HAVE_LIBZ */
2635 if ((dst
= open(to
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644)) < 0)
2641 #endif /* HAVE_LIBZ */
2646 while ((bytes
= gzread(src
, buffer
, sizeof(buffer
))) > 0)
2648 while ((bytes
= read(src
, buffer
, sizeof(buffer
))) > 0)
2649 #endif /* HAVE_LIBZ */
2650 if (write(dst
, buffer
, bytes
) < bytes
)
2656 #endif /* HAVE_LIBZ */
2665 #endif /* HAVE_LIBZ */
2673 * 'delete_printer()' - Remove a printer or class from the system.
2677 delete_printer(client_t
*con
, /* I - Client connection */
2678 ipp_attribute_t
*uri
) /* I - URI of printer or class */
2680 const char *dest
; /* Destination */
2681 cups_ptype_t dtype
; /* Destination type (printer or class) */
2682 char method
[HTTP_MAX_URI
],
2683 /* Method portion of URI */
2684 username
[HTTP_MAX_URI
],
2685 /* Username portion of URI */
2687 /* Host portion of URI */
2688 resource
[HTTP_MAX_URI
];
2689 /* Resource portion of URI */
2690 int port
; /* Port portion of URI */
2691 printer_t
*printer
; /* Printer/class */
2692 char filename
[1024]; /* Script/PPD filename */
2695 LogMessage(L_DEBUG2
, "delete_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
2696 uri
->values
[0].string
.text
);
2699 * Was this operation called from the correct URI?
2702 if (strncmp(con
->uri
, "/admin/", 7) != 0)
2704 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
2706 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2711 * Do we have a valid URI?
2714 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2716 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2722 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
2723 send_ipp_error(con
, IPP_NOT_FOUND
);
2728 * Find the printer or class and delete it...
2731 if (dtype
== CUPS_PRINTER_CLASS
)
2732 printer
= FindClass(dest
);
2734 printer
= FindPrinter(dest
);
2737 * Remove old jobs...
2743 * Remove any old PPD or script files...
2746 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
2749 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
2752 if (dtype
== CUPS_PRINTER_CLASS
)
2754 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
2757 DeletePrinter(printer
);
2762 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
2765 DeletePrinter(printer
);
2770 * Return with no errors...
2773 con
->response
->request
.status
.status_code
= IPP_OK
;
2778 * 'get_default()' - Get the default destination.
2782 get_default(client_t
*con
) /* I - Client connection */
2784 LogMessage(L_DEBUG2
, "get_default(%p[%d])\n", con
, con
->http
.fd
);
2786 if (DefaultPrinter
!= NULL
)
2788 copy_attrs(con
->response
, DefaultPrinter
->attrs
,
2789 ippFindAttribute(con
->request
, "requested-attributes",
2790 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
2792 con
->response
->request
.status
.status_code
= IPP_OK
;
2795 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
2800 * 'get_devices()' - Get the list of available devices on the local system.
2804 get_devices(client_t
*con
) /* I - Client connection */
2806 LogMessage(L_DEBUG2
, "get_devices(%p[%d])\n", con
, con
->http
.fd
);
2809 * Copy the device attributes to the response using the requested-attributes
2810 * attribute that may be provided by the client.
2813 copy_attrs(con
->response
, Devices
,
2814 ippFindAttribute(con
->request
, "requested-attributes",
2815 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
2817 con
->response
->request
.status
.status_code
= IPP_OK
;
2822 * 'get_jobs()' - Get a list of jobs for the specified printer.
2826 get_jobs(client_t
*con
, /* I - Client connection */
2827 ipp_attribute_t
*uri
) /* I - Printer URI */
2829 ipp_attribute_t
*attr
, /* Current attribute */
2830 *requested
; /* Requested attributes */
2831 const char *dest
; /* Destination */
2832 cups_ptype_t dtype
; /* Destination type (printer or class) */
2833 char method
[HTTP_MAX_URI
],
2834 /* Method portion of URI */
2835 username
[HTTP_MAX_URI
],
2836 /* Username portion of URI */
2838 /* Host portion of URI */
2839 resource
[HTTP_MAX_URI
];
2840 /* Resource portion of URI */
2841 int port
; /* Port portion of URI */
2842 int completed
; /* Completed jobs? */
2843 int limit
; /* Maximum number of jobs to return */
2844 int count
; /* Number of jobs that match */
2845 job_t
*job
; /* Current job pointer */
2846 char job_uri
[HTTP_MAX_URI
];
2850 LogMessage(L_DEBUG2
, "get_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
2851 uri
->values
[0].string
.text
);
2854 * Is the destination valid?
2857 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2859 if ((strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6) ||
2860 (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10))
2863 dtype
= (cups_ptype_t
)0;
2865 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
2868 dtype
= CUPS_PRINTER_CLASS
;
2870 else if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2876 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
2877 send_ipp_error(con
, IPP_NOT_FOUND
);
2882 * See if the "which-jobs" attribute have been specified; if so, return
2883 * right away if they specify "completed" - we don't keep old job records...
2886 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
2887 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
2893 * See if they want to limit the number of jobs reported...
2896 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
2897 limit
= attr
->values
[0].integer
;
2902 * See if we only want to see jobs for a specific user...
2905 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
2906 attr
->values
[0].boolean
)
2908 if (con
->username
[0])
2910 strncpy(username
, con
->username
, sizeof(username
) - 1);
2911 username
[sizeof(username
) - 1] = '\0';
2913 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
2915 strncpy(username
, attr
->values
[0].string
.text
, sizeof(username
) - 1);
2916 username
[sizeof(username
) - 1] = '\0';
2919 strcpy(username
, "anonymous");
2924 requested
= ippFindAttribute(con
->request
, "requested-attributes",
2928 * OK, build a list of jobs for this printer...
2931 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
2934 * Filter out jobs that don't match...
2937 LogMessage(L_DEBUG2
, "get_jobs: job->id = %d", job
->id
);
2939 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0))
2941 if (job
->dtype
!= dtype
&&
2942 (username
[0] == '\0' || strncmp(resource
, "/jobs", 5) != 0))
2944 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
2947 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
2949 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
2954 LogMessage(L_DEBUG2
, "get_jobs: count = %d", count
);
2957 * Send the requested attributes for each job...
2960 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
2961 ntohs(con
->http
.hostaddr
.sin_port
), job
->id
);
2963 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
2964 "job-more-info", NULL
, job_uri
);
2966 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
2967 "job-uri", NULL
, job_uri
);
2969 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2970 "job-printer-up-time", time(NULL
));
2973 * Copy the job attributes to the response using the requested-attributes
2974 * attribute that may be provided by the client.
2977 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
);
2979 add_job_state_reasons(con
, job
);
2981 ippAddSeparator(con
->response
);
2984 if (requested
!= NULL
)
2985 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
2987 con
->response
->request
.status
.status_code
= IPP_OK
;
2992 * 'get_job_attrs()' - Get job attributes.
2996 get_job_attrs(client_t
*con
, /* I - Client connection */
2997 ipp_attribute_t
*uri
) /* I - Job URI */
2999 ipp_attribute_t
*attr
, /* Current attribute */
3000 *requested
; /* Requested attributes */
3001 int jobid
; /* Job ID */
3002 job_t
*job
; /* Current job */
3003 char method
[HTTP_MAX_URI
],
3004 /* Method portion of URI */
3005 username
[HTTP_MAX_URI
],
3006 /* Username portion of URI */
3008 /* Host portion of URI */
3009 resource
[HTTP_MAX_URI
];
3010 /* Resource portion of URI */
3011 int port
; /* Port portion of URI */
3012 char job_uri
[HTTP_MAX_URI
];
3016 LogMessage(L_DEBUG2
, "get_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
3017 uri
->values
[0].string
.text
);
3020 * See if we have a job URI or a printer URI...
3023 if (strcmp(uri
->name
, "printer-uri") == 0)
3026 * Got a printer URI; see if we also have a job-id attribute...
3029 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3031 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
3032 send_ipp_error(con
, IPP_BAD_REQUEST
);
3036 jobid
= attr
->values
[0].integer
;
3041 * Got a job URI; parse it to get the job ID...
3044 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3046 if (strncmp(resource
, "/jobs/", 6) != 0)
3052 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
3053 uri
->values
[0].string
.text
);
3054 send_ipp_error(con
, IPP_BAD_REQUEST
);
3058 jobid
= atoi(resource
+ 6);
3062 * See if the job exists...
3065 if ((job
= FindJob(jobid
)) == NULL
)
3068 * Nope - return a "not found" error...
3071 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
3072 send_ipp_error(con
, IPP_NOT_FOUND
);
3077 * Put out the standard attributes...
3080 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
3081 ServerName
, ntohs(con
->http
.hostaddr
.sin_port
),
3084 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3086 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3087 "job-more-info", NULL
, job_uri
);
3089 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3090 "job-uri", NULL
, job_uri
);
3092 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3093 "job-printer-up-time", time(NULL
));
3096 * Copy the job attributes to the response using the requested-attributes
3097 * attribute that may be provided by the client.
3100 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3103 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
);
3105 add_job_state_reasons(con
, job
);
3107 if (requested
!= NULL
)
3108 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
3110 con
->response
->request
.status
.status_code
= IPP_OK
;
3115 * 'get_ppds()' - Get the list of PPD files on the local system.
3119 get_ppds(client_t
*con
) /* I - Client connection */
3121 LogMessage(L_DEBUG2
, "get_ppds(%p[%d])\n", con
, con
->http
.fd
);
3124 * Copy the PPD attributes to the response using the requested-attributes
3125 * attribute that may be provided by the client.
3128 copy_attrs(con
->response
, PPDs
,
3129 ippFindAttribute(con
->request
, "requested-attributes",
3130 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
3132 con
->response
->request
.status
.status_code
= IPP_OK
;
3137 * 'get_printer_attrs()' - Get printer attributes.
3141 get_printer_attrs(client_t
*con
, /* I - Client connection */
3142 ipp_attribute_t
*uri
) /* I - Printer URI */
3144 const char *dest
; /* Destination */
3145 cups_ptype_t dtype
; /* Destination type (printer or class) */
3146 char method
[HTTP_MAX_URI
],
3147 /* Method portion of URI */
3148 username
[HTTP_MAX_URI
],
3149 /* Username portion of URI */
3151 /* Host portion of URI */
3152 resource
[HTTP_MAX_URI
];
3153 /* Resource portion of URI */
3154 int port
; /* Port portion of URI */
3155 printer_t
*printer
; /* Printer/class */
3156 time_t curtime
; /* Current time */
3159 LogMessage(L_DEBUG2
, "get_printer_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
3160 uri
->values
[0].string
.text
);
3163 * Is the destination valid?
3166 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3168 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3174 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
3175 send_ipp_error(con
, IPP_NOT_FOUND
);
3179 if (dtype
== CUPS_PRINTER_CLASS
)
3180 printer
= FindClass(dest
);
3182 printer
= FindPrinter(dest
);
3184 curtime
= time(NULL
);
3187 * Copy the printer attributes to the response using requested-attributes
3188 * and document-format attributes that may be provided by the client.
3191 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
3194 add_printer_state_reasons(con
, printer
);
3196 if (printer
->state_message
[0])
3197 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
3198 "printer-state-message", NULL
, printer
->state_message
);
3200 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
3201 printer
->accepting
);
3203 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
3204 "printer-up-time", curtime
);
3205 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
3206 ippTimeToDate(curtime
));
3208 add_queued_job_count(con
, printer
);
3210 copy_attrs(con
->response
, printer
->attrs
,
3211 ippFindAttribute(con
->request
, "requested-attributes",
3212 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
3214 con
->response
->request
.status
.status_code
= IPP_OK
;
3219 * 'get_printers()' - Get a list of printers or classes.
3223 get_printers(client_t
*con
, /* I - Client connection */
3224 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
3226 ipp_attribute_t
*attr
, /* Current attribute */
3227 *requested
; /* Requested attributes */
3228 int limit
; /* Maximum number of printers to return */
3229 int count
; /* Number of printers that match */
3230 printer_t
*printer
; /* Current printer pointer */
3231 time_t curtime
; /* Current time */
3232 int printer_type
, /* printer-type attribute */
3233 printer_mask
; /* printer-type-mask attribute */
3234 char *location
; /* Location string */
3235 char name
[IPP_MAX_NAME
],
3237 *nameptr
; /* Pointer into name */
3238 printer_t
*iclass
; /* Implicit class */
3241 LogMessage(L_DEBUG2
, "get_printers(%p[%d], %x)\n", con
, con
->http
.fd
, type
);
3244 * See if they want to limit the number of printers reported...
3247 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
3248 limit
= attr
->values
[0].integer
;
3253 * Support filtering...
3256 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
3257 printer_type
= attr
->values
[0].integer
;
3261 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
3262 printer_mask
= attr
->values
[0].integer
;
3266 if ((attr
= ippFindAttribute(con
->request
, "location", IPP_TAG_TEXT
)) != NULL
)
3267 location
= attr
->values
[0].string
.text
;
3271 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3275 * OK, build a list of printers for this printer...
3278 curtime
= time(NULL
);
3280 for (count
= 0, printer
= Printers
;
3281 count
< limit
&& printer
!= NULL
;
3282 printer
= printer
->next
)
3283 if ((printer
->type
& CUPS_PRINTER_CLASS
) == type
&&
3284 (printer
->type
& printer_mask
) == printer_type
&&
3285 (location
== NULL
|| strcasecmp(printer
->location
, location
) == 0))
3288 * If HideImplicitMembers is enabled, see if this printer or class
3289 * is a member of an implicit class...
3292 if (ImplicitClasses
&& HideImplicitMembers
&&
3293 (printer
->type
& CUPS_PRINTER_REMOTE
))
3296 * Make a copy of the printer name...
3298 * Note: name and printer->name are both IPP_MAX_NAME characters
3299 * in size, so strcpy() is safe...
3302 strcpy(name
, printer
->name
);
3304 if ((nameptr
= strchr(name
, '@')) != NULL
)
3307 * Strip trailing @server...
3313 * Find the core printer, if any...
3316 if ((iclass
= FindPrinter(name
)) != NULL
&&
3317 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
3323 * Add the group separator as needed...
3327 ippAddSeparator(con
->response
);
3332 * Send the following attributes for each printer:
3335 * printer-state-message
3336 * printer-is-accepting-jobs
3337 * + all printer attributes
3340 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
3341 "printer-state", printer
->state
);
3343 add_printer_state_reasons(con
, printer
);
3345 if (printer
->state_message
[0])
3346 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
3347 "printer-state-message", NULL
, printer
->state_message
);
3349 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
3350 printer
->accepting
);
3352 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
3353 "printer-up-time", curtime
);
3354 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
3355 ippTimeToDate(curtime
));
3357 add_queued_job_count(con
, printer
);
3359 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
);
3362 con
->response
->request
.status
.status_code
= IPP_OK
;
3367 * 'hold_job()' - Hold a print job.
3371 hold_job(client_t
*con
, /* I - Client connection */
3372 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
3374 ipp_attribute_t
*attr
, /* Current job-hold-until */
3375 *newattr
; /* New job-hold-until */
3376 int jobid
; /* Job ID */
3377 char method
[HTTP_MAX_URI
],
3378 /* Method portion of URI */
3379 username
[HTTP_MAX_URI
],
3380 /* Username portion of URI */
3382 /* Host portion of URI */
3383 resource
[HTTP_MAX_URI
];
3384 /* Resource portion of URI */
3385 int port
; /* Port portion of URI */
3386 job_t
*job
; /* Job information */
3389 LogMessage(L_DEBUG2
, "hold_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3390 uri
->values
[0].string
.text
);
3393 * Verify that the POST operation was done to a valid URI.
3396 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3397 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
3398 strncmp(con
->uri
, "/printers/", 10) != 0)
3400 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
3402 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3407 * See if we have a job URI or a printer URI...
3410 if (strcmp(uri
->name
, "printer-uri") == 0)
3413 * Got a printer URI; see if we also have a job-id attribute...
3416 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3418 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
3419 send_ipp_error(con
, IPP_BAD_REQUEST
);
3423 jobid
= attr
->values
[0].integer
;
3428 * Got a job URI; parse it to get the job ID...
3431 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3433 if (strncmp(resource
, "/jobs/", 6) != 0)
3439 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
3440 uri
->values
[0].string
.text
);
3441 send_ipp_error(con
, IPP_BAD_REQUEST
);
3445 jobid
= atoi(resource
+ 6);
3449 * See if the job exists...
3452 if ((job
= FindJob(jobid
)) == NULL
)
3455 * Nope - return a "not found" error...
3458 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
3459 send_ipp_error(con
, IPP_NOT_FOUND
);
3464 * See if the job is owned by the requesting user...
3467 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
3469 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
3470 username
, jobid
, job
->username
);
3471 send_ipp_error(con
, IPP_FORBIDDEN
);
3476 * Hold the job and return...
3481 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3482 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
3484 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3485 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3490 * Free the old hold value and copy the new one over...
3493 free(attr
->values
[0].string
.text
);
3495 if (newattr
!= NULL
)
3497 attr
->value_tag
= newattr
->value_tag
;
3498 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
3502 attr
->value_tag
= IPP_TAG_KEYWORD
;
3503 attr
->values
[0].string
.text
= strdup("indefinite");
3507 * Hold job until specified time...
3510 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3513 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
3515 con
->response
->request
.status
.status_code
= IPP_OK
;
3520 * 'move_job()' - Set job attributes.
3524 move_job(client_t
*con
, /* I - Client connection */
3525 ipp_attribute_t
*uri
) /* I - Job URI */
3527 ipp_attribute_t
*attr
; /* Current attribute */
3528 int jobid
; /* Job ID */
3529 job_t
*job
; /* Current job */
3530 const char *dest
; /* Destination */
3531 cups_ptype_t dtype
; /* Destination type (printer or class) */
3532 char method
[HTTP_MAX_URI
],
3533 /* Method portion of URI */
3534 username
[HTTP_MAX_URI
],
3535 /* Username portion of URI */
3537 /* Host portion of URI */
3538 resource
[HTTP_MAX_URI
];
3539 /* Resource portion of URI */
3540 int port
; /* Port portion of URI */
3543 LogMessage(L_DEBUG2
, "move_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3544 uri
->values
[0].string
.text
);
3547 * See if we have a job URI or a printer URI...
3550 if (strcmp(uri
->name
, "printer-uri") == 0)
3553 * Got a printer URI; see if we also have a job-id attribute...
3556 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3558 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
3559 send_ipp_error(con
, IPP_BAD_REQUEST
);
3563 jobid
= attr
->values
[0].integer
;
3568 * Got a job URI; parse it to get the job ID...
3571 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3573 if (strncmp(resource
, "/jobs/", 6) != 0)
3579 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
3580 uri
->values
[0].string
.text
);
3581 send_ipp_error(con
, IPP_BAD_REQUEST
);
3585 jobid
= atoi(resource
+ 6);
3589 * See if the job exists...
3592 if ((job
= FindJob(jobid
)) == NULL
)
3595 * Nope - return a "not found" error...
3598 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
3599 send_ipp_error(con
, IPP_NOT_FOUND
);
3604 * See if the job has been completed...
3607 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
3610 * Return a "not-possible" error...
3613 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
3614 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3619 * See if the job is owned by the requesting user...
3622 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
3624 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
3625 username
, jobid
, job
->username
);
3626 send_ipp_error(con
, IPP_FORBIDDEN
);
3630 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
3633 * Need job-printer-uri...
3636 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
3637 send_ipp_error(con
, IPP_BAD_REQUEST
);
3642 * Move the job to a different printer or class...
3645 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
3647 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3653 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
3654 send_ipp_error(con
, IPP_NOT_FOUND
);
3658 MoveJob(jobid
, dest
);
3661 * Start jobs if possible...
3667 * Return with "everything is OK" status...
3670 con
->response
->request
.status
.status_code
= IPP_OK
;
3675 * 'print_job()' - Print a file to a printer or class.
3679 print_job(client_t
*con
, /* I - Client connection */
3680 ipp_attribute_t
*uri
) /* I - Printer URI */
3682 ipp_attribute_t
*attr
; /* Current attribute */
3683 ipp_attribute_t
*format
; /* Document-format attribute */
3684 const char *dest
; /* Destination */
3685 cups_ptype_t dtype
; /* Destination type (printer or class) */
3686 int priority
; /* Job priority */
3687 char *title
; /* Job name/title */
3688 job_t
*job
; /* Current job */
3689 char job_uri
[HTTP_MAX_URI
],
3691 printer_uri
[HTTP_MAX_URI
],
3693 method
[HTTP_MAX_URI
],
3694 /* Method portion of URI */
3695 username
[HTTP_MAX_URI
],
3696 /* Username portion of URI */
3698 /* Host portion of URI */
3699 resource
[HTTP_MAX_URI
],
3700 /* Resource portion of URI */
3701 filename
[1024]; /* Job filename */
3702 int port
; /* Port portion of URI */
3703 mime_type_t
*filetype
; /* Type of file */
3704 char super
[MIME_MAX_SUPER
],
3705 /* Supertype of file */
3706 type
[MIME_MAX_TYPE
],
3707 /* Subtype of file */
3708 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
3709 /* Textual name of mime type */
3710 printer_t
*printer
; /* Printer data */
3711 struct stat fileinfo
; /* File information */
3712 int kbytes
; /* Size of file */
3715 LogMessage(L_DEBUG2
, "print_job(%p[%d], %s)\n", con
, con
->http
.fd
,
3716 uri
->values
[0].string
.text
);
3719 * Verify that the POST operation was done to a valid URI.
3722 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3723 strncmp(con
->uri
, "/printers/", 10) != 0)
3725 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
3727 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3732 * OK, see if the client is sending the document compressed - CUPS
3733 * doesn't support compression yet...
3736 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
3737 strcmp(attr
->values
[0].string
.text
, "none") == 0)
3739 LogMessage(L_ERROR
, "print_job: Unsupported compression attribute %s!",
3740 attr
->values
[0].string
.text
);
3741 send_ipp_error(con
, IPP_ATTRIBUTES
);
3742 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
3743 "compression", NULL
, attr
->values
[0].string
.text
);
3748 * Do we have a file to print?
3751 if (con
->filename
[0] == '\0')
3753 LogMessage(L_ERROR
, "print_job: No file!?!");
3754 send_ipp_error(con
, IPP_BAD_REQUEST
);
3759 * Is it a format we support?
3762 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
3765 * Grab format from client...
3768 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
3770 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
3771 format
->values
[0].string
.text
);
3772 send_ipp_error(con
, IPP_BAD_REQUEST
);
3779 * No document format attribute? Auto-type it!
3782 strcpy(super
, "application");
3783 strcpy(type
, "octet-stream");
3786 if (strcmp(super
, "application") == 0 &&
3787 strcmp(type
, "octet-stream") == 0)
3790 * Auto-type the file...
3793 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
3795 filetype
= mimeFileType(MimeDatabase
, con
->filename
);
3797 if (filetype
!= NULL
)
3800 * Replace the document-format attribute value with the auto-typed one.
3803 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
3808 free(format
->values
[0].string
.text
);
3809 format
->values
[0].string
.text
= strdup(mimetype
);
3812 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
3813 "document-format", NULL
, mimetype
);
3816 filetype
= mimeType(MimeDatabase
, super
, type
);
3819 filetype
= mimeType(MimeDatabase
, super
, type
);
3821 if (filetype
== NULL
)
3823 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
3825 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
3828 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
3829 "document-format", NULL
, format
->values
[0].string
.text
);
3834 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
3835 filetype
->super
, filetype
->type
);
3838 * Is the destination valid?
3841 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3843 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3849 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
3850 send_ipp_error(con
, IPP_NOT_FOUND
);
3855 * See if the printer is accepting jobs...
3858 if (dtype
== CUPS_PRINTER_CLASS
)
3860 printer
= FindClass(dest
);
3861 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
3862 ServerName
, ntohs(con
->http
.hostaddr
.sin_port
), dest
);
3866 printer
= FindPrinter(dest
);
3868 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
3869 ServerName
, ntohs(con
->http
.hostaddr
.sin_port
), dest
);
3872 if (!printer
->accepting
)
3874 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
3876 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3881 * Make sure we aren't over our limit...
3884 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3887 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3889 LogMessage(L_INFO
, "print_job: too many jobs.");
3890 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3894 if (!check_quotas(con
, printer
))
3896 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3901 * Create the job and set things up...
3904 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3905 priority
= attr
->values
[0].integer
;
3907 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3910 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3911 title
= attr
->values
[0].string
.text
;
3913 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3914 title
= "Untitled");
3916 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3918 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
3920 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3925 job
->attrs
= con
->request
;
3926 con
->request
= NULL
;
3929 * Copy the rest of the job info...
3932 strncpy(job
->title
, title
, sizeof(job
->title
) - 1);
3934 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
3936 if (con
->username
[0])
3938 strncpy(job
->username
, con
->username
, sizeof(job
->username
) - 1);
3939 job
->username
[sizeof(job
->username
) - 1] = '\0';
3943 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
3944 attr
->values
[0].string
.text
);
3946 strncpy(job
->username
, attr
->values
[0].string
.text
, sizeof(job
->username
) - 1);
3947 job
->username
[sizeof(job
->username
) - 1] = '\0';
3950 strcpy(job
->username
, "anonymous");
3953 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
3954 NULL
, job
->username
);
3957 attr
->group_tag
= IPP_TAG_JOB
;
3959 attr
->name
= strdup("job-originating-user-name");
3963 * Add remaining job attributes...
3966 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
3967 "job-originating-host-name", NULL
, con
->http
.hostname
);
3968 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3969 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
3970 "job-state", IPP_JOB_PENDING
);
3971 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3972 "job-media-sheets-completed", 0);
3973 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
3975 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3978 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
3979 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3982 if (stat(con
->filename
, &fileinfo
))
3985 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
3987 UpdateQuota(printer
, job
->username
, 0, kbytes
);
3988 attr
->values
[0].integer
+= kbytes
;
3990 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
3992 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3993 "time-at-processing", 0);
3994 attr
->value_tag
= IPP_TAG_NOVALUE
;
3995 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3996 "time-at-completed", 0);
3997 attr
->value_tag
= IPP_TAG_NOVALUE
;
3999 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4000 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4002 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
4003 "job-hold-until", NULL
, "no-hold");
4005 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
4006 !(printer
->type
& CUPS_PRINTER_REMOTE
))
4009 * Hold job until specified time...
4012 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
4013 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4016 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) || Classification
[0])
4019 * Add job sheets options...
4022 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
4024 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
4026 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
4027 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
4030 job
->job_sheets
= attr
;
4033 * Enforce classification level if set...
4036 if (Classification
[0])
4038 if (ClassifyOverride
)
4040 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
4041 (attr
->num_values
== 1 ||
4042 strcmp(attr
->values
[1].string
.text
, "none") == 0))
4045 * Force the leading banner to have the classification on it...
4048 free(attr
->values
[0].string
.text
);
4049 attr
->values
[0].string
.text
= strdup(Classification
);
4051 else if (attr
->num_values
== 2 &&
4052 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
4053 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
4054 strcmp(attr
->values
[1].string
.text
, "none") != 0)
4057 * Can't put two different security markings on the same document!
4060 free(attr
->values
[1].string
.text
);
4061 attr
->values
[1].string
.text
= strdup(attr
->values
[0].string
.text
);
4064 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
4065 (attr
->num_values
== 1 ||
4066 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
4069 * Force the leading banner to have the classification on it...
4072 free(attr
->values
[0].string
.text
);
4073 attr
->values
[0].string
.text
= strdup(Classification
);
4078 * Add the starting sheet...
4081 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
4083 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4087 * Add the job file...
4090 if (add_file(con
, job
, filetype
))
4093 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
4095 rename(con
->filename
, filename
);
4096 con
->filename
[0] = '\0';
4099 * See if we need to add the ending sheet...
4102 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) && attr
->num_values
> 1)
4108 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
4109 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4113 * Log and save the job...
4116 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
4117 job
->dest
, job
->username
);
4118 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, job
->hold_until
);
4123 * Start the job if possible...
4129 * Fill in the response info...
4132 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4133 ntohs(con
->http
.hostaddr
.sin_port
), job
->id
);
4134 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
4136 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4138 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
4139 job
->state
->values
[0].integer
);
4140 add_job_state_reasons(con
, job
);
4142 con
->response
->request
.status
.status_code
= IPP_OK
;
4147 * 'reject_jobs()' - Reject print jobs to a printer.
4151 reject_jobs(client_t
*con
, /* I - Client connection */
4152 ipp_attribute_t
*uri
) /* I - Printer or class URI */
4154 cups_ptype_t dtype
; /* Destination type (printer or class) */
4155 char method
[HTTP_MAX_URI
],
4156 /* Method portion of URI */
4157 username
[HTTP_MAX_URI
],
4158 /* Username portion of URI */
4160 /* Host portion of URI */
4161 resource
[HTTP_MAX_URI
];
4162 /* Resource portion of URI */
4163 int port
; /* Port portion of URI */
4164 const char *name
; /* Printer name */
4165 printer_t
*printer
; /* Printer data */
4166 ipp_attribute_t
*attr
; /* printer-state-message text */
4169 LogMessage(L_DEBUG2
, "reject_jobs(%p[%d], %s)\n", con
, con
->http
.fd
,
4170 uri
->values
[0].string
.text
);
4173 * Was this operation called from the correct URI?
4176 if (strncmp(con
->uri
, "/admin/", 7) != 0)
4178 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
4180 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4185 * Is the destination valid?
4188 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4190 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
4196 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
4197 send_ipp_error(con
, IPP_NOT_FOUND
);
4202 * Reject jobs sent to the printer...
4205 if (dtype
== CUPS_PRINTER_CLASS
)
4206 printer
= FindClass(name
);
4208 printer
= FindPrinter(name
);
4210 printer
->accepting
= 0;
4212 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
4213 IPP_TAG_TEXT
)) == NULL
)
4214 strcpy(printer
->state_message
, "Rejecting Jobs");
4217 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
4218 sizeof(printer
->state_message
) - 1);
4219 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
4222 if (dtype
== CUPS_PRINTER_CLASS
)
4227 if (dtype
== CUPS_PRINTER_CLASS
)
4228 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
4231 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
4235 * Everything was ok, so return OK status...
4238 con
->response
->request
.status
.status_code
= IPP_OK
;
4243 * 'release_job()' - Release a held print job.
4247 release_job(client_t
*con
, /* I - Client connection */
4248 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4250 ipp_attribute_t
*attr
; /* Current attribute */
4251 int jobid
; /* Job ID */
4252 char method
[HTTP_MAX_URI
],
4253 /* Method portion of URI */
4254 username
[HTTP_MAX_URI
],
4255 /* Username portion of URI */
4257 /* Host portion of URI */
4258 resource
[HTTP_MAX_URI
];
4259 /* Resource portion of URI */
4260 int port
; /* Port portion of URI */
4261 job_t
*job
; /* Job information */
4264 LogMessage(L_DEBUG2
, "release_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4265 uri
->values
[0].string
.text
);
4268 * Verify that the POST operation was done to a valid URI.
4271 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4272 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4273 strncmp(con
->uri
, "/printers/", 10) != 0)
4275 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
4277 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4282 * See if we have a job URI or a printer URI...
4285 if (strcmp(uri
->name
, "printer-uri") == 0)
4288 * Got a printer URI; see if we also have a job-id attribute...
4291 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4293 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
4294 send_ipp_error(con
, IPP_BAD_REQUEST
);
4298 jobid
= attr
->values
[0].integer
;
4303 * Got a job URI; parse it to get the job ID...
4306 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4308 if (strncmp(resource
, "/jobs/", 6) != 0)
4314 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
4315 uri
->values
[0].string
.text
);
4316 send_ipp_error(con
, IPP_BAD_REQUEST
);
4320 jobid
= atoi(resource
+ 6);
4324 * See if the job exists...
4327 if ((job
= FindJob(jobid
)) == NULL
)
4330 * Nope - return a "not found" error...
4333 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
4334 send_ipp_error(con
, IPP_NOT_FOUND
);
4339 * See if job is "held"...
4342 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
4345 * Nope - return a "not possible" error...
4348 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
4349 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4354 * See if the job is owned by the requesting user...
4357 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4359 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
4360 username
, jobid
, job
->username
);
4361 send_ipp_error(con
, IPP_FORBIDDEN
);
4366 * Reset the job-hold-until value to "no-hold"...
4369 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4370 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4374 free(attr
->values
[0].string
.text
);
4375 attr
->value_tag
= IPP_TAG_KEYWORD
;
4376 attr
->values
[0].string
.text
= strdup("no-hold");
4380 * Release the job and return...
4385 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
4387 con
->response
->request
.status
.status_code
= IPP_OK
;
4392 * 'restart_job()' - Restart an old print job.
4396 restart_job(client_t
*con
, /* I - Client connection */
4397 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4399 ipp_attribute_t
*attr
; /* Current attribute */
4400 int jobid
; /* Job ID */
4401 char method
[HTTP_MAX_URI
],
4402 /* Method portion of URI */
4403 username
[HTTP_MAX_URI
],
4404 /* Username portion of URI */
4406 /* Host portion of URI */
4407 resource
[HTTP_MAX_URI
];
4408 /* Resource portion of URI */
4409 int port
; /* Port portion of URI */
4410 job_t
*job
; /* Job information */
4413 LogMessage(L_DEBUG2
, "restart_job(%p[%d], %s)\n", con
, con
->http
.fd
,
4414 uri
->values
[0].string
.text
);
4417 * Verify that the POST operation was done to a valid URI.
4420 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4421 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4422 strncmp(con
->uri
, "/printers/", 10) != 0)
4424 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
4426 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4431 * See if we have a job URI or a printer URI...
4434 if (strcmp(uri
->name
, "printer-uri") == 0)
4437 * Got a printer URI; see if we also have a job-id attribute...
4440 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4442 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
4443 send_ipp_error(con
, IPP_BAD_REQUEST
);
4447 jobid
= attr
->values
[0].integer
;
4452 * Got a job URI; parse it to get the job ID...
4455 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4457 if (strncmp(resource
, "/jobs/", 6) != 0)
4463 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
4464 uri
->values
[0].string
.text
);
4465 send_ipp_error(con
, IPP_BAD_REQUEST
);
4469 jobid
= atoi(resource
+ 6);
4473 * See if the job exists...
4476 if ((job
= FindJob(jobid
)) == NULL
)
4479 * Nope - return a "not found" error...
4482 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
4483 send_ipp_error(con
, IPP_NOT_FOUND
);
4488 * See if job is in any of the "completed" states...
4491 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
4494 * Nope - return a "not possible" error...
4497 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
4498 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4503 * See if we have retained the job files...
4506 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4509 * Nope - return a "not possible" error...
4512 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
4513 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4518 * See if the job is owned by the requesting user...
4521 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4523 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
4524 username
, jobid
, job
->username
);
4525 send_ipp_error(con
, IPP_FORBIDDEN
);
4530 * Restart the job and return...
4535 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
4537 con
->response
->request
.status
.status_code
= IPP_OK
;
4542 * 'send_document()' - Send a file to a printer or class.
4546 send_document(client_t
*con
, /* I - Client connection */
4547 ipp_attribute_t
*uri
) /* I - Printer URI */
4549 ipp_attribute_t
*attr
; /* Current attribute */
4550 ipp_attribute_t
*format
; /* Document-format attribute */
4551 int jobid
; /* Job ID number */
4552 job_t
*job
; /* Current job */
4553 char job_uri
[HTTP_MAX_URI
],
4555 method
[HTTP_MAX_URI
],
4556 /* Method portion of URI */
4557 username
[HTTP_MAX_URI
],
4558 /* Username portion of URI */
4560 /* Host portion of URI */
4561 resource
[HTTP_MAX_URI
];
4562 /* Resource portion of URI */
4563 int port
; /* Port portion of URI */
4564 mime_type_t
*filetype
; /* Type of file */
4565 char super
[MIME_MAX_SUPER
],
4566 /* Supertype of file */
4567 type
[MIME_MAX_TYPE
],
4568 /* Subtype of file */
4569 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
4570 /* Textual name of mime type */
4571 char filename
[1024]; /* Job filename */
4572 printer_t
*printer
; /* Current printer */
4573 struct stat fileinfo
; /* File information */
4574 int kbytes
; /* Size of file */
4577 LogMessage(L_DEBUG2
, "send_document(%p[%d], %s)\n", con
, con
->http
.fd
,
4578 uri
->values
[0].string
.text
);
4581 * Verify that the POST operation was done to a valid URI.
4584 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4585 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
4586 strncmp(con
->uri
, "/printers/", 10) != 0)
4588 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
4590 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4595 * See if we have a job URI or a printer URI...
4598 if (strcmp(uri
->name
, "printer-uri") == 0)
4601 * Got a printer URI; see if we also have a job-id attribute...
4604 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4606 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
4607 send_ipp_error(con
, IPP_BAD_REQUEST
);
4611 jobid
= attr
->values
[0].integer
;
4616 * Got a job URI; parse it to get the job ID...
4619 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4621 if (strncmp(resource
, "/jobs/", 6) != 0)
4627 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
4628 uri
->values
[0].string
.text
);
4629 send_ipp_error(con
, IPP_BAD_REQUEST
);
4633 jobid
= atoi(resource
+ 6);
4637 * See if the job exists...
4640 if ((job
= FindJob(jobid
)) == NULL
)
4643 * Nope - return a "not found" error...
4646 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
4647 send_ipp_error(con
, IPP_NOT_FOUND
);
4652 * See if the job is owned by the requesting user...
4655 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4657 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
4658 username
, jobid
, job
->username
);
4659 send_ipp_error(con
, IPP_FORBIDDEN
);
4664 * OK, see if the client is sending the document compressed - CUPS
4665 * doesn't support compression yet...
4668 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
4669 strcmp(attr
->values
[0].string
.text
, "none") == 0)
4671 LogMessage(L_ERROR
, "send_document: Unsupported compression attribute %s!",
4672 attr
->values
[0].string
.text
);
4673 send_ipp_error(con
, IPP_ATTRIBUTES
);
4674 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
4675 "compression", NULL
, attr
->values
[0].string
.text
);
4680 * Do we have a file to print?
4683 if (con
->filename
[0] == '\0')
4685 LogMessage(L_ERROR
, "send_document: No file!?!");
4686 send_ipp_error(con
, IPP_BAD_REQUEST
);
4691 * Is it a format we support?
4694 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
4697 * Grab format from client...
4700 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
4702 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
4703 format
->values
[0].string
.text
);
4704 send_ipp_error(con
, IPP_BAD_REQUEST
);
4711 * No document format attribute? Auto-type it!
4714 strcpy(super
, "application");
4715 strcpy(type
, "octet-stream");
4718 if (strcmp(super
, "application") == 0 &&
4719 strcmp(type
, "octet-stream") == 0)
4722 * Auto-type the file...
4725 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
4727 filetype
= mimeFileType(MimeDatabase
, con
->filename
);
4729 if (filetype
!= NULL
)
4732 * Replace the document-format attribute value with the auto-typed one.
4735 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
4740 free(format
->values
[0].string
.text
);
4741 format
->values
[0].string
.text
= strdup(mimetype
);
4744 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
4745 "document-format", NULL
, mimetype
);
4748 filetype
= mimeType(MimeDatabase
, super
, type
);
4751 filetype
= mimeType(MimeDatabase
, super
, type
);
4753 if (filetype
== NULL
)
4755 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
4757 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
4760 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
4761 "document-format", NULL
, format
->values
[0].string
.text
);
4766 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
4767 filetype
->super
, filetype
->type
);
4770 * Add the file to the job...
4773 if (add_file(con
, job
, filetype
))
4776 if (job
->dtype
& CUPS_PRINTER_CLASS
)
4777 printer
= FindClass(job
->dest
);
4779 printer
= FindPrinter(job
->dest
);
4781 if (stat(con
->filename
, &fileinfo
))
4784 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
4786 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4788 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
4789 attr
->values
[0].integer
+= kbytes
;
4791 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
4793 rename(con
->filename
, filename
);
4795 con
->filename
[0] = '\0';
4797 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
4798 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
4801 * Start the job if this is the last document...
4804 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
4805 attr
->values
[0].boolean
)
4808 * See if we need to add the ending sheet...
4811 if (printer
!= NULL
&& !(printer
->type
& CUPS_PRINTER_REMOTE
) &&
4812 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
4813 attr
->num_values
> 1)
4819 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
4820 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4823 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
4824 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
4825 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
4827 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4828 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4830 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
4831 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
4839 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4840 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4842 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
4844 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
4845 job
->hold_until
= time(NULL
) + 60;
4851 * Fill in the response info...
4854 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4855 ntohs(con
->http
.hostaddr
.sin_port
), job
->id
);
4856 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
4859 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4861 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
4862 job
->state
->values
[0].integer
);
4863 add_job_state_reasons(con
, job
);
4865 con
->response
->request
.status
.status_code
= IPP_OK
;
4870 * 'send_ipp_error()' - Send an error status back to the IPP client.
4874 send_ipp_error(client_t
*con
, /* I - Client connection */
4875 ipp_status_t status
) /* I - IPP status code */
4877 LogMessage(L_DEBUG2
, "send_ipp_error(%p[%d], %x)\n", con
, con
->http
.fd
,
4880 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
4882 con
->response
->request
.status
.status_code
= status
;
4884 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
4885 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
4886 "attributes-charset", NULL
, DefaultCharset
);
4888 if (ippFindAttribute(con
->response
, "attributes-natural-language",
4889 IPP_TAG_ZERO
) == NULL
)
4890 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
4891 "attributes-natural-language", NULL
, DefaultLanguage
);
4896 * 'set_default()' - Set the default destination...
4900 set_default(client_t
*con
, /* I - Client connection */
4901 ipp_attribute_t
*uri
) /* I - Printer URI */
4903 cups_ptype_t dtype
; /* Destination type (printer or class) */
4904 char method
[HTTP_MAX_URI
],
4905 /* Method portion of URI */
4906 username
[HTTP_MAX_URI
],
4907 /* Username portion of URI */
4909 /* Host portion of URI */
4910 resource
[HTTP_MAX_URI
];
4911 /* Resource portion of URI */
4912 int port
; /* Port portion of URI */
4913 const char *name
; /* Printer name */
4916 LogMessage(L_DEBUG2
, "set_default(%p[%d], %s)\n", con
, con
->http
.fd
,
4917 uri
->values
[0].string
.text
);
4920 * Was this operation called from the correct URI?
4923 if (strncmp(con
->uri
, "/admin/", 7) != 0)
4925 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
4927 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4932 * Is the destination valid?
4935 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4937 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
4943 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
4944 send_ipp_error(con
, IPP_NOT_FOUND
);
4949 * Set it as the default...
4952 if (dtype
== CUPS_PRINTER_CLASS
)
4953 DefaultPrinter
= FindClass(name
);
4955 DefaultPrinter
= FindPrinter(name
);
4960 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
4964 * Everything was ok, so return OK status...
4967 con
->response
->request
.status
.status_code
= IPP_OK
;
4972 * 'set_job_attrs()' - Set job attributes.
4976 set_job_attrs(client_t
*con
, /* I - Client connection */
4977 ipp_attribute_t
*uri
) /* I - Job URI */
4979 ipp_attribute_t
*attr
, /* Current attribute */
4980 *attr2
, /* Job attribute */
4981 *prev2
; /* Previous job attribute */
4982 int jobid
; /* Job ID */
4983 job_t
*job
; /* Current job */
4984 char method
[HTTP_MAX_URI
],
4985 /* Method portion of URI */
4986 username
[HTTP_MAX_URI
],
4987 /* Username portion of URI */
4989 /* Host portion of URI */
4990 resource
[HTTP_MAX_URI
];
4991 /* Resource portion of URI */
4992 int port
; /* Port portion of URI */
4995 LogMessage(L_DEBUG2
, "set_job_attrs(%p[%d], %s)\n", con
, con
->http
.fd
,
4996 uri
->values
[0].string
.text
);
4999 * See if we have a job URI or a printer URI...
5002 if (strcmp(uri
->name
, "printer-uri") == 0)
5005 * Got a printer URI; see if we also have a job-id attribute...
5008 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
5010 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
5011 send_ipp_error(con
, IPP_BAD_REQUEST
);
5015 jobid
= attr
->values
[0].integer
;
5020 * Got a job URI; parse it to get the job ID...
5023 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5025 if (strncmp(resource
, "/jobs/", 6) != 0)
5031 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
5032 uri
->values
[0].string
.text
);
5033 send_ipp_error(con
, IPP_BAD_REQUEST
);
5037 jobid
= atoi(resource
+ 6);
5041 * See if the job exists...
5044 if ((job
= FindJob(jobid
)) == NULL
)
5047 * Nope - return a "not found" error...
5050 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
5051 send_ipp_error(con
, IPP_NOT_FOUND
);
5056 * See if the job has been completed...
5059 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
5062 * Return a "not-possible" error...
5065 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
5066 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5071 * See if the job is owned by the requesting user...
5074 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
5076 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
5077 username
, jobid
, job
->username
);
5078 send_ipp_error(con
, IPP_FORBIDDEN
);
5083 * See what the user wants to change.
5086 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5088 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
5091 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
5092 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
5093 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
5094 strcmp(attr
->name
, "job-k-octets") == 0 ||
5095 strcmp(attr
->name
, "job-id") == 0 ||
5096 strcmp(attr
->name
, "job-sheets") == 0 ||
5097 strncmp(attr
->name
, "time-at-", 8) == 0)
5098 continue; /* Read-only attrs */
5100 if (strcmp(attr
->name
, "job-priority") == 0 &&
5101 attr
->value_tag
== IPP_TAG_INTEGER
&&
5102 job
->state
->values
[0].integer
!= IPP_JOB_PROCESSING
)
5105 * Change the job priority
5108 SetJobPriority(jobid
, attr
->values
[0].integer
);
5110 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
5113 * Some other value; first free the old value...
5116 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
5117 if (prev2
->next
== attr2
)
5121 prev2
->next
= attr2
->next
;
5123 job
->attrs
->attrs
= attr2
->next
;
5125 _ipp_free_attr(attr2
);
5128 * Then copy the attribute...
5131 copy_attribute(job
->attrs
, attr
, 0);
5134 * See if the job-name or job-hold-until is being changed.
5137 if (strcmp(attr
->name
, "job-name") == 0)
5138 strncpy(job
->title
, attr
->values
[0].string
.text
, sizeof(job
->title
) - 1);
5139 else if (strcmp(attr
->name
, "job-hold-until") == 0)
5141 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5143 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
5144 ReleaseJob(job
->id
);
5149 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
5152 * Delete the attribute...
5155 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
5157 prev2
= attr2
, attr2
= attr2
->next
)
5158 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
5164 prev2
->next
= attr2
->next
;
5166 job
->attrs
->attrs
= attr2
->next
;
5168 _ipp_free_attr(attr2
);
5174 * Add new option by copying it...
5177 copy_attribute(job
->attrs
, attr
, 0);
5188 * Start jobs if possible...
5194 * Return with "everything is OK" status...
5197 con
->response
->request
.status
.status_code
= IPP_OK
;
5202 * 'start_printer()' - Start a printer.
5206 start_printer(client_t
*con
, /* I - Client connection */
5207 ipp_attribute_t
*uri
) /* I - Printer URI */
5209 cups_ptype_t dtype
; /* Destination type (printer or class) */
5210 char method
[HTTP_MAX_URI
],
5211 /* Method portion of URI */
5212 username
[HTTP_MAX_URI
],
5213 /* Username portion of URI */
5215 /* Host portion of URI */
5216 resource
[HTTP_MAX_URI
];
5217 /* Resource portion of URI */
5218 int port
; /* Port portion of URI */
5219 const char *name
; /* Printer name */
5220 printer_t
*printer
; /* Printer data */
5223 LogMessage(L_DEBUG2
, "start_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
5224 uri
->values
[0].string
.text
);
5227 * Was this operation called from the correct URI?
5230 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5232 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
5234 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5239 * Is the destination valid?
5242 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5244 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
5250 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
5251 send_ipp_error(con
, IPP_NOT_FOUND
);
5256 * Start the printer...
5259 if (dtype
== CUPS_PRINTER_CLASS
)
5260 printer
= FindClass(name
);
5262 printer
= FindPrinter(name
);
5264 StartPrinter(printer
);
5266 if (dtype
== CUPS_PRINTER_CLASS
)
5271 if (dtype
== CUPS_PRINTER_CLASS
)
5272 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
5275 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
5278 printer
->state_message
[0] = '\0';
5283 * Everything was ok, so return OK status...
5286 con
->response
->request
.status
.status_code
= IPP_OK
;
5291 * 'stop_printer()' - Stop a printer.
5295 stop_printer(client_t
*con
, /* I - Client connection */
5296 ipp_attribute_t
*uri
) /* I - Printer URI */
5298 cups_ptype_t dtype
; /* Destination type (printer or class) */
5299 char method
[HTTP_MAX_URI
],
5300 /* Method portion of URI */
5301 username
[HTTP_MAX_URI
],
5302 /* Username portion of URI */
5304 /* Host portion of URI */
5305 resource
[HTTP_MAX_URI
];
5306 /* Resource portion of URI */
5307 int port
; /* Port portion of URI */
5308 const char *name
; /* Printer name */
5309 printer_t
*printer
; /* Printer data */
5310 ipp_attribute_t
*attr
; /* printer-state-message attribute */
5313 LogMessage(L_DEBUG2
, "stop_printer(%p[%d], %s)\n", con
, con
->http
.fd
,
5314 uri
->values
[0].string
.text
);
5317 * Was this operation called from the correct URI?
5320 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5322 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
5324 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5329 * Is the destination valid?
5332 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5334 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
5340 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
5341 send_ipp_error(con
, IPP_NOT_FOUND
);
5346 * Stop the printer...
5349 if (dtype
== CUPS_PRINTER_CLASS
)
5350 printer
= FindClass(name
);
5352 printer
= FindPrinter(name
);
5354 StopPrinter(printer
);
5356 if (dtype
== CUPS_PRINTER_CLASS
)
5361 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
5362 IPP_TAG_TEXT
)) == NULL
)
5363 strcpy(printer
->state_message
, "Paused");
5366 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
5367 sizeof(printer
->state_message
) - 1);
5368 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
5371 if (dtype
== CUPS_PRINTER_CLASS
)
5372 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
5375 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
5379 * Everything was ok, so return OK status...
5382 con
->response
->request
.status
.status_code
= IPP_OK
;
5387 * 'validate_job()' - Validate printer options and destination.
5391 validate_job(client_t
*con
, /* I - Client connection */
5392 ipp_attribute_t
*uri
) /* I - Printer URI */
5394 ipp_attribute_t
*attr
; /* Current attribute */
5395 ipp_attribute_t
*format
; /* Document-format attribute */
5396 cups_ptype_t dtype
; /* Destination type (printer or class) */
5397 char method
[HTTP_MAX_URI
],
5398 /* Method portion of URI */
5399 username
[HTTP_MAX_URI
],
5400 /* Username portion of URI */
5402 /* Host portion of URI */
5403 resource
[HTTP_MAX_URI
];
5404 /* Resource portion of URI */
5405 int port
; /* Port portion of URI */
5406 char super
[MIME_MAX_SUPER
],
5407 /* Supertype of file */
5408 type
[MIME_MAX_TYPE
];
5409 /* Subtype of file */
5412 LogMessage(L_DEBUG2
, "validate_job(%p[%d], %s)\n", con
, con
->http
.fd
,
5413 uri
->values
[0].string
.text
);
5416 * Verify that the POST operation was done to a valid URI.
5419 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5420 strncmp(con
->uri
, "/printers/", 10) != 0)
5422 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
5424 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5429 * OK, see if the client is sending the document compressed - CUPS
5430 * doesn't support compression yet...
5433 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
5434 strcmp(attr
->values
[0].string
.text
, "none") == 0)
5436 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
5437 attr
->values
[0].string
.text
);
5438 send_ipp_error(con
, IPP_ATTRIBUTES
);
5439 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5440 "compression", NULL
, attr
->values
[0].string
.text
);
5445 * Is it a format we support?
5448 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5450 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5452 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
5453 format
->values
[0].string
.text
);
5454 send_ipp_error(con
, IPP_BAD_REQUEST
);
5458 if ((strcmp(super
, "application") != 0 ||
5459 strcmp(type
, "octet-stream") != 0) &&
5460 mimeType(MimeDatabase
, super
, type
) == NULL
)
5462 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
5463 format
->values
[0].string
.text
);
5464 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5465 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5466 "document-format", NULL
, format
->values
[0].string
.text
);
5472 * Is the destination valid?
5475 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5477 if (ValidateDest(host
, resource
, &dtype
) == NULL
)
5483 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
5484 send_ipp_error(con
, IPP_NOT_FOUND
);
5489 * Everything was ok, so return OK status...
5492 con
->response
->request
.status
.status_code
= IPP_OK
;
5497 * 'validate_user()' - Validate the user for the request.
5500 static int /* O - 1 if permitted, 0 otherwise */
5501 validate_user(client_t
*con
, /* I - Client connection */
5502 const char *owner
, /* I - Owner of job/resource */
5503 char *username
, /* O - Authenticated username */
5504 int userlen
) /* I - Length of username */
5506 int i
, j
; /* Looping vars */
5507 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
5508 struct passwd
*user
; /* User info */
5509 struct group
*group
; /* System group info */
5512 LogMessage(L_DEBUG2
, "validate_user(%p[%d], \"%s\", %p, %d)\n",
5513 con
, con
->http
.fd
, owner
, username
, userlen
);
5519 if (con
== NULL
|| owner
== NULL
|| username
== NULL
|| userlen
<= 0)
5523 * Get the best authenticated username that is available.
5526 if (con
->username
[0])
5527 strncpy(username
, con
->username
, userlen
- 1);
5528 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
5529 strncpy(username
, attr
->values
[0].string
.text
, userlen
- 1);
5531 strncpy(username
, "anonymous", userlen
- 1);
5533 username
[userlen
- 1] = '\0';
5536 * Check the username against the owner...
5539 if (strcasecmp(username
, owner
) != 0 && strcasecmp(username
, "root") != 0)
5542 * Not the owner or root; check to see if the user is a member of the
5546 user
= getpwnam(username
);
5549 for (i
= 0, j
= 0, group
= NULL
; i
< NumSystemGroups
; i
++)
5551 group
= getgrnam(SystemGroups
[i
]);
5556 for (j
= 0; group
->gr_mem
[j
]; j
++)
5557 if (strcasecmp(username
, group
->gr_mem
[j
]) == 0)
5560 if (group
->gr_mem
[j
])
5567 if (user
== NULL
|| group
== NULL
||
5568 (group
->gr_mem
[j
] == NULL
&& group
->gr_gid
!= user
->pw_gid
))
5571 * Username not found, group not found, or user is not part of the
5584 * End of "$Id: ipp.c,v 1.146 2001/10/22 21:04:08 mike Exp $".