2 * "$Id: ipp.c,v 1.127.2.3 2001/12/26 16:52:53 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 to a new destination.
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 DEBUG_printf(("ProcessIPPRequest(%08x)\n", con
));
145 DEBUG_printf(("ProcessIPPRequest: operation_id = %04x\n",
146 con
->request
->request
.op
.operation_id
));
149 * First build an empty response message for this request...
152 con
->response
= ippNew();
154 con
->response
->request
.status
.version
[0] = con
->request
->request
.op
.version
[0];
155 con
->response
->request
.status
.version
[1] = con
->request
->request
.op
.version
[1];
156 con
->response
->request
.status
.request_id
= con
->request
->request
.op
.request_id
;
159 * Then validate the request header and required attributes...
162 if (con
->request
->request
.any
.version
[0] != 1)
165 * Return an error, since we only support IPP 1.x.
168 LogMessage(L_ERROR
, "ProcessIPPRequest: bad request version (%d.%d)!",
169 con
->request
->request
.any
.version
[0],
170 con
->request
->request
.any
.version
[1]);
172 send_ipp_error(con
, IPP_VERSION_NOT_SUPPORTED
);
174 else if (con
->request
->attrs
== NULL
)
176 LogMessage(L_ERROR
, "ProcessIPPRequest: no attributes in request!");
177 send_ipp_error(con
, IPP_BAD_REQUEST
);
182 * Make sure that the attributes are provided in the correct order and
183 * don't repeat groups...
186 for (attr
= con
->request
->attrs
, group
= attr
->group_tag
;
189 if (attr
->group_tag
< group
)
192 * Out of order; return an error...
195 LogMessage(L_ERROR
, "ProcessIPPRequest: attribute groups are out of order!");
196 send_ipp_error(con
, IPP_BAD_REQUEST
);
200 group
= attr
->group_tag
;
205 * Then make sure that the first three attributes are:
208 * attributes-natural-language
209 * printer-uri/job-uri
212 attr
= con
->request
->attrs
;
213 if (attr
!= NULL
&& strcmp(attr
->name
, "attributes-charset") == 0 &&
214 attr
->value_tag
== IPP_TAG_CHARSET
)
221 if (attr
!= NULL
&& strcmp(attr
->name
, "attributes-natural-language") == 0 &&
222 attr
->value_tag
== IPP_TAG_LANGUAGE
)
227 if ((attr
= ippFindAttribute(con
->request
, "printer-uri", IPP_TAG_URI
)) != NULL
)
229 else if ((attr
= ippFindAttribute(con
->request
, "job-uri", IPP_TAG_URI
)) != NULL
)
235 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
236 "attributes-charset", NULL
, charset
->values
[0].string
.text
);
238 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
239 "attributes-charset", NULL
, DefaultCharset
);
242 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
243 "attributes-natural-language", NULL
,
244 language
->values
[0].string
.text
);
246 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
247 "attributes-natural-language", NULL
, DefaultLanguage
);
249 if (charset
== NULL
|| language
== NULL
||
251 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEFAULT
&&
252 con
->request
->request
.op
.operation_id
!= CUPS_GET_PRINTERS
&&
253 con
->request
->request
.op
.operation_id
!= CUPS_GET_CLASSES
&&
254 con
->request
->request
.op
.operation_id
!= CUPS_GET_DEVICES
&&
255 con
->request
->request
.op
.operation_id
!= CUPS_GET_PPDS
))
258 * Return an error, since attributes-charset,
259 * attributes-natural-language, and printer-uri/job-uri are required
260 * for all operations.
264 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-charset attribute!");
266 if (language
== NULL
)
267 LogMessage(L_ERROR
, "ProcessIPPRequest: missing attributes-natural-language attribute!");
270 LogMessage(L_ERROR
, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
272 send_ipp_error(con
, IPP_BAD_REQUEST
);
277 * OK, all the checks pass so far; make sure requesting-user-name is
278 * not "root" from a remote host...
281 if ((username
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
284 * Check for root user...
287 if (strcmp(username
->values
[0].string
.text
, "root") == 0 &&
288 strcasecmp(con
->http
.hostname
, "localhost") != 0 &&
289 strcmp(con
->username
, "root") != 0)
292 * Remote unauthenticated user masquerading as local root...
295 free(username
->values
[0].string
.text
);
296 username
->values
[0].string
.text
= strdup(RemoteRoot
);
301 * Then try processing the operation...
304 switch (con
->request
->request
.op
.operation_id
)
310 case IPP_VALIDATE_JOB
:
311 validate_job(con
, uri
);
314 case IPP_CREATE_JOB
:
315 create_job(con
, uri
);
318 case IPP_SEND_DOCUMENT
:
319 send_document(con
, uri
);
322 case IPP_CANCEL_JOB
:
323 cancel_job(con
, uri
);
326 case IPP_GET_JOB_ATTRIBUTES
:
327 get_job_attrs(con
, uri
);
334 case IPP_GET_PRINTER_ATTRIBUTES
:
335 get_printer_attrs(con
, uri
);
342 case IPP_RELEASE_JOB
:
343 release_job(con
, uri
);
346 case IPP_RESTART_JOB
:
347 restart_job(con
, uri
);
350 case IPP_PAUSE_PRINTER
:
351 stop_printer(con
, uri
);
354 case IPP_RESUME_PRINTER
:
355 start_printer(con
, uri
);
358 case IPP_PURGE_JOBS
:
359 cancel_all_jobs(con
, uri
);
362 case IPP_SET_JOB_ATTRIBUTES
:
363 set_job_attrs(con
, uri
);
366 case CUPS_GET_DEFAULT
:
370 case CUPS_GET_PRINTERS
:
371 get_printers(con
, 0);
374 case CUPS_GET_CLASSES
:
375 get_printers(con
, CUPS_PRINTER_CLASS
);
378 case CUPS_ADD_PRINTER
:
379 add_printer(con
, uri
);
382 case CUPS_DELETE_PRINTER
:
383 delete_printer(con
, uri
);
386 case CUPS_ADD_CLASS
:
390 case CUPS_DELETE_CLASS
:
391 delete_printer(con
, uri
);
394 case CUPS_ACCEPT_JOBS
:
395 case IPP_ENABLE_PRINTER
:
396 accept_jobs(con
, uri
);
399 case CUPS_REJECT_JOBS
:
400 case IPP_DISABLE_PRINTER
:
401 reject_jobs(con
, uri
);
404 case CUPS_SET_DEFAULT
:
405 set_default(con
, uri
);
408 case CUPS_GET_DEVICES
:
421 send_ipp_error(con
, IPP_OPERATION_NOT_SUPPORTED
);
427 SendHeader(con
, HTTP_OK
, "application/ipp");
429 con
->http
.data_encoding
= HTTP_ENCODE_LENGTH
;
430 con
->http
.data_remaining
= ippLength(con
->response
);
432 httpPrintf(HTTP(con
), "Content-Length: %d\r\n\r\n",
433 con
->http
.data_remaining
);
435 FD_SET(con
->http
.fd
, &OutputSet
);
440 * 'accept_jobs()' - Accept print jobs to a printer.
444 accept_jobs(client_t
*con
, /* I - Client connection */
445 ipp_attribute_t
*uri
) /* I - Printer or class URI */
447 cups_ptype_t dtype
; /* Destination type (printer or class) */
448 char method
[HTTP_MAX_URI
],
449 /* Method portion of URI */
450 username
[HTTP_MAX_URI
],
451 /* Username portion of URI */
453 /* Host portion of URI */
454 resource
[HTTP_MAX_URI
];
455 /* Resource portion of URI */
456 int port
; /* Port portion of URI */
457 const char *name
; /* Printer name */
458 printer_t
*printer
; /* Printer data */
461 LogMessage(L_DEBUG2
, "accept_jobs(%d, %s)\n", con
->http
.fd
,
462 uri
->values
[0].string
.text
);
465 * Was this operation called from the correct URI?
468 if (strncmp(con
->uri
, "/admin/", 7) != 0)
470 LogMessage(L_ERROR
, "accept_jobs: admin request on bad resource \'%s\'!",
472 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
477 * Is the destination valid?
480 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
482 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
488 LogMessage(L_ERROR
, "accept_jobs: resource name \'%s\' no good!", resource
);
489 send_ipp_error(con
, IPP_NOT_FOUND
);
494 * Accept jobs sent to the printer...
497 if (dtype
== CUPS_PRINTER_CLASS
)
498 printer
= FindClass(name
);
500 printer
= FindPrinter(name
);
502 printer
->accepting
= 1;
503 printer
->state_message
[0] = '\0';
505 if (dtype
== CUPS_PRINTER_CLASS
)
510 LogMessage(L_INFO
, "Printer \'%s\' now accepting jobs (\'%s\').", name
,
514 * Everything was ok, so return OK status...
517 con
->response
->request
.status
.status_code
= IPP_OK
;
522 * 'add_class()' - Add a class to the system.
526 add_class(client_t
*con
, /* I - Client connection */
527 ipp_attribute_t
*uri
) /* I - URI of class */
529 int i
; /* Looping var */
530 char method
[HTTP_MAX_URI
],
531 /* Method portion of URI */
532 username
[HTTP_MAX_URI
],
533 /* Username portion of URI */
535 /* Host portion of URI */
536 resource
[HTTP_MAX_URI
];
537 /* Resource portion of URI */
538 int port
; /* Port portion of URI */
539 printer_t
*pclass
; /* Class */
540 cups_ptype_t dtype
; /* Destination type */
541 const char *dest
; /* Printer or class name */
542 ipp_attribute_t
*attr
; /* Printer attribute */
543 int modify
; /* Non-zero if we just modified */
546 LogMessage(L_DEBUG2
, "add_class(%d, %s)\n", con
->http
.fd
,
547 uri
->values
[0].string
.text
);
550 * Was this operation called from the correct URI?
553 if (strncmp(con
->uri
, "/admin/", 7) != 0)
555 LogMessage(L_ERROR
, "add_class: admin request on bad resource \'%s\'!",
557 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
561 DEBUG_printf(("add_class(%08x, %08x)\n", con
, uri
));
564 * Do we have a valid URI?
567 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
569 if (strncmp(resource
, "/classes/", 9) != 0 || strlen(resource
) == 9)
572 * No, return an error...
575 send_ipp_error(con
, IPP_BAD_REQUEST
);
580 * See if the class already exists; if not, create a new class...
583 if ((pclass
= FindClass(resource
+ 9)) == NULL
)
586 * Class doesn't exist; see if we have a printer of the same name...
589 if ((pclass
= FindPrinter(resource
+ 9)) != NULL
&&
590 !(pclass
->type
& CUPS_PRINTER_REMOTE
))
593 * Yes, return an error...
596 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
601 * No, add the pclass...
604 pclass
= AddClass(resource
+ 9);
607 else if (pclass
->type
& CUPS_PRINTER_IMPLICIT
)
610 * Rename the implicit class to "AnyClass" or remove it...
613 if (ImplicitAnyClasses
)
615 snprintf(pclass
->name
, sizeof(pclass
->name
), "Any%s", resource
+ 9);
619 DeletePrinter(pclass
);
622 * Add the class as a new local class...
625 pclass
= AddClass(resource
+ 9);
628 else if (pclass
->type
& CUPS_PRINTER_REMOTE
)
631 * Rename the remote class to "Class"...
634 DeletePrinterFilters(pclass
);
635 snprintf(pclass
->name
, sizeof(pclass
->name
), "%s@%s", resource
+ 9,
637 SetPrinterAttrs(pclass
);
641 * Add the class as a new local class...
644 pclass
= AddClass(resource
+ 9);
651 * Look for attributes and copy them over as needed...
654 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
656 strncpy(pclass
->location
, attr
->values
[0].string
.text
, sizeof(pclass
->location
) - 1);
657 pclass
->location
[sizeof(pclass
->location
) - 1] = '\0';
660 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
662 strncpy(pclass
->info
, attr
->values
[0].string
.text
, sizeof(pclass
->info
) - 1);
663 pclass
->info
[sizeof(pclass
->info
) - 1] = '\0';
666 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
668 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
669 pclass
->name
, attr
->values
[0].boolean
, pclass
->accepting
);
671 pclass
->accepting
= attr
->values
[0].boolean
;
673 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
675 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", pclass
->name
,
676 attr
->values
[0].integer
, pclass
->state
);
678 if (pclass
->state
== IPP_PRINTER_STOPPED
&&
679 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
680 pclass
->state
= IPP_PRINTER_IDLE
;
681 else if (pclass
->state
!= IPP_PRINTER_STOPPED
&&
682 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
684 if (pclass
->state
== IPP_PRINTER_PROCESSING
)
685 StopJob(((job_t
*)pclass
->job
)->id
);
687 pclass
->state
= IPP_PRINTER_STOPPED
;
690 pclass
->browse_time
= 0;
692 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
694 strncpy(pclass
->state_message
, attr
->values
[0].string
.text
,
695 sizeof(pclass
->state_message
) - 1);
696 pclass
->state_message
[sizeof(pclass
->state_message
) - 1] = '\0';
698 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
701 strncpy(pclass
->job_sheets
[0], attr
->values
[0].string
.text
,
702 sizeof(pclass
->job_sheets
[0]) - 1);
703 if (attr
->num_values
> 1)
704 strncpy(pclass
->job_sheets
[1], attr
->values
[1].string
.text
,
705 sizeof(pclass
->job_sheets
[1]) - 1);
707 strcpy(pclass
->job_sheets
[1], "none");
709 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
710 IPP_TAG_ZERO
)) != NULL
)
712 FreePrinterUsers(pclass
);
714 pclass
->deny_users
= 0;
715 if (attr
->value_tag
== IPP_TAG_NAME
&&
716 (attr
->num_values
> 1 ||
717 strcmp(attr
->values
[0].string
.text
, "all") != 0))
718 for (i
= 0; i
< attr
->num_values
; i
++)
719 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
721 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
722 IPP_TAG_ZERO
)) != NULL
)
724 FreePrinterUsers(pclass
);
726 pclass
->deny_users
= 1;
727 if (attr
->value_tag
== IPP_TAG_NAME
&&
728 (attr
->num_values
> 1 ||
729 strcmp(attr
->values
[0].string
.text
, "none") != 0))
730 for (i
= 0; i
< attr
->num_values
; i
++)
731 AddPrinterUser(pclass
, attr
->values
[i
].string
.text
);
733 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
734 IPP_TAG_INTEGER
)) != NULL
)
737 pclass
->quota_period
= attr
->values
[0].integer
;
739 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
740 IPP_TAG_INTEGER
)) != NULL
)
743 pclass
->k_limit
= attr
->values
[0].integer
;
745 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
746 IPP_TAG_INTEGER
)) != NULL
)
749 pclass
->page_limit
= attr
->values
[0].integer
;
752 if ((attr
= ippFindAttribute(con
->request
, "member-uris", IPP_TAG_URI
)) != NULL
)
755 * Clear the printer array as needed...
758 if (pclass
->num_printers
> 0)
760 free(pclass
->printers
);
761 pclass
->num_printers
= 0;
765 * Add each printer or class that is listed...
768 for (i
= 0; i
< attr
->num_values
; i
++)
771 * Search for the printer or class URI...
774 httpSeparate(attr
->values
[i
].string
.text
, method
, username
, host
,
777 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
783 LogMessage(L_ERROR
, "add_class: resource name \'%s\' no good!", resource
);
784 send_ipp_error(con
, IPP_NOT_FOUND
);
789 * Add it to the class...
792 if (dtype
== CUPS_PRINTER_CLASS
)
793 AddPrinterToClass(pclass
, FindClass(dest
));
795 AddPrinterToClass(pclass
, FindPrinter(dest
));
800 * Update the printer class attributes and return...
803 SetPrinterAttrs(pclass
);
808 LogMessage(L_INFO
, "Class \'%s\' modified by \'%s\'.", pclass
->name
,
811 LogMessage(L_INFO
, "New class \'%s\' added by \'%s\'.", pclass
->name
,
814 con
->response
->request
.status
.status_code
= IPP_OK
;
819 * 'add_file()' - Add a file to a job.
822 static int /* O - 0 on success, -1 on error */
823 add_file(client_t
*con
, /* I - Connection to client */
824 job_t
*job
, /* I - Job to add to */
825 mime_type_t
*filetype
) /* I - Type of file */
827 mime_type_t
**filetypes
; /* New filetypes array... */
830 LogMessage(L_DEBUG2
, "add_file(%d, %d, %s/%s)\n", con
->http
.fd
,
831 job
->id
, filetype
->super
, filetype
->type
);
834 * Add the file to the job...
837 if (job
->num_files
== 0)
838 filetypes
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
840 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
841 (job
->num_files
+ 1) *
842 sizeof(mime_type_t
));
844 if (filetypes
== NULL
)
846 CancelJob(job
->id
, 1);
847 LogMessage(L_ERROR
, "add_file: unable to allocate memory for file types!");
848 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
852 job
->filetypes
= filetypes
;
853 job
->filetypes
[job
->num_files
] = filetype
;
862 * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
863 * upon the job and printer state...
867 add_job_state_reasons(client_t
*con
, /* I - Client connection */
868 job_t
*job
) /* I - Job info */
870 printer_t
*dest
; /* Destination printer */
873 LogMessage(L_DEBUG2
, "add_job_state_reasons(%d, %d)\n", con
->http
.fd
,
876 switch (job
->state
->values
[0].integer
)
878 case IPP_JOB_PENDING
:
879 if (job
->dtype
& CUPS_PRINTER_CLASS
)
880 dest
= FindClass(job
->dest
);
882 dest
= FindPrinter(job
->dest
);
884 if (dest
!= NULL
&& dest
->state
== IPP_PRINTER_STOPPED
)
885 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
886 "job-state-reasons", NULL
, "printer-stopped");
888 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
889 "job-state-reasons", NULL
, "none");
893 if (ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
) != NULL
||
894 ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
) != NULL
)
895 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
896 "job-state-reasons", NULL
, "job-hold-until-specified");
898 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
899 "job-state-reasons", NULL
, "job-incoming");
902 case IPP_JOB_PROCESSING
:
903 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
904 "job-state-reasons", NULL
, "job-printing");
907 case IPP_JOB_STOPPED
:
908 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
909 "job-state-reasons", NULL
, "job-stopped");
912 case IPP_JOB_CANCELLED
:
913 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
914 "job-state-reasons", NULL
, "job-canceled-by-user");
917 case IPP_JOB_ABORTED
:
918 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
919 "job-state-reasons", NULL
, "aborted-by-system");
922 case IPP_JOB_COMPLETED
:
923 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
924 "job-state-reasons", NULL
, "job-completed-successfully");
931 * 'add_printer()' - Add a printer to the system.
935 add_printer(client_t
*con
, /* I - Client connection */
936 ipp_attribute_t
*uri
) /* I - URI of printer */
938 int i
; /* Looping var */
939 char method
[HTTP_MAX_URI
],
940 /* Method portion of URI */
941 username
[HTTP_MAX_URI
],
942 /* Username portion of URI */
944 /* Host portion of URI */
945 resource
[HTTP_MAX_URI
];
946 /* Resource portion of URI */
947 int port
; /* Port portion of URI */
948 printer_t
*printer
; /* Printer/class */
949 ipp_attribute_t
*attr
; /* Printer attribute */
951 gzFile fp
; /* Script/PPD file */
953 FILE *fp
; /* Script/PPD file */
954 #endif /* HAVE_LIBZ */
955 char line
[1024]; /* Line from file... */
956 char srcfile
[1024], /* Source Script/PPD file */
957 dstfile
[1024]; /* Destination Script/PPD file */
958 int modify
; /* Non-zero if we are modifying */
961 LogMessage(L_DEBUG2
, "add_printer(%d, %s)\n", con
->http
.fd
,
962 uri
->values
[0].string
.text
);
965 * Was this operation called from the correct URI?
968 if (strncmp(con
->uri
, "/admin/", 7) != 0)
970 LogMessage(L_ERROR
, "add_printer: admin request on bad resource \'%s\'!",
972 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
977 * Do we have a valid URI?
980 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
982 if (strncmp(resource
, "/printers/", 10) != 0 || strlen(resource
) == 10)
985 * No, return an error...
988 send_ipp_error(con
, IPP_BAD_REQUEST
);
993 * See if the printer already exists; if not, create a new printer...
996 if ((printer
= FindPrinter(resource
+ 10)) == NULL
)
999 * Printer doesn't exist; see if we have a class of the same name...
1002 if ((printer
= FindClass(resource
+ 10)) != NULL
&&
1003 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1006 * Yes, return an error...
1009 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1014 * No, add the printer...
1017 printer
= AddPrinter(resource
+ 10);
1020 else if (printer
->type
& CUPS_PRINTER_IMPLICIT
)
1023 * Rename the implicit printer to "AnyPrinter" or delete it...
1026 if (ImplicitAnyClasses
)
1028 snprintf(printer
->name
, sizeof(printer
->name
), "Any%s", resource
+ 10);
1032 DeletePrinter(printer
);
1035 * Add the printer as a new local printer...
1038 printer
= AddPrinter(resource
+ 10);
1041 else if (printer
->type
& CUPS_PRINTER_REMOTE
)
1044 * Rename the remote printer to "Printer@server"...
1047 DeletePrinterFilters(printer
);
1048 snprintf(printer
->name
, sizeof(printer
->name
), "%s@%s", resource
+ 10,
1050 SetPrinterAttrs(printer
);
1054 * Add the printer as a new local printer...
1057 printer
= AddPrinter(resource
+ 10);
1064 * Look for attributes and copy them over as needed...
1067 if ((attr
= ippFindAttribute(con
->request
, "printer-location", IPP_TAG_TEXT
)) != NULL
)
1069 strncpy(printer
->location
, attr
->values
[0].string
.text
, sizeof(printer
->location
) - 1);
1070 printer
->location
[sizeof(printer
->location
) - 1] = '\0';
1073 if ((attr
= ippFindAttribute(con
->request
, "printer-info", IPP_TAG_TEXT
)) != NULL
)
1075 strncpy(printer
->info
, attr
->values
[0].string
.text
, sizeof(printer
->info
) - 1);
1076 printer
->info
[sizeof(printer
->info
) - 1] = '\0';
1079 if ((attr
= ippFindAttribute(con
->request
, "device-uri", IPP_TAG_URI
)) != NULL
)
1081 ipp_attribute_t
*device
; /* Current device */
1082 int methodlen
; /* Length of method string */
1086 * Do we have a valid device URI?
1089 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
1091 methodlen
= strlen(method
);
1093 if (strcmp(method
, "file") != 0)
1096 * See if the backend is listed as a device...
1099 for (device
= ippFindAttribute(Devices
, "device-uri", IPP_TAG_URI
);
1101 device
= ippFindNextAttribute(Devices
, "device-uri", IPP_TAG_URI
))
1102 if (strncmp(method
, device
->values
[0].string
.text
, methodlen
) == 0 &&
1103 (device
->values
[0].string
.text
[methodlen
] == ':' ||
1104 device
->values
[0].string
.text
[methodlen
] == '\0'))
1110 * Could not find device in list!
1113 LogMessage(L_ERROR
, "add_printer: bad device-uri attribute \'%s\'!",
1114 attr
->values
[0].string
.text
);
1115 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1120 LogMessage(L_INFO
, "Setting %s device-uri to \"%s\" (was \"%s\".)",
1121 printer
->name
, attr
->values
[0].string
.text
, printer
->device_uri
);
1123 strncpy(printer
->device_uri
, attr
->values
[0].string
.text
,
1124 sizeof(printer
->device_uri
) - 1);
1125 printer
->device_uri
[sizeof(printer
->device_uri
) - 1] = '\0';
1128 if ((attr
= ippFindAttribute(con
->request
, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN
)) != NULL
)
1130 LogMessage(L_INFO
, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
1131 printer
->name
, attr
->values
[0].boolean
, printer
->accepting
);
1133 printer
->accepting
= attr
->values
[0].boolean
;
1135 if ((attr
= ippFindAttribute(con
->request
, "printer-state", IPP_TAG_ENUM
)) != NULL
)
1137 LogMessage(L_INFO
, "Setting %s printer-state to %d (was %d.)", printer
->name
,
1138 attr
->values
[0].integer
, printer
->state
);
1140 if (printer
->state
== IPP_PRINTER_STOPPED
&&
1141 attr
->values
[0].integer
!= IPP_PRINTER_STOPPED
)
1142 printer
->state
= IPP_PRINTER_IDLE
;
1143 else if (printer
->state
!= IPP_PRINTER_STOPPED
&&
1144 attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1146 if (printer
->state
== IPP_PRINTER_PROCESSING
)
1147 StopJob(((job_t
*)printer
->job
)->id
);
1149 printer
->state
= IPP_PRINTER_STOPPED
;
1152 printer
->browse_time
= 0;
1154 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message", IPP_TAG_TEXT
)) != NULL
)
1156 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
1157 sizeof(printer
->state_message
) - 1);
1158 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
1160 if ((attr
= ippFindAttribute(con
->request
, "job-sheets-default", IPP_TAG_ZERO
)) != NULL
&&
1163 strncpy(printer
->job_sheets
[0], attr
->values
[0].string
.text
,
1164 sizeof(printer
->job_sheets
[0]) - 1);
1165 if (attr
->num_values
> 1)
1166 strncpy(printer
->job_sheets
[1], attr
->values
[1].string
.text
,
1167 sizeof(printer
->job_sheets
[1]) - 1);
1169 strcpy(printer
->job_sheets
[1], "none");
1171 if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-allowed",
1172 IPP_TAG_ZERO
)) != NULL
)
1174 FreePrinterUsers(printer
);
1176 printer
->deny_users
= 0;
1177 if (attr
->value_tag
== IPP_TAG_NAME
&&
1178 (attr
->num_values
> 1 ||
1179 strcmp(attr
->values
[0].string
.text
, "all") != 0))
1180 for (i
= 0; i
< attr
->num_values
; i
++)
1181 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1183 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name-denied",
1184 IPP_TAG_ZERO
)) != NULL
)
1186 FreePrinterUsers(printer
);
1188 printer
->deny_users
= 1;
1189 if (attr
->value_tag
== IPP_TAG_NAME
&&
1190 (attr
->num_values
> 1 ||
1191 strcmp(attr
->values
[0].string
.text
, "none") != 0))
1192 for (i
= 0; i
< attr
->num_values
; i
++)
1193 AddPrinterUser(printer
, attr
->values
[i
].string
.text
);
1195 if ((attr
= ippFindAttribute(con
->request
, "job-quota-period",
1196 IPP_TAG_INTEGER
)) != NULL
)
1198 FreeQuotas(printer
);
1199 printer
->quota_period
= attr
->values
[0].integer
;
1201 if ((attr
= ippFindAttribute(con
->request
, "job-k-limit",
1202 IPP_TAG_INTEGER
)) != NULL
)
1204 FreeQuotas(printer
);
1205 printer
->k_limit
= attr
->values
[0].integer
;
1207 if ((attr
= ippFindAttribute(con
->request
, "job-page-limit",
1208 IPP_TAG_INTEGER
)) != NULL
)
1210 FreeQuotas(printer
);
1211 printer
->page_limit
= attr
->values
[0].integer
;
1215 * See if we have all required attributes...
1218 if (printer
->device_uri
[0] == '\0')
1219 strcpy(printer
->device_uri
, "file:/dev/null");
1222 * See if we have an interface script or PPD file attached to the request...
1225 if (con
->filename
[0])
1227 strncpy(srcfile
, con
->filename
, sizeof(srcfile
) - 1);
1228 srcfile
[sizeof(srcfile
) - 1] = '\0';
1230 else if ((attr
= ippFindAttribute(con
->request
, "ppd-name", IPP_TAG_NAME
)) != NULL
)
1232 if (strcmp(attr
->values
[0].string
.text
, "raw") == 0)
1233 strcpy(srcfile
, "raw");
1235 snprintf(srcfile
, sizeof(srcfile
), "%s/model/%s", DataDir
,
1236 attr
->values
[0].string
.text
);
1241 LogMessage(L_DEBUG
, "add_printer: srcfile = \"%s\"", srcfile
);
1243 if (strcmp(srcfile
, "raw") == 0)
1246 * Raw driver, remove any existing PPD or interface script files.
1249 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1253 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1258 else if (srcfile
[0] && (fp
= gzopen(srcfile
, "rb")) != NULL
)
1260 else if (srcfile
[0] && (fp
= fopen(srcfile
, "rb")) != NULL
)
1261 #endif /* HAVE_LIBZ */
1264 * Yes; get the first line from it...
1269 gzgets(fp
, line
, sizeof(line
));
1272 fgets(line
, sizeof(line
), fp
);
1274 #endif /* HAVE_LIBZ */
1277 * Then see what kind of file it is...
1280 snprintf(dstfile
, sizeof(dstfile
), "%s/interfaces/%s", ServerRoot
,
1283 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1286 * The new file is a PPD file, so remove any old interface script
1287 * that might be lying around...
1295 * This must be an interface script, so move the file over to the
1296 * interfaces directory and make it executable...
1299 if (copy_file(srcfile
, dstfile
))
1301 LogMessage(L_ERROR
, "add_printer: Unable to copy interface script from %s to %s - %s!",
1302 srcfile
, dstfile
, strerror(errno
));
1303 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1308 LogMessage(L_DEBUG
, "add_printer: Copied interface script successfully!");
1309 chmod(dstfile
, 0755);
1313 snprintf(dstfile
, sizeof(dstfile
), "%s/ppd/%s.ppd", ServerRoot
,
1316 if (strncmp(line
, "*PPD-Adobe", 10) == 0)
1319 * The new file is a PPD file, so move the file over to the
1320 * ppd directory and make it readable by all...
1323 if (copy_file(srcfile
, dstfile
))
1325 LogMessage(L_ERROR
, "add_printer: Unable to copy PPD file from %s to %s - %s!",
1326 srcfile
, dstfile
, strerror(errno
));
1327 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
1332 LogMessage(L_DEBUG
, "add_printer: Copied PPD file successfully!");
1333 chmod(dstfile
, 0644);
1339 * This must be an interface script, so remove any old PPD file that
1340 * may be lying around...
1348 * Make this printer the default if there is none...
1351 if (DefaultPrinter
== NULL
)
1352 DefaultPrinter
= printer
;
1355 * Update the printer attributes and return...
1358 SetPrinterAttrs(printer
);
1361 if (printer
->job
!= NULL
)
1364 * Stop the current job and then restart it below...
1367 StopJob(((job_t
*)printer
->job
)->id
);
1373 LogMessage(L_INFO
, "Printer \'%s\' modified by \'%s\'.", printer
->name
,
1376 LogMessage(L_INFO
, "New printer \'%s\' added by \'%s\'.", printer
->name
,
1379 con
->response
->request
.status
.status_code
= IPP_OK
;
1384 * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
1385 * based upon the printer state...
1389 add_printer_state_reasons(client_t
*con
, /* I - Client connection */
1390 printer_t
*p
) /* I - Printer info */
1392 LogMessage(L_DEBUG2
, "add_printer_state_reasons(%d, %s)\n", con
->http
.fd
,
1397 case IPP_PRINTER_STOPPED
:
1398 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1399 "printer-state-reasons", NULL
, "paused");
1403 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1404 "printer-state-reasons", NULL
, "none");
1411 * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
1412 * the specified printer or class.
1416 add_queued_job_count(client_t
*con
, /* I - Client connection */
1417 printer_t
*p
) /* I - Printer or class */
1419 int count
; /* Number of jobs on destination */
1422 LogMessage(L_DEBUG2
, "add_queued_job_count(%d, %s)\n", con
->http
.fd
,
1425 count
= GetPrinterJobCount(p
->name
);
1427 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1428 "queued-job-count", count
);
1433 * 'cancel_all_jobs()' - Cancel all print jobs.
1437 cancel_all_jobs(client_t
*con
, /* I - Client connection */
1438 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1440 const char *dest
; /* Destination */
1441 cups_ptype_t dtype
; /* Destination type */
1442 char method
[HTTP_MAX_URI
],
1443 /* Method portion of URI */
1444 username
[HTTP_MAX_URI
],
1445 /* Username portion of URI */
1447 /* Host portion of URI */
1448 resource
[HTTP_MAX_URI
];
1449 /* Resource portion of URI */
1450 int port
; /* Port portion of URI */
1451 printer_t
*printer
; /* Current printer */
1454 LogMessage(L_DEBUG2
, "cancel_all_jobs(%d, %s)\n", con
->http
.fd
,
1455 uri
->values
[0].string
.text
);
1458 * Was this operation called from the correct URI?
1461 if (strncmp(con
->uri
, "/admin/", 7) != 0)
1463 LogMessage(L_ERROR
, "cancel_all_jobs: admin request on bad resource \'%s\'!",
1465 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1470 * See if we have a printer URI...
1473 if (strcmp(uri
->name
, "printer-uri") != 0)
1475 LogMessage(L_ERROR
, "cancel_all_jobs: bad %s attribute \'%s\'!",
1476 uri
->name
, uri
->values
[0].string
.text
);
1477 send_ipp_error(con
, IPP_BAD_REQUEST
);
1482 * And if the destination is valid...
1485 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
,
1488 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
1494 if (strcmp(resource
, "/printers/") != 0)
1496 LogMessage(L_ERROR
, "cancel_all_jobs: resource name \'%s\' no good!", resource
);
1497 send_ipp_error(con
, IPP_NOT_FOUND
);
1502 * Cancel all jobs on all printers...
1505 for (printer
= Printers
; printer
; printer
= printer
->next
)
1507 CancelJobs(printer
->name
);
1508 LogMessage(L_INFO
, "All jobs on \'%s\' were cancelled by \'%s\'.",
1509 printer
->name
, con
->username
);
1515 * Cancel all of the jobs on the named printer...
1519 LogMessage(L_INFO
, "All jobs on \'%s\' were cancelled by \'%s\'.", dest
,
1523 con
->response
->request
.status
.status_code
= IPP_OK
;
1528 * 'cancel_job()' - Cancel a print job.
1532 cancel_job(client_t
*con
, /* I - Client connection */
1533 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
1535 ipp_attribute_t
*attr
; /* Current attribute */
1536 int jobid
; /* Job ID */
1537 char method
[HTTP_MAX_URI
],
1538 /* Method portion of URI */
1539 username
[HTTP_MAX_URI
],
1540 /* Username portion of URI */
1542 /* Host portion of URI */
1543 resource
[HTTP_MAX_URI
];
1544 /* Resource portion of URI */
1545 int port
; /* Port portion of URI */
1546 job_t
*job
; /* Job information */
1547 const char *dest
; /* Destination */
1548 cups_ptype_t dtype
; /* Destination type (printer or class) */
1549 printer_t
*printer
; /* Printer data */
1552 LogMessage(L_DEBUG2
, "cancel_job(%d, %s)\n", con
->http
.fd
,
1553 uri
->values
[0].string
.text
);
1556 * Verify that the POST operation was done to a valid URI.
1559 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
1560 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
1561 strncmp(con
->uri
, "/printers/", 10) != 0)
1563 LogMessage(L_ERROR
, "cancel_job: cancel request on bad resource \'%s\'!",
1565 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
1570 * See if we have a job URI or a printer URI...
1573 if (strcmp(uri
->name
, "printer-uri") == 0)
1576 * Got a printer URI; see if we also have a job-id attribute...
1579 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1581 LogMessage(L_ERROR
, "cancel_job: got a printer-uri attribute but no job-id!");
1582 send_ipp_error(con
, IPP_BAD_REQUEST
);
1586 if ((jobid
= attr
->values
[0].integer
) == 0)
1589 * Find the current job on the specified printer...
1592 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1594 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
1600 LogMessage(L_ERROR
, "cancel_job: resource name \'%s\' no good!", resource
);
1601 send_ipp_error(con
, IPP_NOT_FOUND
);
1605 if (dtype
& CUPS_PRINTER_CLASS
)
1606 printer
= FindClass(dest
);
1608 printer
= FindPrinter(dest
);
1611 * See if the printer is currently printing a job...
1615 jobid
= ((job_t
*)printer
->job
)->id
;
1619 * No, see if there are any pending jobs...
1622 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
1623 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
1624 strcasecmp(job
->dest
, dest
) == 0)
1631 LogMessage(L_ERROR
, "cancel_job: No active jobs on %s!", dest
);
1632 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1641 * Got a job URI; parse it to get the job ID...
1644 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
1646 if (strncmp(resource
, "/jobs/", 6) != 0)
1652 LogMessage(L_ERROR
, "cancel_job: bad job-uri attribute \'%s\'!",
1653 uri
->values
[0].string
.text
);
1654 send_ipp_error(con
, IPP_BAD_REQUEST
);
1658 jobid
= atoi(resource
+ 6);
1662 * See if the job exists...
1665 if ((job
= FindJob(jobid
)) == NULL
)
1668 * Nope - return a "not found" error...
1671 LogMessage(L_ERROR
, "cancel_job: job #%d doesn't exist!", jobid
);
1672 send_ipp_error(con
, IPP_NOT_FOUND
);
1677 * See if the job is owned by the requesting user...
1680 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
1682 LogMessage(L_ERROR
, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
1683 username
, jobid
, job
->username
);
1684 send_ipp_error(con
, IPP_FORBIDDEN
);
1689 * See if the job is already completed, cancelled, or aborted; if so,
1690 * we can't cancel...
1693 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
1695 LogMessage(L_ERROR
, "cancel_job: job id %d is %s - can't cancel!",
1697 job
->state
->values
[0].integer
== IPP_JOB_CANCELLED
? "cancelled" :
1698 job
->state
->values
[0].integer
== IPP_JOB_ABORTED
? "aborted" :
1700 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
1705 * Cancel the job and return...
1708 CancelJob(jobid
, 0);
1711 LogMessage(L_INFO
, "Job %d was cancelled by \'%s\'.", jobid
, username
);
1713 con
->response
->request
.status
.status_code
= IPP_OK
;
1718 * 'check_quotas()' - Check quotas for a printer and user.
1721 static int /* O - 1 if OK, 0 if not */
1722 check_quotas(client_t
*con
, /* I - Client connection */
1723 printer_t
*p
) /* I - Printer or class */
1725 int i
; /* Looping var */
1726 ipp_attribute_t
*attr
; /* Current attribute */
1727 char username
[33]; /* Username */
1728 quota_t
*q
; /* Quota data */
1731 LogMessage(L_DEBUG2
, "check_quotas(%d, %s)\n", con
->http
.fd
, p
->name
);
1737 if (con
== NULL
|| p
== NULL
)
1741 * Figure out who is printing...
1744 attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
);
1746 if (con
->username
[0])
1748 strncpy(username
, con
->username
, sizeof(username
) - 1);
1749 username
[sizeof(username
) - 1] = '\0';
1751 else if (attr
!= NULL
)
1753 LogMessage(L_DEBUG
, "check_quotas: requesting-user-name = \'%s\'",
1754 attr
->values
[0].string
.text
);
1756 strncpy(username
, attr
->values
[0].string
.text
, sizeof(username
) - 1);
1757 username
[sizeof(username
) - 1] = '\0';
1760 strcpy(username
, "anonymous");
1763 * Check global active job limits for printers and users...
1766 if (MaxJobsPerPrinter
)
1769 * Check if there are too many pending jobs on this printer...
1772 if (GetPrinterJobCount(p
->name
) >= MaxJobsPerPrinter
)
1774 LogMessage(L_INFO
, "Too many jobs for printer \"%s\"...", p
->name
);
1782 * Check if there are too many pending jobs for this user...
1785 if (GetUserJobCount(username
) >= MaxJobsPerUser
)
1787 LogMessage(L_INFO
, "Too many jobs for user \"%s\"...", username
);
1793 * Check against users...
1796 if (p
->num_users
== 0 && p
->k_limit
== 0 && p
->page_limit
== 0)
1801 for (i
= 0; i
< p
->num_users
; i
++)
1802 if (strcasecmp(username
, p
->users
[i
]) == 0)
1805 if ((i
< p
->num_users
) == p
->deny_users
)
1807 LogMessage(L_INFO
, "Denying user \"%s\" access to printer \"%s\"...",
1817 if (p
->k_limit
|| p
->page_limit
)
1819 if ((q
= UpdateQuota(p
, username
, 0, 0)) == NULL
)
1821 LogMessage(L_ERROR
, "Unable to allocate quota data for user \"%s\"!",
1826 if ((q
->k_count
>= p
->k_limit
&& p
->k_limit
) ||
1827 (q
->page_count
>= p
->page_limit
&& p
->page_limit
))
1829 LogMessage(L_INFO
, "User \"%s\" is over the quota limit...",
1836 * If we have gotten this far, we're done!
1844 * 'copy_attribute()' - Copy a single attribute.
1848 copy_attribute(ipp_t
*to
, /* O - Destination request/response */
1849 ipp_attribute_t
*attr
, /* I - Attribute to copy */
1850 int quickcopy
)/* I - Do a quick copy? */
1852 int i
; /* Looping var */
1853 ipp_attribute_t
*toattr
; /* Destination attribute */
1856 LogMessage(L_DEBUG2
, "copy_attribute(%p, %s)\n", to
,
1857 attr
->name
? attr
->name
: "(null)");
1859 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
1862 ippAddSeparator(to
);
1865 case IPP_TAG_INTEGER
:
1867 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
1868 attr
->name
, attr
->num_values
, NULL
);
1870 for (i
= 0; i
< attr
->num_values
; i
++)
1871 toattr
->values
[i
].integer
= attr
->values
[i
].integer
;
1874 case IPP_TAG_BOOLEAN
:
1875 toattr
= ippAddBooleans(to
, attr
->group_tag
, attr
->name
,
1876 attr
->num_values
, NULL
);
1878 for (i
= 0; i
< attr
->num_values
; i
++)
1879 toattr
->values
[i
].boolean
= attr
->values
[i
].boolean
;
1882 case IPP_TAG_STRING
:
1885 case IPP_TAG_KEYWORD
:
1887 case IPP_TAG_URISCHEME
:
1888 case IPP_TAG_CHARSET
:
1889 case IPP_TAG_LANGUAGE
:
1890 case IPP_TAG_MIMETYPE
:
1891 toattr
= ippAddStrings(to
, attr
->group_tag
,
1892 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
1893 attr
->name
, attr
->num_values
, NULL
, NULL
);
1897 for (i
= 0; i
< attr
->num_values
; i
++)
1898 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
1902 for (i
= 0; i
< attr
->num_values
; i
++)
1903 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
1908 toattr
= ippAddDate(to
, attr
->group_tag
, attr
->name
,
1909 attr
->values
[0].date
);
1912 case IPP_TAG_RESOLUTION
:
1913 toattr
= ippAddResolutions(to
, attr
->group_tag
, attr
->name
,
1914 attr
->num_values
, IPP_RES_PER_INCH
,
1917 for (i
= 0; i
< attr
->num_values
; i
++)
1919 toattr
->values
[i
].resolution
.xres
= attr
->values
[i
].resolution
.xres
;
1920 toattr
->values
[i
].resolution
.yres
= attr
->values
[i
].resolution
.yres
;
1921 toattr
->values
[i
].resolution
.units
= attr
->values
[i
].resolution
.units
;
1925 case IPP_TAG_RANGE
:
1926 toattr
= ippAddRanges(to
, attr
->group_tag
, attr
->name
,
1927 attr
->num_values
, NULL
, NULL
);
1929 for (i
= 0; i
< attr
->num_values
; i
++)
1931 toattr
->values
[i
].range
.lower
= attr
->values
[i
].range
.lower
;
1932 toattr
->values
[i
].range
.upper
= attr
->values
[i
].range
.upper
;
1936 case IPP_TAG_TEXTLANG
:
1937 case IPP_TAG_NAMELANG
:
1938 toattr
= ippAddStrings(to
, attr
->group_tag
,
1939 (ipp_tag_t
)(attr
->value_tag
| quickcopy
),
1940 attr
->name
, attr
->num_values
, NULL
, NULL
);
1944 for (i
= 0; i
< attr
->num_values
; i
++)
1946 toattr
->values
[i
].string
.charset
= attr
->values
[i
].string
.charset
;
1947 toattr
->values
[i
].string
.text
= attr
->values
[i
].string
.text
;
1952 for (i
= 0; i
< attr
->num_values
; i
++)
1955 toattr
->values
[i
].string
.charset
=
1956 strdup(attr
->values
[i
].string
.charset
);
1958 toattr
->values
[i
].string
.charset
=
1959 toattr
->values
[0].string
.charset
;
1961 toattr
->values
[i
].string
.text
= strdup(attr
->values
[i
].string
.text
);
1967 toattr
= ippAddIntegers(to
, attr
->group_tag
, attr
->value_tag
,
1968 attr
->name
, attr
->num_values
, NULL
);
1970 for (i
= 0; i
< attr
->num_values
; i
++)
1972 toattr
->values
[i
].unknown
.length
= attr
->values
[i
].unknown
.length
;
1974 if (toattr
->values
[i
].unknown
.length
> 0)
1976 if ((toattr
->values
[i
].unknown
.data
= malloc(toattr
->values
[i
].unknown
.length
)) == NULL
)
1977 toattr
->values
[i
].unknown
.length
= 0;
1979 memcpy(toattr
->values
[i
].unknown
.data
,
1980 attr
->values
[i
].unknown
.data
,
1981 toattr
->values
[i
].unknown
.length
);
1984 break; /* anti-compiler-warning-code */
1990 * 'copy_attrs()' - Copy attributes from one request to another.
1994 copy_attrs(ipp_t
*to
, /* I - Destination request */
1995 ipp_t
*from
, /* I - Source request */
1996 ipp_attribute_t
*req
, /* I - Requested attributes */
1997 ipp_tag_t group
) /* I - Group to copy */
1999 int i
; /* Looping var */
2000 ipp_attribute_t
*fromattr
; /* Source attribute */
2003 LogMessage(L_DEBUG2
, "copy_attrs(%p, %p, %p, %x)\n", to
, from
, req
, group
);
2005 if (to
== NULL
|| from
== NULL
)
2008 if (req
!= NULL
&& strcmp(req
->values
[0].string
.text
, "all") == 0)
2009 req
= NULL
; /* "all" means no filter... */
2011 for (fromattr
= from
->attrs
; fromattr
!= NULL
; fromattr
= fromattr
->next
)
2014 * Filter attributes as needed...
2017 if (group
!= IPP_TAG_ZERO
&& fromattr
->group_tag
!= group
&&
2018 fromattr
->group_tag
!= IPP_TAG_ZERO
)
2021 if (req
!= NULL
&& fromattr
->name
!= NULL
)
2023 for (i
= 0; i
< req
->num_values
; i
++)
2024 if (strcmp(fromattr
->name
, req
->values
[i
].string
.text
) == 0)
2027 if (i
== req
->num_values
)
2031 copy_attribute(to
, fromattr
, IPP_TAG_COPY
);
2037 * 'create_job()' - Print a file to a printer or class.
2041 create_job(client_t
*con
, /* I - Client connection */
2042 ipp_attribute_t
*uri
) /* I - Printer URI */
2044 ipp_attribute_t
*attr
; /* Current attribute */
2045 const char *dest
; /* Destination */
2046 cups_ptype_t dtype
; /* Destination type (printer or class) */
2047 int priority
; /* Job priority */
2048 char *title
; /* Job name/title */
2049 job_t
*job
; /* Current job */
2050 char job_uri
[HTTP_MAX_URI
],
2052 printer_uri
[HTTP_MAX_URI
],
2054 method
[HTTP_MAX_URI
],
2055 /* Method portion of URI */
2056 username
[HTTP_MAX_URI
],
2057 /* Username portion of URI */
2059 /* Host portion of URI */
2060 resource
[HTTP_MAX_URI
];
2061 /* Resource portion of URI */
2062 int port
; /* Port portion of URI */
2063 printer_t
*printer
; /* Printer data */
2064 int kbytes
; /* Size of print file */
2067 LogMessage(L_DEBUG2
, "create_job(%d, %s)\n", con
->http
.fd
,
2068 uri
->values
[0].string
.text
);
2071 * Verify that the POST operation was done to a valid URI.
2074 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
2075 strncmp(con
->uri
, "/printers/", 10) != 0)
2077 LogMessage(L_ERROR
, "create_job: cancel request on bad resource \'%s\'!",
2079 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2084 * Is the destination valid?
2087 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2089 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2095 LogMessage(L_ERROR
, "create_job: resource name \'%s\' no good!", resource
);
2096 send_ipp_error(con
, IPP_NOT_FOUND
);
2101 * See if the printer is accepting jobs...
2104 if (dtype
== CUPS_PRINTER_CLASS
)
2106 printer
= FindClass(dest
);
2109 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
2110 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
2111 ServerName
, ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), dest
);
2113 #endif /* AF_INET6 */
2114 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
2115 ServerName
, ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), dest
);
2119 printer
= FindPrinter(dest
);
2122 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
2123 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
2124 ServerName
, ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), dest
);
2126 #endif /* AF_INET6 */
2127 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
2128 ServerName
, ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), dest
);
2131 if (!printer
->accepting
)
2133 LogMessage(L_INFO
, "create_job: destination \'%s\' is not accepting jobs.",
2135 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
2140 * Make sure we aren't over our limit...
2143 if (NumJobs
>= MaxJobs
&& MaxJobs
)
2146 if (NumJobs
>= MaxJobs
&& MaxJobs
)
2148 LogMessage(L_INFO
, "create_job: too many jobs.");
2149 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2153 if (!check_quotas(con
, printer
))
2155 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
2160 * Create the job and set things up...
2163 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
2164 priority
= attr
->values
[0].integer
;
2166 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
2169 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
2170 title
= attr
->values
[0].string
.text
;
2172 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
2173 title
= "Untitled");
2175 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
2177 LogMessage(L_ERROR
, "create_job: unable to add job for destination \'%s\'!",
2179 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
2184 job
->attrs
= con
->request
;
2185 con
->request
= NULL
;
2187 strncpy(job
->title
, title
, sizeof(job
->title
) - 1);
2189 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
2191 if (con
->username
[0])
2193 strncpy(job
->username
, con
->username
, sizeof(job
->username
) - 1);
2194 job
->username
[sizeof(job
->username
) - 1] = '\0';
2196 else if (attr
!= NULL
)
2198 LogMessage(L_DEBUG
, "create_job: requesting-user-name = \'%s\'",
2199 attr
->values
[0].string
.text
);
2201 strncpy(job
->username
, attr
->values
[0].string
.text
,
2202 sizeof(job
->username
) - 1);
2203 job
->username
[sizeof(job
->username
) - 1] = '\0';
2206 strcpy(job
->username
, "anonymous");
2209 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
2210 NULL
, job
->username
);
2213 attr
->group_tag
= IPP_TAG_JOB
;
2215 attr
->name
= strdup("job-originating-user-name");
2218 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
2219 "job-originating-host-name", NULL
, con
->http
.hostname
);
2220 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
2222 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2223 "time-at-processing", 0);
2224 attr
->value_tag
= IPP_TAG_NOVALUE
;
2225 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2226 "time-at-completed", 0);
2227 attr
->value_tag
= IPP_TAG_NOVALUE
;
2230 * Add remaining job attributes...
2233 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
2234 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
2235 "job-state", IPP_JOB_STOPPED
);
2236 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2237 "job-media-sheets-completed", 0);
2238 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
2240 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
2243 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2244 attr
->values
[0].integer
= 0;
2246 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
2249 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
2250 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
2252 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
2253 "job-hold-until", NULL
, "no-hold");
2254 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
2255 !(printer
->type
& CUPS_PRINTER_REMOTE
))
2258 * Hold job until specified time...
2261 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
2264 job
->hold_until
= time(NULL
) + 60;
2266 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
2268 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) || Classification
[0])
2271 * Add job sheets options...
2274 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
2276 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
2277 printer
->job_sheets
[0], printer
->job_sheets
[1]);
2279 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
2281 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
2282 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
2285 job
->job_sheets
= attr
;
2288 * Enforce classification level if set...
2291 if (Classification
[0])
2293 if (ClassifyOverride
)
2295 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
2296 (attr
->num_values
== 1 ||
2297 strcmp(attr
->values
[1].string
.text
, "none") == 0))
2300 * Force the leading banner to have the classification on it...
2303 free(attr
->values
[0].string
.text
);
2304 attr
->values
[0].string
.text
= strdup(Classification
);
2306 else if (attr
->num_values
== 2 &&
2307 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
2308 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
2309 strcmp(attr
->values
[1].string
.text
, "none") != 0)
2312 * Can't put two different security markings on the same document!
2315 free(attr
->values
[1].string
.text
);
2316 attr
->values
[1].string
.text
= strdup(attr
->values
[0].string
.text
);
2319 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
2320 (attr
->num_values
== 1 ||
2321 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
2324 * Force the leading banner to have the classification on it...
2327 free(attr
->values
[0].string
.text
);
2328 attr
->values
[0].string
.text
= strdup(Classification
);
2333 * See if we need to add the starting sheet...
2336 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
2338 UpdateQuota(printer
, job
->username
, 0, kbytes
);
2340 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
2344 * Save and log the job...
2349 LogMessage(L_INFO
, "Job %d created on \'%s\' by \'%s\'.", job
->id
,
2350 job
->dest
, job
->username
);
2353 * Fill in the response info...
2357 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
2358 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
2359 ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), job
->id
);
2361 #endif /* AF_INET6 */
2362 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
2363 ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), job
->id
);
2365 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
2367 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
2369 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
2370 job
->state
->values
[0].integer
);
2372 con
->response
->request
.status
.status_code
= IPP_OK
;
2377 * 'copy_banner()' - Copy a banner file to the requests directory for the
2381 static int /* O - Size of banner file in kbytes */
2382 copy_banner(client_t
*con
, /* I - Client connection */
2383 job_t
*job
, /* I - Job information */
2384 const char *name
) /* I - Name of banner */
2386 int i
; /* Looping var */
2387 int kbytes
; /* Size of banner file in kbytes */
2388 char filename
[1024]; /* Job filename */
2389 banner_t
*banner
; /* Pointer to banner */
2390 FILE *in
; /* Input file */
2391 FILE *out
; /* Output file */
2392 int ch
; /* Character from file */
2393 char attrname
[255], /* Name of attribute */
2394 *s
; /* Pointer into name */
2395 ipp_attribute_t
*attr
; /* Attribute */
2398 LogMessage(L_DEBUG2
, "copy_banner(%d, %d, %s)\n", con
->http
.fd
, job
->id
,
2402 * Find the banner; return if not found or "none"...
2405 LogMessage(L_DEBUG
, "copy_banner(%p, %d, \"%s\")", con
, job
->id
,
2406 name
? name
: "(null)");
2409 strcmp(name
, "none") == 0 ||
2410 (banner
= FindBanner(name
)) == NULL
)
2414 * Open the banner and job files...
2417 if (add_file(con
, job
, banner
->filetype
))
2420 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
2422 if ((out
= fopen(filename
, "w")) == NULL
)
2424 LogMessage(L_ERROR
, "copy_banner: Unable to create banner job file %s - %s",
2425 filename
, strerror(errno
));
2430 fchmod(fileno(out
), 0640);
2431 fchown(fileno(out
), User
, Group
);
2436 * Try the localized banner file under the subdirectory...
2439 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2440 con
->language
->language
, name
);
2442 if (access(filename
, 0) && con
->language
->language
[2])
2445 * Wasn't able to find "ll_CC" locale file; try the non-national
2446 * localization banner directory.
2449 attrname
[0] = con
->language
->language
[0];
2450 attrname
[1] = con
->language
->language
[1];
2453 snprintf(filename
, sizeof(filename
), "%s/banners/%s/%s", DataDir
,
2457 if (access(filename
, 0))
2460 * Use the non-localized banner file.
2463 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2469 * Use the non-localized banner file.
2472 snprintf(filename
, sizeof(filename
), "%s/banners/%s", DataDir
, name
);
2475 if ((in
= fopen(filename
, "r")) == NULL
)
2479 LogMessage(L_ERROR
, "copy_banner: Unable to open banner template file %s - %s",
2480 filename
, strerror(errno
));
2486 * Parse the file to the end...
2489 while ((ch
= getc(in
)) != EOF
)
2493 * Get an attribute name...
2496 for (s
= attrname
; (ch
= getc(in
)) != EOF
;)
2497 if (!isalpha(ch
) && ch
!= '-' && ch
!= '?')
2499 else if (s
< (attrname
+ sizeof(attrname
) - 1))
2509 * Ignore { followed by stuff that is not an attribute name...
2513 fputs(attrname
, out
);
2519 * See if it is defined...
2522 if (attrname
[0] == '?')
2527 if (strcmp(s
, "printer-name") == 0)
2529 fputs(job
->dest
, out
);
2532 else if ((attr
= ippFindAttribute(job
->attrs
, s
, IPP_TAG_ZERO
)) == NULL
)
2535 * See if we have a leading question mark...
2538 if (attrname
[0] != '?')
2541 * Nope, write to file as-is; probably a PostScript procedure...
2545 fputs(attrname
, out
);
2553 * Output value(s)...
2556 for (i
= 0; i
< attr
->num_values
; i
++)
2561 switch (attr
->value_tag
)
2563 case IPP_TAG_INTEGER
:
2565 if (strncmp(attrname
, "time-at-", 8) == 0)
2566 fputs(GetDateTime(attr
->values
[i
].integer
), out
);
2568 fprintf(out
, "%d", attr
->values
[i
].integer
);
2571 case IPP_TAG_BOOLEAN
:
2572 fprintf(out
, "%d", attr
->values
[i
].boolean
);
2575 case IPP_TAG_NOVALUE
:
2576 fputs("novalue", out
);
2579 case IPP_TAG_RANGE
:
2580 fprintf(out
, "%d-%d", attr
->values
[i
].range
.lower
,
2581 attr
->values
[i
].range
.upper
);
2584 case IPP_TAG_RESOLUTION
:
2585 fprintf(out
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
2586 attr
->values
[i
].resolution
.yres
,
2587 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2592 case IPP_TAG_STRING
:
2595 case IPP_TAG_KEYWORD
:
2596 case IPP_TAG_CHARSET
:
2597 case IPP_TAG_LANGUAGE
:
2598 if (strcasecmp(banner
->filetype
->type
, "postscript") == 0)
2601 * Need to quote strings for PS banners...
2606 for (p
= attr
->values
[i
].string
.text
; *p
; p
++)
2608 if (*p
== '(' || *p
== ')' || *p
== '\\')
2613 else if (*p
< 32 || *p
> 126)
2614 fprintf(out
, "\\%03o", *p
);
2620 fputs(attr
->values
[i
].string
.text
, out
);
2624 break; /* anti-compiler-warning-code */
2628 else if (ch
== '\\') /* Quoted char */
2629 putc(getc(in
), out
);
2635 kbytes
= (ftell(out
) + 1023) / 1024;
2637 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
2638 attr
->values
[0].integer
+= kbytes
;
2647 * 'copy_file()' - Copy a PPD file or interface script...
2650 static int /* O - 0 = success, -1 = error */
2651 copy_file(const char *from
, /* I - Source file */
2652 const char *to
) /* I - Destination file */
2655 gzFile src
; /* Source file */
2657 int src
; /* Source file */
2658 #endif /* HAVE_LIBZ */
2659 int dst
, /* Destination file */
2660 bytes
; /* Bytes to read/write */
2661 char buffer
[8192]; /* Copy buffer */
2664 LogMessage(L_DEBUG2
, "copy_file(%s, %s)\n", from
, to
);
2667 if ((src
= gzopen(from
, "rb")) == NULL
)
2670 if ((src
= open(from
, O_RDONLY
)) < 0)
2672 #endif /* HAVE_LIBZ */
2674 if ((dst
= open(to
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644)) < 0)
2680 #endif /* HAVE_LIBZ */
2685 while ((bytes
= gzread(src
, buffer
, sizeof(buffer
))) > 0)
2687 while ((bytes
= read(src
, buffer
, sizeof(buffer
))) > 0)
2688 #endif /* HAVE_LIBZ */
2689 if (write(dst
, buffer
, bytes
) < bytes
)
2695 #endif /* HAVE_LIBZ */
2704 #endif /* HAVE_LIBZ */
2712 * 'delete_printer()' - Remove a printer or class from the system.
2716 delete_printer(client_t
*con
, /* I - Client connection */
2717 ipp_attribute_t
*uri
) /* I - URI of printer or class */
2719 const char *dest
; /* Destination */
2720 cups_ptype_t dtype
; /* Destination type (printer or class) */
2721 char method
[HTTP_MAX_URI
],
2722 /* Method portion of URI */
2723 username
[HTTP_MAX_URI
],
2724 /* Username portion of URI */
2726 /* Host portion of URI */
2727 resource
[HTTP_MAX_URI
];
2728 /* Resource portion of URI */
2729 int port
; /* Port portion of URI */
2730 printer_t
*printer
; /* Printer/class */
2731 char filename
[1024]; /* Script/PPD filename */
2734 LogMessage(L_DEBUG2
, "delete_printer(%d, %s)\n", con
->http
.fd
,
2735 uri
->values
[0].string
.text
);
2738 * Was this operation called from the correct URI?
2741 if (strncmp(con
->uri
, "/admin/", 7) != 0)
2743 LogMessage(L_ERROR
, "delete_printer: admin request on bad resource \'%s\'!",
2745 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
2749 DEBUG_printf(("delete_printer(%08x, %08x)\n", con
, uri
));
2752 * Do we have a valid URI?
2755 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2757 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2763 LogMessage(L_ERROR
, "delete_printer: resource name \'%s\' no good!", resource
);
2764 send_ipp_error(con
, IPP_NOT_FOUND
);
2769 * Find the printer or class and delete it...
2772 if (dtype
== CUPS_PRINTER_CLASS
)
2773 printer
= FindClass(dest
);
2775 printer
= FindPrinter(dest
);
2778 * Remove old jobs...
2784 * Remove any old PPD or script files...
2787 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
, dest
);
2790 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
, dest
);
2793 if (dtype
== CUPS_PRINTER_CLASS
)
2795 LogMessage(L_INFO
, "Class \'%s\' deleted by \'%s\'.", dest
,
2798 DeletePrinter(printer
);
2803 LogMessage(L_INFO
, "Printer \'%s\' deleted by \'%s\'.", dest
,
2806 DeletePrinter(printer
);
2811 * Return with no errors...
2814 con
->response
->request
.status
.status_code
= IPP_OK
;
2819 * 'get_default()' - Get the default destination.
2823 get_default(client_t
*con
) /* I - Client connection */
2825 LogMessage(L_DEBUG2
, "get_default(%d)\n", con
->http
.fd
);
2827 if (DefaultPrinter
!= NULL
)
2829 copy_attrs(con
->response
, DefaultPrinter
->attrs
,
2830 ippFindAttribute(con
->request
, "requested-attributes",
2831 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
2833 con
->response
->request
.status
.status_code
= IPP_OK
;
2836 con
->response
->request
.status
.status_code
= IPP_NOT_FOUND
;
2841 * 'get_devices()' - Get the list of available devices on the local system.
2845 get_devices(client_t
*con
) /* I - Client connection */
2847 LogMessage(L_DEBUG2
, "get_devices(%d)\n", con
->http
.fd
);
2850 * Copy the device attributes to the response using the requested-attributes
2851 * attribute that may be provided by the client.
2854 copy_attrs(con
->response
, Devices
,
2855 ippFindAttribute(con
->request
, "requested-attributes",
2856 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
2858 con
->response
->request
.status
.status_code
= IPP_OK
;
2863 * 'get_jobs()' - Get a list of jobs for the specified printer.
2867 get_jobs(client_t
*con
, /* I - Client connection */
2868 ipp_attribute_t
*uri
) /* I - Printer URI */
2870 ipp_attribute_t
*attr
, /* Current attribute */
2871 *requested
; /* Requested attributes */
2872 const char *dest
; /* Destination */
2873 cups_ptype_t dtype
; /* Destination type (printer or class) */
2874 char method
[HTTP_MAX_URI
],
2875 /* Method portion of URI */
2876 username
[HTTP_MAX_URI
],
2877 /* Username portion of URI */
2879 /* Host portion of URI */
2880 resource
[HTTP_MAX_URI
];
2881 /* Resource portion of URI */
2882 int port
; /* Port portion of URI */
2883 int completed
; /* Completed jobs? */
2884 int limit
; /* Maximum number of jobs to return */
2885 int count
; /* Number of jobs that match */
2886 job_t
*job
; /* Current job pointer */
2887 char job_uri
[HTTP_MAX_URI
];
2891 LogMessage(L_DEBUG2
, "get_jobs(%d, %s)\n", con
->http
.fd
,
2892 uri
->values
[0].string
.text
);
2895 * Is the destination valid?
2898 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
2900 if ((strncmp(resource
, "/jobs", 5) == 0 && strlen(resource
) <= 6) ||
2901 (strncmp(resource
, "/printers", 9) == 0 && strlen(resource
) <= 10))
2904 dtype
= (cups_ptype_t
)0;
2906 else if (strncmp(resource
, "/classes", 8) == 0 && strlen(resource
) <= 9)
2909 dtype
= CUPS_PRINTER_CLASS
;
2911 else if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
2917 LogMessage(L_ERROR
, "get_jobs: resource name \'%s\' no good!", resource
);
2918 send_ipp_error(con
, IPP_NOT_FOUND
);
2923 * See if the "which-jobs" attribute have been specified; if so, return
2924 * right away if they specify "completed" - we don't keep old job records...
2927 if ((attr
= ippFindAttribute(con
->request
, "which-jobs", IPP_TAG_KEYWORD
)) != NULL
&&
2928 strcmp(attr
->values
[0].string
.text
, "completed") == 0)
2934 * See if they want to limit the number of jobs reported...
2937 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
2938 limit
= attr
->values
[0].integer
;
2943 * See if we only want to see jobs for a specific user...
2946 if ((attr
= ippFindAttribute(con
->request
, "my-jobs", IPP_TAG_BOOLEAN
)) != NULL
&&
2947 attr
->values
[0].boolean
)
2949 if (con
->username
[0])
2951 strncpy(username
, con
->username
, sizeof(username
) - 1);
2952 username
[sizeof(username
) - 1] = '\0';
2954 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
2956 strncpy(username
, attr
->values
[0].string
.text
, sizeof(username
) - 1);
2957 username
[sizeof(username
) - 1] = '\0';
2960 strcpy(username
, "anonymous");
2965 requested
= ippFindAttribute(con
->request
, "requested-attributes",
2969 * OK, build a list of jobs for this printer...
2972 for (count
= 0, job
= Jobs
; count
< limit
&& job
!= NULL
; job
= job
->next
)
2975 * Filter out jobs that don't match...
2978 DEBUG_printf(("get_jobs: job->id = %d\n", job
->id
));
2980 if ((dest
!= NULL
&& strcmp(job
->dest
, dest
) != 0))
2982 if (job
->dtype
!= dtype
&&
2983 (username
[0] == '\0' || strncmp(resource
, "/jobs", 5) != 0))
2985 if (username
[0] != '\0' && strcmp(username
, job
->username
) != 0)
2988 if (completed
&& job
->state
->values
[0].integer
<= IPP_JOB_STOPPED
)
2990 if (!completed
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
2995 DEBUG_printf(("get_jobs: count = %d\n", count
));
2998 * Send the requested attributes for each job...
3002 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
3003 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3004 ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), job
->id
);
3006 #endif /* AF_INET6 */
3007 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
3008 ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), job
->id
);
3010 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3011 "job-more-info", NULL
, job_uri
);
3013 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3014 "job-uri", NULL
, job_uri
);
3016 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3017 "job-printer-up-time", time(NULL
));
3020 * Copy the job attributes to the response using the requested-attributes
3021 * attribute that may be provided by the client.
3024 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
);
3026 add_job_state_reasons(con
, job
);
3028 ippAddSeparator(con
->response
);
3031 if (requested
!= NULL
)
3032 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
3034 con
->response
->request
.status
.status_code
= IPP_OK
;
3039 * 'get_job_attrs()' - Get job attributes.
3043 get_job_attrs(client_t
*con
, /* I - Client connection */
3044 ipp_attribute_t
*uri
) /* I - Job URI */
3046 ipp_attribute_t
*attr
, /* Current attribute */
3047 *requested
; /* Requested attributes */
3048 int jobid
; /* Job ID */
3049 job_t
*job
; /* Current job */
3050 char method
[HTTP_MAX_URI
],
3051 /* Method portion of URI */
3052 username
[HTTP_MAX_URI
],
3053 /* Username portion of URI */
3055 /* Host portion of URI */
3056 resource
[HTTP_MAX_URI
];
3057 /* Resource portion of URI */
3058 int port
; /* Port portion of URI */
3059 char job_uri
[HTTP_MAX_URI
];
3063 LogMessage(L_DEBUG2
, "get_job_attrs(%d, %s)\n", con
->http
.fd
,
3064 uri
->values
[0].string
.text
);
3067 * See if we have a job URI or a printer URI...
3070 if (strcmp(uri
->name
, "printer-uri") == 0)
3073 * Got a printer URI; see if we also have a job-id attribute...
3076 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3078 LogMessage(L_ERROR
, "get_job_attrs: got a printer-uri attribute but no job-id!");
3079 send_ipp_error(con
, IPP_BAD_REQUEST
);
3083 jobid
= attr
->values
[0].integer
;
3088 * Got a job URI; parse it to get the job ID...
3091 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3093 if (strncmp(resource
, "/jobs/", 6) != 0)
3099 LogMessage(L_ERROR
, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
3100 uri
->values
[0].string
.text
);
3101 send_ipp_error(con
, IPP_BAD_REQUEST
);
3105 jobid
= atoi(resource
+ 6);
3109 * See if the job exists...
3112 if ((job
= FindJob(jobid
)) == NULL
)
3115 * Nope - return a "not found" error...
3118 LogMessage(L_ERROR
, "get_job_attrs: job #%d doesn't exist!", jobid
);
3119 send_ipp_error(con
, IPP_NOT_FOUND
);
3124 * Put out the standard attributes...
3128 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
3129 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
3130 ServerName
, ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
),
3133 #endif /* AF_INET6 */
3134 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d",
3135 ServerName
, ntohs(con
->http
.hostaddr
.ipv4
.sin_port
),
3138 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
3140 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3141 "job-more-info", NULL
, job_uri
);
3143 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
,
3144 "job-uri", NULL
, job_uri
);
3146 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
3147 "job-printer-up-time", time(NULL
));
3150 * Copy the job attributes to the response using the requested-attributes
3151 * attribute that may be provided by the client.
3154 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3157 copy_attrs(con
->response
, job
->attrs
, requested
, IPP_TAG_JOB
);
3159 add_job_state_reasons(con
, job
);
3161 if (requested
!= NULL
)
3162 con
->response
->request
.status
.status_code
= IPP_OK_SUBST
;
3164 con
->response
->request
.status
.status_code
= IPP_OK
;
3169 * 'get_ppds()' - Get the list of PPD files on the local system.
3173 get_ppds(client_t
*con
) /* I - Client connection */
3175 LogMessage(L_DEBUG2
, "get_ppds(%d)\n", con
->http
.fd
);
3178 * Copy the PPD attributes to the response using the requested-attributes
3179 * attribute that may be provided by the client.
3182 copy_attrs(con
->response
, PPDs
,
3183 ippFindAttribute(con
->request
, "requested-attributes",
3184 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
3186 con
->response
->request
.status
.status_code
= IPP_OK
;
3191 * 'get_printer_attrs()' - Get printer attributes.
3195 get_printer_attrs(client_t
*con
, /* I - Client connection */
3196 ipp_attribute_t
*uri
) /* I - Printer URI */
3198 const char *dest
; /* Destination */
3199 cups_ptype_t dtype
; /* Destination type (printer or class) */
3200 char method
[HTTP_MAX_URI
],
3201 /* Method portion of URI */
3202 username
[HTTP_MAX_URI
],
3203 /* Username portion of URI */
3205 /* Host portion of URI */
3206 resource
[HTTP_MAX_URI
];
3207 /* Resource portion of URI */
3208 int port
; /* Port portion of URI */
3209 printer_t
*printer
; /* Printer/class */
3210 time_t curtime
; /* Current time */
3213 LogMessage(L_DEBUG2
, "get_printer_attrs(%d, %s)\n", con
->http
.fd
,
3214 uri
->values
[0].string
.text
);
3217 * Is the destination valid?
3220 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3222 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3228 LogMessage(L_ERROR
, "get_printer_attrs: resource name \'%s\' no good!", resource
);
3229 send_ipp_error(con
, IPP_NOT_FOUND
);
3233 if (dtype
== CUPS_PRINTER_CLASS
)
3234 printer
= FindClass(dest
);
3236 printer
= FindPrinter(dest
);
3238 curtime
= time(NULL
);
3241 * Copy the printer attributes to the response using requested-attributes
3242 * and document-format attributes that may be provided by the client.
3245 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
3248 add_printer_state_reasons(con
, printer
);
3250 if (printer
->state_message
[0])
3251 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
3252 "printer-state-message", NULL
, printer
->state_message
);
3254 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
3255 printer
->accepting
);
3257 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
3258 "printer-up-time", curtime
);
3259 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
3260 ippTimeToDate(curtime
));
3262 add_queued_job_count(con
, printer
);
3264 copy_attrs(con
->response
, printer
->attrs
,
3265 ippFindAttribute(con
->request
, "requested-attributes",
3266 IPP_TAG_KEYWORD
), IPP_TAG_ZERO
);
3268 con
->response
->request
.status
.status_code
= IPP_OK
;
3273 * 'get_printers()' - Get a list of printers or classes.
3277 get_printers(client_t
*con
, /* I - Client connection */
3278 int type
) /* I - 0 or CUPS_PRINTER_CLASS */
3280 ipp_attribute_t
*attr
, /* Current attribute */
3281 *requested
; /* Requested attributes */
3282 int limit
; /* Maximum number of printers to return */
3283 int count
; /* Number of printers that match */
3284 printer_t
*printer
; /* Current printer pointer */
3285 time_t curtime
; /* Current time */
3286 int printer_type
, /* printer-type attribute */
3287 printer_mask
; /* printer-type-mask attribute */
3288 char *location
; /* Location string */
3289 char name
[IPP_MAX_NAME
],
3291 *nameptr
; /* Pointer into name */
3292 printer_t
*iclass
; /* Implicit class */
3295 LogMessage(L_DEBUG2
, "get_printers(%d, %x)\n", con
->http
.fd
, type
);
3298 * See if they want to limit the number of printers reported...
3301 if ((attr
= ippFindAttribute(con
->request
, "limit", IPP_TAG_INTEGER
)) != NULL
)
3302 limit
= attr
->values
[0].integer
;
3307 * Support filtering...
3310 if ((attr
= ippFindAttribute(con
->request
, "printer-type", IPP_TAG_ENUM
)) != NULL
)
3311 printer_type
= attr
->values
[0].integer
;
3315 if ((attr
= ippFindAttribute(con
->request
, "printer-type-mask", IPP_TAG_ENUM
)) != NULL
)
3316 printer_mask
= attr
->values
[0].integer
;
3320 if ((attr
= ippFindAttribute(con
->request
, "location", IPP_TAG_TEXT
)) != NULL
)
3321 location
= attr
->values
[0].string
.text
;
3325 requested
= ippFindAttribute(con
->request
, "requested-attributes",
3329 * OK, build a list of printers for this printer...
3332 curtime
= time(NULL
);
3334 for (count
= 0, printer
= Printers
;
3335 count
< limit
&& printer
!= NULL
;
3336 printer
= printer
->next
)
3337 if ((printer
->type
& CUPS_PRINTER_CLASS
) == type
&&
3338 (printer
->type
& printer_mask
) == printer_type
&&
3339 (location
== NULL
|| strcasecmp(printer
->location
, location
) == 0))
3342 * If HideImplicitMembers is enabled, see if this printer or class
3343 * is a member of an implicit class...
3346 if (ImplicitClasses
&& HideImplicitMembers
&&
3347 (printer
->type
& CUPS_PRINTER_REMOTE
))
3350 * Make a copy of the printer name...
3352 * Note: name and printer->name are both IPP_MAX_NAME characters
3353 * in size, so strcpy() is safe...
3356 strcpy(name
, printer
->name
);
3358 if ((nameptr
= strchr(name
, '@')) != NULL
)
3361 * Strip trailing @server...
3367 * Find the core printer, if any...
3370 if ((iclass
= FindPrinter(name
)) != NULL
&&
3371 (iclass
->type
& CUPS_PRINTER_IMPLICIT
))
3377 * Add the group separator as needed...
3381 ippAddSeparator(con
->response
);
3386 * Send the following attributes for each printer:
3389 * printer-state-message
3390 * printer-is-accepting-jobs
3391 * + all printer attributes
3394 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
3395 "printer-state", printer
->state
);
3397 add_printer_state_reasons(con
, printer
);
3399 if (printer
->state_message
[0])
3400 ippAddString(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
3401 "printer-state-message", NULL
, printer
->state_message
);
3403 ippAddBoolean(con
->response
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
3404 printer
->accepting
);
3406 ippAddInteger(con
->response
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
3407 "printer-up-time", curtime
);
3408 ippAddDate(con
->response
, IPP_TAG_PRINTER
, "printer-current-time",
3409 ippTimeToDate(curtime
));
3411 add_queued_job_count(con
, printer
);
3413 copy_attrs(con
->response
, printer
->attrs
, requested
, IPP_TAG_ZERO
);
3416 con
->response
->request
.status
.status_code
= IPP_OK
;
3421 * 'hold_job()' - Hold a print job.
3425 hold_job(client_t
*con
, /* I - Client connection */
3426 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
3428 ipp_attribute_t
*attr
, /* Current job-hold-until */
3429 *newattr
; /* New job-hold-until */
3430 int jobid
; /* Job ID */
3431 char method
[HTTP_MAX_URI
],
3432 /* Method portion of URI */
3433 username
[HTTP_MAX_URI
],
3434 /* Username portion of URI */
3436 /* Host portion of URI */
3437 resource
[HTTP_MAX_URI
];
3438 /* Resource portion of URI */
3439 int port
; /* Port portion of URI */
3440 job_t
*job
; /* Job information */
3443 LogMessage(L_DEBUG2
, "hold_job(%d, %s)\n", con
->http
.fd
,
3444 uri
->values
[0].string
.text
);
3447 * Verify that the POST operation was done to a valid URI.
3450 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3451 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
3452 strncmp(con
->uri
, "/printers/", 10) != 0)
3454 LogMessage(L_ERROR
, "hold_job: hold request on bad resource \'%s\'!",
3456 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3461 * See if we have a job URI or a printer URI...
3464 if (strcmp(uri
->name
, "printer-uri") == 0)
3467 * Got a printer URI; see if we also have a job-id attribute...
3470 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3472 LogMessage(L_ERROR
, "hold_job: got a printer-uri attribute but no job-id!");
3473 send_ipp_error(con
, IPP_BAD_REQUEST
);
3477 jobid
= attr
->values
[0].integer
;
3482 * Got a job URI; parse it to get the job ID...
3485 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3487 if (strncmp(resource
, "/jobs/", 6) != 0)
3493 LogMessage(L_ERROR
, "hold_job: bad job-uri attribute \'%s\'!",
3494 uri
->values
[0].string
.text
);
3495 send_ipp_error(con
, IPP_BAD_REQUEST
);
3499 jobid
= atoi(resource
+ 6);
3503 * See if the job exists...
3506 if ((job
= FindJob(jobid
)) == NULL
)
3509 * Nope - return a "not found" error...
3512 LogMessage(L_ERROR
, "hold_job: job #%d doesn't exist!", jobid
);
3513 send_ipp_error(con
, IPP_NOT_FOUND
);
3518 * See if the job is owned by the requesting user...
3521 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
3523 LogMessage(L_ERROR
, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
3524 username
, jobid
, job
->username
);
3525 send_ipp_error(con
, IPP_FORBIDDEN
);
3530 * Hold the job and return...
3535 if ((newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3536 newattr
= ippFindAttribute(con
->request
, "job-hold-until", IPP_TAG_NAME
);
3538 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
3539 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
3544 * Free the old hold value and copy the new one over...
3547 free(attr
->values
[0].string
.text
);
3549 if (newattr
!= NULL
)
3551 attr
->value_tag
= newattr
->value_tag
;
3552 attr
->values
[0].string
.text
= strdup(newattr
->values
[0].string
.text
);
3556 attr
->value_tag
= IPP_TAG_KEYWORD
;
3557 attr
->values
[0].string
.text
= strdup("indefinite");
3561 * Hold job until specified time...
3564 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
3567 LogMessage(L_INFO
, "Job %d was held by \'%s\'.", jobid
, username
);
3569 con
->response
->request
.status
.status_code
= IPP_OK
;
3574 * 'move_job()' - Move a job to a new destination.
3578 move_job(client_t
*con
, /* I - Client connection */
3579 ipp_attribute_t
*uri
) /* I - Job URI */
3581 ipp_attribute_t
*attr
; /* Current attribute */
3582 int jobid
; /* Job ID */
3583 job_t
*job
; /* Current job */
3584 const char *dest
; /* Destination */
3585 cups_ptype_t dtype
; /* Destination type (printer or class) */
3586 char method
[HTTP_MAX_URI
],
3587 /* Method portion of URI */
3588 username
[HTTP_MAX_URI
],
3589 /* Username portion of URI */
3591 /* Host portion of URI */
3592 resource
[HTTP_MAX_URI
];
3593 /* Resource portion of URI */
3594 int port
; /* Port portion of URI */
3597 LogMessage(L_DEBUG2
, "move_job(%d, %s)\n", con
->http
.fd
,
3598 uri
->values
[0].string
.text
);
3601 * See if we have a job URI or a printer URI...
3604 if (strcmp(uri
->name
, "printer-uri") == 0)
3607 * Got a printer URI; see if we also have a job-id attribute...
3610 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
3612 LogMessage(L_ERROR
, "move_job: got a printer-uri attribute but no job-id!");
3613 send_ipp_error(con
, IPP_BAD_REQUEST
);
3617 jobid
= attr
->values
[0].integer
;
3622 * Got a job URI; parse it to get the job ID...
3625 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3627 if (strncmp(resource
, "/jobs/", 6) != 0)
3633 LogMessage(L_ERROR
, "move_job: bad job-uri attribute \'%s\'!\n",
3634 uri
->values
[0].string
.text
);
3635 send_ipp_error(con
, IPP_BAD_REQUEST
);
3639 jobid
= atoi(resource
+ 6);
3643 * See if the job exists...
3646 if ((job
= FindJob(jobid
)) == NULL
)
3649 * Nope - return a "not found" error...
3652 LogMessage(L_ERROR
, "move_job: job #%d doesn't exist!", jobid
);
3653 send_ipp_error(con
, IPP_NOT_FOUND
);
3658 * See if the job has been completed...
3661 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
3664 * Return a "not-possible" error...
3667 LogMessage(L_ERROR
, "move_job: job #%d is finished and cannot be altered!", jobid
);
3668 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3673 * See if the job is owned by the requesting user...
3676 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
3678 LogMessage(L_ERROR
, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
3679 username
, jobid
, job
->username
);
3680 send_ipp_error(con
, IPP_FORBIDDEN
);
3684 if ((attr
= ippFindAttribute(con
->request
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
3687 * Need job-printer-uri...
3690 LogMessage(L_ERROR
, "move_job: job-printer-uri attribute missing!");
3691 send_ipp_error(con
, IPP_BAD_REQUEST
);
3696 * Move the job to a different printer or class...
3699 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
, &port
,
3701 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3707 LogMessage(L_ERROR
, "move_job: resource name \'%s\' no good!", resource
);
3708 send_ipp_error(con
, IPP_NOT_FOUND
);
3712 MoveJob(jobid
, dest
);
3715 * Start jobs if possible...
3721 * Return with "everything is OK" status...
3724 con
->response
->request
.status
.status_code
= IPP_OK
;
3729 * 'print_job()' - Print a file to a printer or class.
3733 print_job(client_t
*con
, /* I - Client connection */
3734 ipp_attribute_t
*uri
) /* I - Printer URI */
3736 ipp_attribute_t
*attr
; /* Current attribute */
3737 ipp_attribute_t
*format
; /* Document-format attribute */
3738 const char *dest
; /* Destination */
3739 cups_ptype_t dtype
; /* Destination type (printer or class) */
3740 int priority
; /* Job priority */
3741 char *title
; /* Job name/title */
3742 job_t
*job
; /* Current job */
3743 char job_uri
[HTTP_MAX_URI
],
3745 printer_uri
[HTTP_MAX_URI
],
3747 method
[HTTP_MAX_URI
],
3748 /* Method portion of URI */
3749 username
[HTTP_MAX_URI
],
3750 /* Username portion of URI */
3752 /* Host portion of URI */
3753 resource
[HTTP_MAX_URI
],
3754 /* Resource portion of URI */
3755 filename
[1024]; /* Job filename */
3756 int port
; /* Port portion of URI */
3757 mime_type_t
*filetype
; /* Type of file */
3758 char super
[MIME_MAX_SUPER
],
3759 /* Supertype of file */
3760 type
[MIME_MAX_TYPE
],
3761 /* Subtype of file */
3762 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
3763 /* Textual name of mime type */
3764 printer_t
*printer
; /* Printer data */
3765 struct stat fileinfo
; /* File information */
3766 int kbytes
; /* Size of file */
3769 LogMessage(L_DEBUG2
, "print_job(%d, %s)\n", con
->http
.fd
,
3770 uri
->values
[0].string
.text
);
3773 * Verify that the POST operation was done to a valid URI.
3776 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
3777 strncmp(con
->uri
, "/printers/", 10) != 0)
3779 LogMessage(L_ERROR
, "print_job: cancel request on bad resource \'%s\'!",
3781 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
3786 * OK, see if the client is sending the document compressed - CUPS
3787 * doesn't support compression yet...
3790 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
3791 strcmp(attr
->values
[0].string
.text
, "none") == 0)
3793 LogMessage(L_ERROR
, "print_job: Unsupported compression attribute %s!",
3794 attr
->values
[0].string
.text
);
3795 send_ipp_error(con
, IPP_ATTRIBUTES
);
3796 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
3797 "compression", NULL
, attr
->values
[0].string
.text
);
3802 * Do we have a file to print?
3805 if (con
->filename
[0] == '\0')
3807 LogMessage(L_ERROR
, "print_job: No file!?!");
3808 send_ipp_error(con
, IPP_BAD_REQUEST
);
3813 * Is it a format we support?
3816 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
3819 * Grab format from client...
3822 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
3824 LogMessage(L_ERROR
, "print_job: could not scan type \'%s\'!",
3825 format
->values
[0].string
.text
);
3826 send_ipp_error(con
, IPP_BAD_REQUEST
);
3833 * No document format attribute? Auto-type it!
3836 strcpy(super
, "application");
3837 strcpy(type
, "octet-stream");
3840 if (strcmp(super
, "application") == 0 &&
3841 strcmp(type
, "octet-stream") == 0)
3844 * Auto-type the file...
3847 LogMessage(L_DEBUG
, "print_job: auto-typing file...");
3849 filetype
= mimeFileType(MimeDatabase
, con
->filename
);
3851 if (filetype
!= NULL
)
3854 * Replace the document-format attribute value with the auto-typed one.
3857 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
3862 free(format
->values
[0].string
.text
);
3863 format
->values
[0].string
.text
= strdup(mimetype
);
3866 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
3867 "document-format", NULL
, mimetype
);
3870 filetype
= mimeType(MimeDatabase
, super
, type
);
3873 filetype
= mimeType(MimeDatabase
, super
, type
);
3875 if (filetype
== NULL
)
3877 LogMessage(L_ERROR
, "print_job: Unsupported format \'%s/%s\'!",
3879 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
3882 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
3883 "document-format", NULL
, format
->values
[0].string
.text
);
3888 LogMessage(L_DEBUG
, "print_job: request file type is %s/%s.",
3889 filetype
->super
, filetype
->type
);
3892 * Is the destination valid?
3895 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
3897 if ((dest
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
3903 LogMessage(L_ERROR
, "print_job: resource name \'%s\' no good!", resource
);
3904 send_ipp_error(con
, IPP_NOT_FOUND
);
3909 * See if the printer is accepting jobs...
3912 if (dtype
== CUPS_PRINTER_CLASS
)
3914 printer
= FindClass(dest
);
3916 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
3917 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
3918 ServerName
, ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), dest
);
3920 #endif /* AF_INET6 */
3921 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/classes/%s",
3922 ServerName
, ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), dest
);
3926 printer
= FindPrinter(dest
);
3929 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
3930 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
3931 ServerName
, ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), dest
);
3933 #endif /* AF_INET6 */
3934 snprintf(printer_uri
, sizeof(printer_uri
), "http://%s:%d/printers/%s",
3935 ServerName
, ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), dest
);
3938 if (!printer
->accepting
)
3940 LogMessage(L_INFO
, "print_job: destination \'%s\' is not accepting jobs.",
3942 send_ipp_error(con
, IPP_NOT_ACCEPTING
);
3947 * Make sure we aren't over our limit...
3950 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3953 if (NumJobs
>= MaxJobs
&& MaxJobs
)
3955 LogMessage(L_INFO
, "print_job: too many jobs.");
3956 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3960 if (!check_quotas(con
, printer
))
3962 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
3967 * Create the job and set things up...
3970 if ((attr
= ippFindAttribute(con
->request
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
3971 priority
= attr
->values
[0].integer
;
3973 ippAddInteger(con
->request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
3976 if ((attr
= ippFindAttribute(con
->request
, "job-name", IPP_TAG_NAME
)) != NULL
)
3977 title
= attr
->values
[0].string
.text
;
3979 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
3980 title
= "Untitled");
3982 if ((job
= AddJob(priority
, printer
->name
)) == NULL
)
3984 LogMessage(L_ERROR
, "print_job: unable to add job for destination \'%s\'!",
3986 send_ipp_error(con
, IPP_INTERNAL_ERROR
);
3991 job
->attrs
= con
->request
;
3992 con
->request
= NULL
;
3995 * Copy the rest of the job info...
3998 strncpy(job
->title
, title
, sizeof(job
->title
) - 1);
4000 attr
= ippFindAttribute(job
->attrs
, "requesting-user-name", IPP_TAG_NAME
);
4002 if (con
->username
[0])
4004 strncpy(job
->username
, con
->username
, sizeof(job
->username
) - 1);
4005 job
->username
[sizeof(job
->username
) - 1] = '\0';
4009 LogMessage(L_DEBUG
, "print_job: requesting-user-name = \'%s\'",
4010 attr
->values
[0].string
.text
);
4012 strncpy(job
->username
, attr
->values
[0].string
.text
, sizeof(job
->username
) - 1);
4013 job
->username
[sizeof(job
->username
) - 1] = '\0';
4016 strcpy(job
->username
, "anonymous");
4019 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-originating-user-name",
4020 NULL
, job
->username
);
4023 attr
->group_tag
= IPP_TAG_JOB
;
4025 attr
->name
= strdup("job-originating-user-name");
4029 * Add remaining job attributes...
4032 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
,
4033 "job-originating-host-name", NULL
, con
->http
.hostname
);
4034 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4035 job
->state
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_ENUM
,
4036 "job-state", IPP_JOB_PENDING
);
4037 job
->sheets
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4038 "job-media-sheets-completed", 0);
4039 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-printer-uri", NULL
,
4041 ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-name", NULL
,
4044 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) == NULL
)
4045 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4048 if (stat(con
->filename
, &fileinfo
))
4051 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
4053 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4054 attr
->values
[0].integer
+= kbytes
;
4056 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "time-at-creation",
4058 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4059 "time-at-processing", 0);
4060 attr
->value_tag
= IPP_TAG_NOVALUE
;
4061 attr
= ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
,
4062 "time-at-completed", 0);
4063 attr
->value_tag
= IPP_TAG_NOVALUE
;
4065 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4066 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4068 attr
= ippAddString(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
,
4069 "job-hold-until", NULL
, "no-hold");
4071 if (attr
!= NULL
&& strcmp(attr
->values
[0].string
.text
, "no-hold") != 0 &&
4072 !(printer
->type
& CUPS_PRINTER_REMOTE
))
4075 * Hold job until specified time...
4078 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
4079 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
4082 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) || Classification
[0])
4085 * Add job sheets options...
4088 if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) == NULL
)
4090 LogMessage(L_DEBUG
, "Adding default job-sheets values \"%s,%s\"...",
4091 printer
->job_sheets
[0], printer
->job_sheets
[1]);
4093 attr
= ippAddStrings(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-sheets",
4095 attr
->values
[0].string
.text
= strdup(printer
->job_sheets
[0]);
4096 attr
->values
[1].string
.text
= strdup(printer
->job_sheets
[1]);
4099 job
->job_sheets
= attr
;
4102 * Enforce classification level if set...
4105 if (Classification
[0])
4107 if (ClassifyOverride
)
4109 if (strcmp(attr
->values
[0].string
.text
, "none") == 0 &&
4110 (attr
->num_values
== 1 ||
4111 strcmp(attr
->values
[1].string
.text
, "none") == 0))
4114 * Force the leading banner to have the classification on it...
4117 free(attr
->values
[0].string
.text
);
4118 attr
->values
[0].string
.text
= strdup(Classification
);
4120 else if (attr
->num_values
== 2 &&
4121 strcmp(attr
->values
[0].string
.text
, attr
->values
[1].string
.text
) != 0 &&
4122 strcmp(attr
->values
[0].string
.text
, "none") != 0 &&
4123 strcmp(attr
->values
[1].string
.text
, "none") != 0)
4126 * Can't put two different security markings on the same document!
4129 free(attr
->values
[1].string
.text
);
4130 attr
->values
[1].string
.text
= strdup(attr
->values
[0].string
.text
);
4133 else if (strcmp(attr
->values
[0].string
.text
, Classification
) != 0 &&
4134 (attr
->num_values
== 1 ||
4135 strcmp(attr
->values
[1].string
.text
, Classification
) != 0))
4138 * Force the leading banner to have the classification on it...
4141 free(attr
->values
[0].string
.text
);
4142 attr
->values
[0].string
.text
= strdup(Classification
);
4147 * Add the starting sheet...
4150 kbytes
= copy_banner(con
, job
, attr
->values
[0].string
.text
);
4152 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4154 else if ((attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
4158 * Add the job file...
4161 if (add_file(con
, job
, filetype
))
4164 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
4166 rename(con
->filename
, filename
);
4167 con
->filename
[0] = '\0';
4170 * See if we need to add the ending sheet...
4173 if (!(printer
->type
& CUPS_PRINTER_REMOTE
) && attr
->num_values
> 1)
4179 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
4180 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4184 * Log and save the job...
4187 LogMessage(L_INFO
, "Job %d queued on \'%s\' by \'%s\'.", job
->id
,
4188 job
->dest
, job
->username
);
4189 LogMessage(L_DEBUG
, "Job %d hold_until = %d", job
->id
, job
->hold_until
);
4194 * Start the job if possible...
4200 * Fill in the response info...
4204 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
4205 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4206 ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), job
->id
);
4208 #endif /* AF_INET6 */
4209 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4210 ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), job
->id
);
4212 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
, job_uri
);
4214 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4216 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
4217 job
->state
->values
[0].integer
);
4218 add_job_state_reasons(con
, job
);
4220 con
->response
->request
.status
.status_code
= IPP_OK
;
4225 * 'reject_jobs()' - Reject print jobs to a printer.
4229 reject_jobs(client_t
*con
, /* I - Client connection */
4230 ipp_attribute_t
*uri
) /* I - Printer or class URI */
4232 cups_ptype_t dtype
; /* Destination type (printer or class) */
4233 char method
[HTTP_MAX_URI
],
4234 /* Method portion of URI */
4235 username
[HTTP_MAX_URI
],
4236 /* Username portion of URI */
4238 /* Host portion of URI */
4239 resource
[HTTP_MAX_URI
];
4240 /* Resource portion of URI */
4241 int port
; /* Port portion of URI */
4242 const char *name
; /* Printer name */
4243 printer_t
*printer
; /* Printer data */
4244 ipp_attribute_t
*attr
; /* printer-state-message text */
4247 LogMessage(L_DEBUG2
, "reject_jobs(%d, %s)\n", con
->http
.fd
,
4248 uri
->values
[0].string
.text
);
4251 * Was this operation called from the correct URI?
4254 if (strncmp(con
->uri
, "/admin/", 7) != 0)
4256 LogMessage(L_ERROR
, "reject_jobs: admin request on bad resource \'%s\'!",
4258 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4263 * Is the destination valid?
4266 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4268 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
4274 LogMessage(L_ERROR
, "reject_jobs: resource name \'%s\' no good!", resource
);
4275 send_ipp_error(con
, IPP_NOT_FOUND
);
4280 * Reject jobs sent to the printer...
4283 if (dtype
== CUPS_PRINTER_CLASS
)
4284 printer
= FindClass(name
);
4286 printer
= FindPrinter(name
);
4288 printer
->accepting
= 0;
4290 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
4291 IPP_TAG_TEXT
)) == NULL
)
4292 strcpy(printer
->state_message
, "Rejecting Jobs");
4295 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
4296 sizeof(printer
->state_message
) - 1);
4297 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
4300 if (dtype
== CUPS_PRINTER_CLASS
)
4305 if (dtype
== CUPS_PRINTER_CLASS
)
4306 LogMessage(L_INFO
, "Class \'%s\' rejecting jobs (\'%s\').", name
,
4309 LogMessage(L_INFO
, "Printer \'%s\' rejecting jobs (\'%s\').", name
,
4313 * Everything was ok, so return OK status...
4316 con
->response
->request
.status
.status_code
= IPP_OK
;
4321 * 'release_job()' - Release a held print job.
4325 release_job(client_t
*con
, /* I - Client connection */
4326 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4328 ipp_attribute_t
*attr
; /* Current attribute */
4329 int jobid
; /* Job ID */
4330 char method
[HTTP_MAX_URI
],
4331 /* Method portion of URI */
4332 username
[HTTP_MAX_URI
],
4333 /* Username portion of URI */
4335 /* Host portion of URI */
4336 resource
[HTTP_MAX_URI
];
4337 /* Resource portion of URI */
4338 int port
; /* Port portion of URI */
4339 job_t
*job
; /* Job information */
4342 LogMessage(L_DEBUG2
, "release_job(%d, %s)\n", con
->http
.fd
,
4343 uri
->values
[0].string
.text
);
4346 * Verify that the POST operation was done to a valid URI.
4349 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4350 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4351 strncmp(con
->uri
, "/printers/", 10) != 0)
4353 LogMessage(L_ERROR
, "release_job: release request on bad resource \'%s\'!",
4355 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4360 * See if we have a job URI or a printer URI...
4363 if (strcmp(uri
->name
, "printer-uri") == 0)
4366 * Got a printer URI; see if we also have a job-id attribute...
4369 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4371 LogMessage(L_ERROR
, "release_job: got a printer-uri attribute but no job-id!");
4372 send_ipp_error(con
, IPP_BAD_REQUEST
);
4376 jobid
= attr
->values
[0].integer
;
4381 * Got a job URI; parse it to get the job ID...
4384 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4386 if (strncmp(resource
, "/jobs/", 6) != 0)
4392 LogMessage(L_ERROR
, "release_job: bad job-uri attribute \'%s\'!",
4393 uri
->values
[0].string
.text
);
4394 send_ipp_error(con
, IPP_BAD_REQUEST
);
4398 jobid
= atoi(resource
+ 6);
4402 * See if the job exists...
4405 if ((job
= FindJob(jobid
)) == NULL
)
4408 * Nope - return a "not found" error...
4411 LogMessage(L_ERROR
, "release_job: job #%d doesn't exist!", jobid
);
4412 send_ipp_error(con
, IPP_NOT_FOUND
);
4417 * See if job is "held"...
4420 if (job
->state
->values
[0].integer
!= IPP_JOB_HELD
)
4423 * Nope - return a "not possible" error...
4426 LogMessage(L_ERROR
, "release_job: job #%d is not held!", jobid
);
4427 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4432 * See if the job is owned by the requesting user...
4435 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4437 LogMessage(L_ERROR
, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
4438 username
, jobid
, job
->username
);
4439 send_ipp_error(con
, IPP_FORBIDDEN
);
4444 * Reset the job-hold-until value to "no-hold"...
4447 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4448 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4452 free(attr
->values
[0].string
.text
);
4453 attr
->value_tag
= IPP_TAG_KEYWORD
;
4454 attr
->values
[0].string
.text
= strdup("no-hold");
4458 * Release the job and return...
4463 LogMessage(L_INFO
, "Job %d was released by \'%s\'.", jobid
, username
);
4465 con
->response
->request
.status
.status_code
= IPP_OK
;
4470 * 'restart_job()' - Restart an old print job.
4474 restart_job(client_t
*con
, /* I - Client connection */
4475 ipp_attribute_t
*uri
) /* I - Job or Printer URI */
4477 ipp_attribute_t
*attr
; /* Current attribute */
4478 int jobid
; /* Job ID */
4479 char method
[HTTP_MAX_URI
],
4480 /* Method portion of URI */
4481 username
[HTTP_MAX_URI
],
4482 /* Username portion of URI */
4484 /* Host portion of URI */
4485 resource
[HTTP_MAX_URI
];
4486 /* Resource portion of URI */
4487 int port
; /* Port portion of URI */
4488 job_t
*job
; /* Job information */
4491 LogMessage(L_DEBUG2
, "restart_job(%d, %s)\n", con
->http
.fd
,
4492 uri
->values
[0].string
.text
);
4495 * Verify that the POST operation was done to a valid URI.
4498 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4499 strncmp(con
->uri
, "/jobs/", 5) != 0 &&
4500 strncmp(con
->uri
, "/printers/", 10) != 0)
4502 LogMessage(L_ERROR
, "restart_job: restart request on bad resource \'%s\'!",
4504 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4509 * See if we have a job URI or a printer URI...
4512 if (strcmp(uri
->name
, "printer-uri") == 0)
4515 * Got a printer URI; see if we also have a job-id attribute...
4518 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4520 LogMessage(L_ERROR
, "restart_job: got a printer-uri attribute but no job-id!");
4521 send_ipp_error(con
, IPP_BAD_REQUEST
);
4525 jobid
= attr
->values
[0].integer
;
4530 * Got a job URI; parse it to get the job ID...
4533 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4535 if (strncmp(resource
, "/jobs/", 6) != 0)
4541 LogMessage(L_ERROR
, "restart_job: bad job-uri attribute \'%s\'!",
4542 uri
->values
[0].string
.text
);
4543 send_ipp_error(con
, IPP_BAD_REQUEST
);
4547 jobid
= atoi(resource
+ 6);
4551 * See if the job exists...
4554 if ((job
= FindJob(jobid
)) == NULL
)
4557 * Nope - return a "not found" error...
4560 LogMessage(L_ERROR
, "restart_job: job #%d doesn't exist!", jobid
);
4561 send_ipp_error(con
, IPP_NOT_FOUND
);
4566 * See if job is in any of the "completed" states...
4569 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
4572 * Nope - return a "not possible" error...
4575 LogMessage(L_ERROR
, "restart_job: job #%d is not complete!", jobid
);
4576 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4581 * See if we have retained the job files...
4584 if (!JobFiles
&& job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
4587 * Nope - return a "not possible" error...
4590 LogMessage(L_ERROR
, "restart_job: job #%d cannot be restarted - no files!", jobid
);
4591 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
4596 * See if the job is owned by the requesting user...
4599 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4601 LogMessage(L_ERROR
, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
4602 username
, jobid
, job
->username
);
4603 send_ipp_error(con
, IPP_FORBIDDEN
);
4608 * Restart the job and return...
4613 LogMessage(L_INFO
, "Job %d was restarted by \'%s\'.", jobid
, username
);
4615 con
->response
->request
.status
.status_code
= IPP_OK
;
4620 * 'send_document()' - Send a file to a printer or class.
4624 send_document(client_t
*con
, /* I - Client connection */
4625 ipp_attribute_t
*uri
) /* I - Printer URI */
4627 ipp_attribute_t
*attr
; /* Current attribute */
4628 ipp_attribute_t
*format
; /* Document-format attribute */
4629 int jobid
; /* Job ID number */
4630 job_t
*job
; /* Current job */
4631 char job_uri
[HTTP_MAX_URI
],
4633 method
[HTTP_MAX_URI
],
4634 /* Method portion of URI */
4635 username
[HTTP_MAX_URI
],
4636 /* Username portion of URI */
4638 /* Host portion of URI */
4639 resource
[HTTP_MAX_URI
];
4640 /* Resource portion of URI */
4641 int port
; /* Port portion of URI */
4642 mime_type_t
*filetype
; /* Type of file */
4643 char super
[MIME_MAX_SUPER
],
4644 /* Supertype of file */
4645 type
[MIME_MAX_TYPE
],
4646 /* Subtype of file */
4647 mimetype
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2];
4648 /* Textual name of mime type */
4649 char filename
[1024]; /* Job filename */
4650 printer_t
*printer
; /* Current printer */
4651 struct stat fileinfo
; /* File information */
4652 int kbytes
; /* Size of file */
4655 LogMessage(L_DEBUG2
, "send_document(%d, %s)\n", con
->http
.fd
,
4656 uri
->values
[0].string
.text
);
4659 * Verify that the POST operation was done to a valid URI.
4662 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
4663 strncmp(con
->uri
, "/jobs/", 6) != 0 &&
4664 strncmp(con
->uri
, "/printers/", 10) != 0)
4666 LogMessage(L_ERROR
, "send_document: print request on bad resource \'%s\'!",
4668 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
4673 * See if we have a job URI or a printer URI...
4676 if (strcmp(uri
->name
, "printer-uri") == 0)
4679 * Got a printer URI; see if we also have a job-id attribute...
4682 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
4684 LogMessage(L_ERROR
, "send_document: got a printer-uri attribute but no job-id!");
4685 send_ipp_error(con
, IPP_BAD_REQUEST
);
4689 jobid
= attr
->values
[0].integer
;
4694 * Got a job URI; parse it to get the job ID...
4697 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
4699 if (strncmp(resource
, "/jobs/", 6) != 0)
4705 LogMessage(L_ERROR
, "send_document: bad job-uri attribute \'%s\'!",
4706 uri
->values
[0].string
.text
);
4707 send_ipp_error(con
, IPP_BAD_REQUEST
);
4711 jobid
= atoi(resource
+ 6);
4715 * See if the job exists...
4718 if ((job
= FindJob(jobid
)) == NULL
)
4721 * Nope - return a "not found" error...
4724 LogMessage(L_ERROR
, "send_document: job #%d doesn't exist!", jobid
);
4725 send_ipp_error(con
, IPP_NOT_FOUND
);
4730 * See if the job is owned by the requesting user...
4733 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
4735 LogMessage(L_ERROR
, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
4736 username
, jobid
, job
->username
);
4737 send_ipp_error(con
, IPP_FORBIDDEN
);
4742 * OK, see if the client is sending the document compressed - CUPS
4743 * doesn't support compression yet...
4746 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
4747 strcmp(attr
->values
[0].string
.text
, "none") == 0)
4749 LogMessage(L_ERROR
, "send_document: Unsupported compression attribute %s!",
4750 attr
->values
[0].string
.text
);
4751 send_ipp_error(con
, IPP_ATTRIBUTES
);
4752 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
4753 "compression", NULL
, attr
->values
[0].string
.text
);
4758 * Do we have a file to print?
4761 if (con
->filename
[0] == '\0')
4763 LogMessage(L_ERROR
, "send_document: No file!?!");
4764 send_ipp_error(con
, IPP_BAD_REQUEST
);
4769 * Is it a format we support?
4772 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
4775 * Grab format from client...
4778 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
4780 LogMessage(L_ERROR
, "send_document: could not scan type \'%s\'!",
4781 format
->values
[0].string
.text
);
4782 send_ipp_error(con
, IPP_BAD_REQUEST
);
4789 * No document format attribute? Auto-type it!
4792 strcpy(super
, "application");
4793 strcpy(type
, "octet-stream");
4796 if (strcmp(super
, "application") == 0 &&
4797 strcmp(type
, "octet-stream") == 0)
4800 * Auto-type the file...
4803 LogMessage(L_DEBUG
, "send_document: auto-typing file...");
4805 filetype
= mimeFileType(MimeDatabase
, con
->filename
);
4807 if (filetype
!= NULL
)
4810 * Replace the document-format attribute value with the auto-typed one.
4813 snprintf(mimetype
, sizeof(mimetype
), "%s/%s", filetype
->super
,
4818 free(format
->values
[0].string
.text
);
4819 format
->values
[0].string
.text
= strdup(mimetype
);
4822 ippAddString(con
->request
, IPP_TAG_JOB
, IPP_TAG_MIMETYPE
,
4823 "document-format", NULL
, mimetype
);
4826 filetype
= mimeType(MimeDatabase
, super
, type
);
4829 filetype
= mimeType(MimeDatabase
, super
, type
);
4831 if (filetype
== NULL
)
4833 LogMessage(L_ERROR
, "send_document: Unsupported format \'%s/%s\'!",
4835 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
4838 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
4839 "document-format", NULL
, format
->values
[0].string
.text
);
4844 LogMessage(L_DEBUG
, "send_document: request file type is %s/%s.",
4845 filetype
->super
, filetype
->type
);
4848 * Add the file to the job...
4851 if (add_file(con
, job
, filetype
))
4854 if (job
->dtype
& CUPS_PRINTER_CLASS
)
4855 printer
= FindClass(job
->dest
);
4857 printer
= FindPrinter(job
->dest
);
4859 if (stat(con
->filename
, &fileinfo
))
4862 kbytes
= (fileinfo
.st_size
+ 1023) / 1024;
4864 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4866 if ((attr
= ippFindAttribute(job
->attrs
, "job-k-octets", IPP_TAG_INTEGER
)) != NULL
)
4867 attr
->values
[0].integer
+= kbytes
;
4869 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
, job
->id
,
4871 rename(con
->filename
, filename
);
4873 con
->filename
[0] = '\0';
4875 LogMessage(L_INFO
, "File of type %s/%s queued in job #%d by \'%s\'.",
4876 filetype
->super
, filetype
->type
, job
->id
, job
->username
);
4879 * Start the job if this is the last document...
4882 if ((attr
= ippFindAttribute(con
->request
, "last-document", IPP_TAG_BOOLEAN
)) != NULL
&&
4883 attr
->values
[0].boolean
)
4886 * See if we need to add the ending sheet...
4889 if (printer
!= NULL
&& !(printer
->type
& CUPS_PRINTER_REMOTE
) &&
4890 (attr
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
&&
4891 attr
->num_values
> 1)
4897 kbytes
= copy_banner(con
, job
, attr
->values
[1].string
.text
);
4898 UpdateQuota(printer
, job
->username
, 0, kbytes
);
4901 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
)
4902 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
4903 else if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
4905 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4906 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4908 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
4909 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
4917 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
4918 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
4920 if (attr
== NULL
|| strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
4922 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
4923 job
->hold_until
= time(NULL
) + 60;
4929 * Fill in the response info...
4933 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
4934 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4935 ntohs(con
->http
.hostaddr
.ipv6
.sin6_port
), job
->id
);
4937 #endif /* AF_INET6 */
4938 snprintf(job_uri
, sizeof(job_uri
), "http://%s:%d/jobs/%d", ServerName
,
4939 ntohs(con
->http
.hostaddr
.ipv4
.sin_port
), job
->id
);
4941 ippAddString(con
->response
, IPP_TAG_JOB
, IPP_TAG_URI
, "job-uri", NULL
,
4944 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-id", job
->id
);
4946 ippAddInteger(con
->response
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "job-state",
4947 job
->state
->values
[0].integer
);
4948 add_job_state_reasons(con
, job
);
4950 con
->response
->request
.status
.status_code
= IPP_OK
;
4955 * 'send_ipp_error()' - Send an error status back to the IPP client.
4959 send_ipp_error(client_t
*con
, /* I - Client connection */
4960 ipp_status_t status
) /* I - IPP status code */
4962 LogMessage(L_DEBUG2
, "send_ipp_error(%d, %x)\n", con
->http
.fd
, status
);
4964 LogMessage(L_DEBUG
, "Sending error: %s", ippErrorString(status
));
4966 con
->response
->request
.status
.status_code
= status
;
4968 if (ippFindAttribute(con
->response
, "attributes-charset", IPP_TAG_ZERO
) == NULL
)
4969 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
4970 "attributes-charset", NULL
, DefaultCharset
);
4972 if (ippFindAttribute(con
->response
, "attributes-natural-language",
4973 IPP_TAG_ZERO
) == NULL
)
4974 ippAddString(con
->response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
4975 "attributes-natural-language", NULL
, DefaultLanguage
);
4980 * 'set_default()' - Set the default destination...
4984 set_default(client_t
*con
, /* I - Client connection */
4985 ipp_attribute_t
*uri
) /* I - Printer URI */
4987 cups_ptype_t dtype
; /* Destination type (printer or class) */
4988 char method
[HTTP_MAX_URI
],
4989 /* Method portion of URI */
4990 username
[HTTP_MAX_URI
],
4991 /* Username portion of URI */
4993 /* Host portion of URI */
4994 resource
[HTTP_MAX_URI
];
4995 /* Resource portion of URI */
4996 int port
; /* Port portion of URI */
4997 const char *name
; /* Printer name */
5000 LogMessage(L_DEBUG2
, "set_default(%d, %s)\n", con
->http
.fd
,
5001 uri
->values
[0].string
.text
);
5004 * Was this operation called from the correct URI?
5007 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5009 LogMessage(L_ERROR
, "set_default: admin request on bad resource \'%s\'!",
5011 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5016 * Is the destination valid?
5019 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5021 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
5027 LogMessage(L_ERROR
, "set_default: resource name \'%s\' no good!", resource
);
5028 send_ipp_error(con
, IPP_NOT_FOUND
);
5033 * Set it as the default...
5036 if (dtype
== CUPS_PRINTER_CLASS
)
5037 DefaultPrinter
= FindClass(name
);
5039 DefaultPrinter
= FindPrinter(name
);
5044 LogMessage(L_INFO
, "Default destination set to \'%s\' by \'%s\'.", name
,
5048 * Everything was ok, so return OK status...
5051 con
->response
->request
.status
.status_code
= IPP_OK
;
5056 * 'set_job_attrs()' - Set job attributes.
5060 set_job_attrs(client_t
*con
, /* I - Client connection */
5061 ipp_attribute_t
*uri
) /* I - Job URI */
5063 ipp_attribute_t
*attr
, /* Current attribute */
5064 *attr2
, /* Job attribute */
5065 *prev2
; /* Previous job attribute */
5066 int jobid
; /* Job ID */
5067 job_t
*job
; /* Current job */
5068 char method
[HTTP_MAX_URI
],
5069 /* Method portion of URI */
5070 username
[HTTP_MAX_URI
],
5071 /* Username portion of URI */
5073 /* Host portion of URI */
5074 resource
[HTTP_MAX_URI
];
5075 /* Resource portion of URI */
5076 int port
; /* Port portion of URI */
5079 LogMessage(L_DEBUG2
, "set_job_attrs(%d, %s)\n", con
->http
.fd
,
5080 uri
->values
[0].string
.text
);
5083 * See if we have a job URI or a printer URI...
5086 if (strcmp(uri
->name
, "printer-uri") == 0)
5089 * Got a printer URI; see if we also have a job-id attribute...
5092 if ((attr
= ippFindAttribute(con
->request
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
5094 LogMessage(L_ERROR
, "set_job_attrs: got a printer-uri attribute but no job-id!");
5095 send_ipp_error(con
, IPP_BAD_REQUEST
);
5099 jobid
= attr
->values
[0].integer
;
5104 * Got a job URI; parse it to get the job ID...
5107 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5109 if (strncmp(resource
, "/jobs/", 6) != 0)
5115 LogMessage(L_ERROR
, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
5116 uri
->values
[0].string
.text
);
5117 send_ipp_error(con
, IPP_BAD_REQUEST
);
5121 jobid
= atoi(resource
+ 6);
5125 * See if the job exists...
5128 if ((job
= FindJob(jobid
)) == NULL
)
5131 * Nope - return a "not found" error...
5134 LogMessage(L_ERROR
, "set_job_attrs: job #%d doesn't exist!", jobid
);
5135 send_ipp_error(con
, IPP_NOT_FOUND
);
5140 * See if the job has been completed...
5143 if (job
->state
->values
[0].integer
> IPP_JOB_STOPPED
)
5146 * Return a "not-possible" error...
5149 LogMessage(L_ERROR
, "set_job_attrs: job #%d is finished and cannot be altered!", jobid
);
5150 send_ipp_error(con
, IPP_NOT_POSSIBLE
);
5155 * See if the job is owned by the requesting user...
5158 if (!validate_user(con
, job
->username
, username
, sizeof(username
)))
5160 LogMessage(L_ERROR
, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
5161 username
, jobid
, job
->username
);
5162 send_ipp_error(con
, IPP_FORBIDDEN
);
5167 * See what the user wants to change.
5170 for (attr
= con
->request
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5172 if (attr
->group_tag
!= IPP_TAG_JOB
|| !attr
->name
)
5175 if (strcmp(attr
->name
, "job-originating-host-name") == 0 ||
5176 strcmp(attr
->name
, "job-originating-user-name") == 0 ||
5177 strcmp(attr
->name
, "job-media-sheets-completed") == 0 ||
5178 strcmp(attr
->name
, "job-k-octets") == 0 ||
5179 strcmp(attr
->name
, "job-id") == 0 ||
5180 strcmp(attr
->name
, "job-sheets") == 0 ||
5181 strncmp(attr
->name
, "time-at-", 8) == 0)
5182 continue; /* Read-only attrs */
5184 if (strcmp(attr
->name
, "job-priority") == 0 &&
5185 attr
->value_tag
== IPP_TAG_INTEGER
&&
5186 job
->state
->values
[0].integer
!= IPP_JOB_PROCESSING
)
5189 * Change the job priority
5192 SetJobPriority(jobid
, attr
->values
[0].integer
);
5194 else if ((attr2
= ippFindAttribute(job
->attrs
, attr
->name
, IPP_TAG_ZERO
)) != NULL
)
5197 * Some other value; first free the old value...
5200 for (prev2
= job
->attrs
->attrs
; prev2
!= NULL
; prev2
= prev2
->next
)
5201 if (prev2
->next
== attr2
)
5205 prev2
->next
= attr2
->next
;
5207 job
->attrs
->attrs
= attr2
->next
;
5209 _ipp_free_attr(attr2
);
5212 * Then copy the attribute...
5215 copy_attribute(job
->attrs
, attr
, 0);
5218 * See if the job-name or job-hold-until is being changed.
5221 if (strcmp(attr
->name
, "job-name") == 0)
5222 strncpy(job
->title
, attr
->values
[0].string
.text
, sizeof(job
->title
) - 1);
5223 else if (strcmp(attr
->name
, "job-hold-until") == 0)
5225 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
5227 if (strcmp(attr
->values
[0].string
.text
, "no-hold") == 0)
5228 ReleaseJob(job
->id
);
5233 else if (attr
->value_tag
== IPP_TAG_DELETEATTR
)
5236 * Delete the attribute...
5239 for (attr2
= job
->attrs
->attrs
, prev2
= NULL
;
5241 prev2
= attr2
, attr2
= attr2
->next
)
5242 if (attr2
->name
&& strcmp(attr2
->name
, attr
->name
) == 0)
5248 prev2
->next
= attr2
->next
;
5250 job
->attrs
->attrs
= attr2
->next
;
5252 _ipp_free_attr(attr2
);
5258 * Add new option by copying it...
5261 copy_attribute(job
->attrs
, attr
, 0);
5272 * Start jobs if possible...
5278 * Return with "everything is OK" status...
5281 con
->response
->request
.status
.status_code
= IPP_OK
;
5286 * 'start_printer()' - Start a printer.
5290 start_printer(client_t
*con
, /* I - Client connection */
5291 ipp_attribute_t
*uri
) /* I - Printer URI */
5293 cups_ptype_t dtype
; /* Destination type (printer or class) */
5294 char method
[HTTP_MAX_URI
],
5295 /* Method portion of URI */
5296 username
[HTTP_MAX_URI
],
5297 /* Username portion of URI */
5299 /* Host portion of URI */
5300 resource
[HTTP_MAX_URI
];
5301 /* Resource portion of URI */
5302 int port
; /* Port portion of URI */
5303 const char *name
; /* Printer name */
5304 printer_t
*printer
; /* Printer data */
5307 LogMessage(L_DEBUG2
, "start_printer(%d, %s)\n", con
->http
.fd
,
5308 uri
->values
[0].string
.text
);
5311 * Was this operation called from the correct URI?
5314 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5316 LogMessage(L_ERROR
, "start_printer: admin request on bad resource \'%s\'!",
5318 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5323 * Is the destination valid?
5326 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5328 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
5334 LogMessage(L_ERROR
, "start_printer: resource name \'%s\' no good!", resource
);
5335 send_ipp_error(con
, IPP_NOT_FOUND
);
5340 * Start the printer...
5343 if (dtype
== CUPS_PRINTER_CLASS
)
5344 printer
= FindClass(name
);
5346 printer
= FindPrinter(name
);
5348 StartPrinter(printer
);
5350 if (dtype
== CUPS_PRINTER_CLASS
)
5355 if (dtype
== CUPS_PRINTER_CLASS
)
5356 LogMessage(L_INFO
, "Class \'%s\' started by \'%s\'.", name
,
5359 LogMessage(L_INFO
, "Printer \'%s\' started by \'%s\'.", name
,
5362 printer
->state_message
[0] = '\0';
5367 * Everything was ok, so return OK status...
5370 con
->response
->request
.status
.status_code
= IPP_OK
;
5375 * 'stop_printer()' - Stop a printer.
5379 stop_printer(client_t
*con
, /* I - Client connection */
5380 ipp_attribute_t
*uri
) /* I - Printer URI */
5382 cups_ptype_t dtype
; /* Destination type (printer or class) */
5383 char method
[HTTP_MAX_URI
],
5384 /* Method portion of URI */
5385 username
[HTTP_MAX_URI
],
5386 /* Username portion of URI */
5388 /* Host portion of URI */
5389 resource
[HTTP_MAX_URI
];
5390 /* Resource portion of URI */
5391 int port
; /* Port portion of URI */
5392 const char *name
; /* Printer name */
5393 printer_t
*printer
; /* Printer data */
5394 ipp_attribute_t
*attr
; /* printer-state-message attribute */
5397 LogMessage(L_DEBUG2
, "stop_printer(%d, %s)\n", con
->http
.fd
,
5398 uri
->values
[0].string
.text
);
5401 * Was this operation called from the correct URI?
5404 if (strncmp(con
->uri
, "/admin/", 7) != 0)
5406 LogMessage(L_ERROR
, "stop_printer: admin request on bad resource \'%s\'!",
5408 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5413 * Is the destination valid?
5416 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5418 if ((name
= ValidateDest(host
, resource
, &dtype
)) == NULL
)
5424 LogMessage(L_ERROR
, "stop_printer: resource name \'%s\' no good!", resource
);
5425 send_ipp_error(con
, IPP_NOT_FOUND
);
5430 * Stop the printer...
5433 if (dtype
== CUPS_PRINTER_CLASS
)
5434 printer
= FindClass(name
);
5436 printer
= FindPrinter(name
);
5438 StopPrinter(printer
);
5440 if (dtype
== CUPS_PRINTER_CLASS
)
5445 if ((attr
= ippFindAttribute(con
->request
, "printer-state-message",
5446 IPP_TAG_TEXT
)) == NULL
)
5447 strcpy(printer
->state_message
, "Paused");
5450 strncpy(printer
->state_message
, attr
->values
[0].string
.text
,
5451 sizeof(printer
->state_message
) - 1);
5452 printer
->state_message
[sizeof(printer
->state_message
) - 1] = '\0';
5455 if (dtype
== CUPS_PRINTER_CLASS
)
5456 LogMessage(L_INFO
, "Class \'%s\' stopped by \'%s\'.", name
,
5459 LogMessage(L_INFO
, "Printer \'%s\' stopped by \'%s\'.", name
,
5463 * Everything was ok, so return OK status...
5466 con
->response
->request
.status
.status_code
= IPP_OK
;
5471 * 'validate_job()' - Validate printer options and destination.
5475 validate_job(client_t
*con
, /* I - Client connection */
5476 ipp_attribute_t
*uri
) /* I - Printer URI */
5478 ipp_attribute_t
*attr
; /* Current attribute */
5479 ipp_attribute_t
*format
; /* Document-format attribute */
5480 cups_ptype_t dtype
; /* Destination type (printer or class) */
5481 char method
[HTTP_MAX_URI
],
5482 /* Method portion of URI */
5483 username
[HTTP_MAX_URI
],
5484 /* Username portion of URI */
5486 /* Host portion of URI */
5487 resource
[HTTP_MAX_URI
];
5488 /* Resource portion of URI */
5489 int port
; /* Port portion of URI */
5490 char super
[MIME_MAX_SUPER
],
5491 /* Supertype of file */
5492 type
[MIME_MAX_TYPE
];
5493 /* Subtype of file */
5496 LogMessage(L_DEBUG2
, "validate_job(%d, %s)\n", con
->http
.fd
,
5497 uri
->values
[0].string
.text
);
5500 * Verify that the POST operation was done to a valid URI.
5503 if (strncmp(con
->uri
, "/classes/", 9) != 0 &&
5504 strncmp(con
->uri
, "/printers/", 10) != 0)
5506 LogMessage(L_ERROR
, "validate_job: request on bad resource \'%s\'!",
5508 send_ipp_error(con
, IPP_NOT_AUTHORIZED
);
5513 * OK, see if the client is sending the document compressed - CUPS
5514 * doesn't support compression yet...
5517 if ((attr
= ippFindAttribute(con
->request
, "compression", IPP_TAG_KEYWORD
)) != NULL
&&
5518 strcmp(attr
->values
[0].string
.text
, "none") == 0)
5520 LogMessage(L_ERROR
, "validate_job: Unsupported compression attribute %s!",
5521 attr
->values
[0].string
.text
);
5522 send_ipp_error(con
, IPP_ATTRIBUTES
);
5523 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_KEYWORD
,
5524 "compression", NULL
, attr
->values
[0].string
.text
);
5529 * Is it a format we support?
5532 if ((format
= ippFindAttribute(con
->request
, "document-format", IPP_TAG_MIMETYPE
)) != NULL
)
5534 if (sscanf(format
->values
[0].string
.text
, "%15[^/]/%31[^;]", super
, type
) != 2)
5536 LogMessage(L_ERROR
, "validate_job: could not scan type \'%s\'!\n",
5537 format
->values
[0].string
.text
);
5538 send_ipp_error(con
, IPP_BAD_REQUEST
);
5542 if ((strcmp(super
, "application") != 0 ||
5543 strcmp(type
, "octet-stream") != 0) &&
5544 mimeType(MimeDatabase
, super
, type
) == NULL
)
5546 LogMessage(L_ERROR
, "validate_job: Unsupported format \'%s\'!\n",
5547 format
->values
[0].string
.text
);
5548 send_ipp_error(con
, IPP_DOCUMENT_FORMAT
);
5549 ippAddString(con
->response
, IPP_TAG_UNSUPPORTED_GROUP
, IPP_TAG_MIMETYPE
,
5550 "document-format", NULL
, format
->values
[0].string
.text
);
5556 * Is the destination valid?
5559 httpSeparate(uri
->values
[0].string
.text
, method
, username
, host
, &port
, resource
);
5561 if (ValidateDest(host
, resource
, &dtype
) == NULL
)
5567 LogMessage(L_ERROR
, "validate_job: resource name \'%s\' no good!", resource
);
5568 send_ipp_error(con
, IPP_NOT_FOUND
);
5573 * Everything was ok, so return OK status...
5576 con
->response
->request
.status
.status_code
= IPP_OK
;
5581 * 'validate_user()' - Validate the user for the request.
5584 static int /* O - 1 if permitted, 0 otherwise */
5585 validate_user(client_t
*con
, /* I - Client connection */
5586 const char *owner
, /* I - Owner of job/resource */
5587 char *username
, /* O - Authenticated username */
5588 int userlen
) /* I - Length of username */
5590 int i
, j
; /* Looping vars */
5591 ipp_attribute_t
*attr
; /* requesting-user-name attribute */
5592 struct passwd
*user
; /* User info */
5593 struct group
*group
; /* System group info */
5596 LogMessage(L_DEBUG2
, "validate_user(%d, %s, %s, %d)\n", con
->http
.fd
,
5597 owner
, username
, userlen
);
5603 if (con
== NULL
|| owner
== NULL
|| username
== NULL
|| userlen
<= 0)
5607 * Get the best authenticated username that is available.
5610 if (con
->username
[0])
5611 strncpy(username
, con
->username
, userlen
- 1);
5612 else if ((attr
= ippFindAttribute(con
->request
, "requesting-user-name", IPP_TAG_NAME
)) != NULL
)
5613 strncpy(username
, attr
->values
[0].string
.text
, userlen
- 1);
5615 strncpy(username
, "anonymous", userlen
- 1);
5617 username
[userlen
- 1] = '\0';
5620 * Check the username against the owner...
5623 if (strcasecmp(username
, owner
) != 0 && strcasecmp(username
, "root") != 0)
5626 * Not the owner or root; check to see if the user is a member of the
5630 user
= getpwnam(username
);
5633 for (i
= 0, j
= 0, group
= NULL
; i
< NumSystemGroups
; i
++)
5635 group
= getgrnam(SystemGroups
[i
]);
5640 for (j
= 0; group
->gr_mem
[j
]; j
++)
5641 if (strcasecmp(username
, group
->gr_mem
[j
]) == 0)
5644 if (group
->gr_mem
[j
])
5651 if (user
== NULL
|| group
== NULL
||
5652 (group
->gr_mem
[j
] == NULL
&& group
->gr_gid
!= user
->pw_gid
))
5655 * Username not found, group not found, or user is not part of the
5668 * End of "$Id: ipp.c,v 1.127.2.3 2001/12/26 16:52:53 mike Exp $".