xref: /aosp_15_r20/external/libcups/scheduler/ipp.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * IPP routines for the CUPS scheduler.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2007-2021 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * This file contains Kerberos support code, copyright 2006 by
8*5e7646d2SAndroid Build Coastguard Worker  * Jelmer Vernooij.
9*5e7646d2SAndroid Build Coastguard Worker  *
10*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
11*5e7646d2SAndroid Build Coastguard Worker  * information.
12*5e7646d2SAndroid Build Coastguard Worker  */
13*5e7646d2SAndroid Build Coastguard Worker 
14*5e7646d2SAndroid Build Coastguard Worker /*
15*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
16*5e7646d2SAndroid Build Coastguard Worker  */
17*5e7646d2SAndroid Build Coastguard Worker 
18*5e7646d2SAndroid Build Coastguard Worker #include "cupsd.h"
19*5e7646d2SAndroid Build Coastguard Worker #include <cups/ppd-private.h>
20*5e7646d2SAndroid Build Coastguard Worker 
21*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
22*5e7646d2SAndroid Build Coastguard Worker #  ifdef HAVE_MEMBERSHIP_H
23*5e7646d2SAndroid Build Coastguard Worker #    include <membership.h>
24*5e7646d2SAndroid Build Coastguard Worker #  endif /* HAVE_MEMBERSHIP_H */
25*5e7646d2SAndroid Build Coastguard Worker extern int mbr_user_name_to_uuid(const char* name, uuid_t uu);
26*5e7646d2SAndroid Build Coastguard Worker extern int mbr_group_name_to_uuid(const char* name, uuid_t uu);
27*5e7646d2SAndroid Build Coastguard Worker extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
28*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker 
31*5e7646d2SAndroid Build Coastguard Worker /*
32*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
33*5e7646d2SAndroid Build Coastguard Worker  */
34*5e7646d2SAndroid Build Coastguard Worker 
35*5e7646d2SAndroid Build Coastguard Worker static void	accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
36*5e7646d2SAndroid Build Coastguard Worker static void	add_class(cupsd_client_t *con, ipp_attribute_t *uri);
37*5e7646d2SAndroid Build Coastguard Worker static int	add_file(cupsd_client_t *con, cupsd_job_t *job,
38*5e7646d2SAndroid Build Coastguard Worker 		         mime_type_t *filetype, int compression);
39*5e7646d2SAndroid Build Coastguard Worker static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer,
40*5e7646d2SAndroid Build Coastguard Worker 			    mime_type_t *filetype);
41*5e7646d2SAndroid Build Coastguard Worker static void	add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job);
42*5e7646d2SAndroid Build Coastguard Worker static void	add_job_uuid(cupsd_job_t *job);
43*5e7646d2SAndroid Build Coastguard Worker static void	add_printer(cupsd_client_t *con, ipp_attribute_t *uri);
44*5e7646d2SAndroid Build Coastguard Worker static void	add_printer_state_reasons(cupsd_client_t *con,
45*5e7646d2SAndroid Build Coastguard Worker 		                          cupsd_printer_t *p);
46*5e7646d2SAndroid Build Coastguard Worker static void	add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p);
47*5e7646d2SAndroid Build Coastguard Worker static void	apply_printer_defaults(cupsd_printer_t *printer,
48*5e7646d2SAndroid Build Coastguard Worker 				       cupsd_job_t *job);
49*5e7646d2SAndroid Build Coastguard Worker static void	authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri);
50*5e7646d2SAndroid Build Coastguard Worker static void	cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
51*5e7646d2SAndroid Build Coastguard Worker static void	cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
52*5e7646d2SAndroid Build Coastguard Worker static void	cancel_subscription(cupsd_client_t *con, int id);
53*5e7646d2SAndroid Build Coastguard Worker static int	check_rss_recipient(const char *recipient);
54*5e7646d2SAndroid Build Coastguard Worker static int	check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
55*5e7646d2SAndroid Build Coastguard Worker static void	close_job(cupsd_client_t *con, ipp_attribute_t *uri);
56*5e7646d2SAndroid Build Coastguard Worker static void	copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
57*5e7646d2SAndroid Build Coastguard Worker 		           ipp_tag_t group, int quickcopy,
58*5e7646d2SAndroid Build Coastguard Worker 			   cups_array_t *exclude);
59*5e7646d2SAndroid Build Coastguard Worker static int	copy_banner(cupsd_client_t *con, cupsd_job_t *job,
60*5e7646d2SAndroid Build Coastguard Worker 		            const char *name);
61*5e7646d2SAndroid Build Coastguard Worker static int	copy_file(const char *from, const char *to, mode_t mode);
62*5e7646d2SAndroid Build Coastguard Worker static int	copy_model(cupsd_client_t *con, const char *from,
63*5e7646d2SAndroid Build Coastguard Worker 		           const char *to);
64*5e7646d2SAndroid Build Coastguard Worker static void	copy_job_attrs(cupsd_client_t *con,
65*5e7646d2SAndroid Build Coastguard Worker 		               cupsd_job_t *job,
66*5e7646d2SAndroid Build Coastguard Worker 			       cups_array_t *ra, cups_array_t *exclude);
67*5e7646d2SAndroid Build Coastguard Worker static void	copy_printer_attrs(cupsd_client_t *con,
68*5e7646d2SAndroid Build Coastguard Worker 		                   cupsd_printer_t *printer,
69*5e7646d2SAndroid Build Coastguard Worker 				   cups_array_t *ra);
70*5e7646d2SAndroid Build Coastguard Worker static void	copy_subscription_attrs(cupsd_client_t *con,
71*5e7646d2SAndroid Build Coastguard Worker 		                        cupsd_subscription_t *sub,
72*5e7646d2SAndroid Build Coastguard Worker 					cups_array_t *ra,
73*5e7646d2SAndroid Build Coastguard Worker 					cups_array_t *exclude);
74*5e7646d2SAndroid Build Coastguard Worker static void	create_job(cupsd_client_t *con, ipp_attribute_t *uri);
75*5e7646d2SAndroid Build Coastguard Worker static void	*create_local_bg_thread(cupsd_printer_t *printer);
76*5e7646d2SAndroid Build Coastguard Worker static void	create_local_printer(cupsd_client_t *con);
77*5e7646d2SAndroid Build Coastguard Worker static cups_array_t *create_requested_array(ipp_t *request);
78*5e7646d2SAndroid Build Coastguard Worker static void	create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
79*5e7646d2SAndroid Build Coastguard Worker static void	delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
80*5e7646d2SAndroid Build Coastguard Worker static void	get_default(cupsd_client_t *con);
81*5e7646d2SAndroid Build Coastguard Worker static void	get_devices(cupsd_client_t *con);
82*5e7646d2SAndroid Build Coastguard Worker static void	get_document(cupsd_client_t *con, ipp_attribute_t *uri);
83*5e7646d2SAndroid Build Coastguard Worker static void	get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
84*5e7646d2SAndroid Build Coastguard Worker static void	get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
85*5e7646d2SAndroid Build Coastguard Worker static void	get_notifications(cupsd_client_t *con);
86*5e7646d2SAndroid Build Coastguard Worker static void	get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
87*5e7646d2SAndroid Build Coastguard Worker static void	get_ppds(cupsd_client_t *con);
88*5e7646d2SAndroid Build Coastguard Worker static void	get_printers(cupsd_client_t *con, int type);
89*5e7646d2SAndroid Build Coastguard Worker static void	get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
90*5e7646d2SAndroid Build Coastguard Worker static void	get_printer_supported(cupsd_client_t *con, ipp_attribute_t *uri);
91*5e7646d2SAndroid Build Coastguard Worker static void	get_subscription_attrs(cupsd_client_t *con, int sub_id);
92*5e7646d2SAndroid Build Coastguard Worker static void	get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
93*5e7646d2SAndroid Build Coastguard Worker static const char *get_username(cupsd_client_t *con);
94*5e7646d2SAndroid Build Coastguard Worker static void	hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
95*5e7646d2SAndroid Build Coastguard Worker static void	hold_new_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
96*5e7646d2SAndroid Build Coastguard Worker static void	move_job(cupsd_client_t *con, ipp_attribute_t *uri);
97*5e7646d2SAndroid Build Coastguard Worker static int	ppd_parse_line(const char *line, char *option, int olen,
98*5e7646d2SAndroid Build Coastguard Worker 		               char *choice, int clen);
99*5e7646d2SAndroid Build Coastguard Worker static void	print_job(cupsd_client_t *con, ipp_attribute_t *uri);
100*5e7646d2SAndroid Build Coastguard Worker static void	read_job_ticket(cupsd_client_t *con);
101*5e7646d2SAndroid Build Coastguard Worker static void	reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
102*5e7646d2SAndroid Build Coastguard Worker static void	release_held_new_jobs(cupsd_client_t *con,
103*5e7646d2SAndroid Build Coastguard Worker 		                      ipp_attribute_t *uri);
104*5e7646d2SAndroid Build Coastguard Worker static void	release_job(cupsd_client_t *con, ipp_attribute_t *uri);
105*5e7646d2SAndroid Build Coastguard Worker static void	renew_subscription(cupsd_client_t *con, int sub_id);
106*5e7646d2SAndroid Build Coastguard Worker static void	restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
107*5e7646d2SAndroid Build Coastguard Worker static void	save_auth_info(cupsd_client_t *con, cupsd_job_t *job,
108*5e7646d2SAndroid Build Coastguard Worker 		               ipp_attribute_t *auth_info);
109*5e7646d2SAndroid Build Coastguard Worker static void	send_document(cupsd_client_t *con, ipp_attribute_t *uri);
110*5e7646d2SAndroid Build Coastguard Worker static void	send_http_error(cupsd_client_t *con, http_status_t status,
111*5e7646d2SAndroid Build Coastguard Worker 		                cupsd_printer_t *printer);
112*5e7646d2SAndroid Build Coastguard Worker static void	send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4);
113*5e7646d2SAndroid Build Coastguard Worker static void	set_default(cupsd_client_t *con, ipp_attribute_t *uri);
114*5e7646d2SAndroid Build Coastguard Worker static void	set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
115*5e7646d2SAndroid Build Coastguard Worker static void	set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
116*5e7646d2SAndroid Build Coastguard Worker static int	set_printer_defaults(cupsd_client_t *con, cupsd_printer_t *printer);
117*5e7646d2SAndroid Build Coastguard Worker static void	start_printer(cupsd_client_t *con, ipp_attribute_t *uri);
118*5e7646d2SAndroid Build Coastguard Worker static void	stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
119*5e7646d2SAndroid Build Coastguard Worker static void	url_encode_attr(ipp_attribute_t *attr, char *buffer, size_t bufsize);
120*5e7646d2SAndroid Build Coastguard Worker static char	*url_encode_string(const char *s, char *buffer, size_t bufsize);
121*5e7646d2SAndroid Build Coastguard Worker static int	user_allowed(cupsd_printer_t *p, const char *username);
122*5e7646d2SAndroid Build Coastguard Worker static void	validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
123*5e7646d2SAndroid Build Coastguard Worker static int	validate_name(const char *name);
124*5e7646d2SAndroid Build Coastguard Worker static int	validate_user(cupsd_job_t *job, cupsd_client_t *con, const char *owner, char *username, size_t userlen);
125*5e7646d2SAndroid Build Coastguard Worker 
126*5e7646d2SAndroid Build Coastguard Worker 
127*5e7646d2SAndroid Build Coastguard Worker /*
128*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdProcessIPPRequest()' - Process an incoming IPP request.
129*5e7646d2SAndroid Build Coastguard Worker  */
130*5e7646d2SAndroid Build Coastguard Worker 
131*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsdProcessIPPRequest(cupsd_client_t * con)132*5e7646d2SAndroid Build Coastguard Worker cupsdProcessIPPRequest(
133*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con)		/* I - Client connection */
134*5e7646d2SAndroid Build Coastguard Worker {
135*5e7646d2SAndroid Build Coastguard Worker   ipp_tag_t		group;		/* Current group tag */
136*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
137*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*charset;	/* Character set attribute */
138*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*language;	/* Language attribute */
139*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*uri = NULL;	/* Printer or job URI attribute */
140*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*username;	/* requesting-user-name attr */
141*5e7646d2SAndroid Build Coastguard Worker   int			sub_id;		/* Subscription ID */
142*5e7646d2SAndroid Build Coastguard Worker   int			valid = 1;	/* Valid request? */
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker 
145*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
146*5e7646d2SAndroid Build Coastguard Worker 
147*5e7646d2SAndroid Build Coastguard Worker   if (LogLevel >= CUPSD_LOG_DEBUG2)
148*5e7646d2SAndroid Build Coastguard Worker   {
149*5e7646d2SAndroid Build Coastguard Worker     for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(con->request); attr; attr = ippNextAttribute(con->request))
150*5e7646d2SAndroid Build Coastguard Worker     {
151*5e7646d2SAndroid Build Coastguard Worker       const char  *name;                /* Attribute name */
152*5e7646d2SAndroid Build Coastguard Worker       char        value[1024];          /* Attribute value */
153*5e7646d2SAndroid Build Coastguard Worker 
154*5e7646d2SAndroid Build Coastguard Worker       if (group != ippGetGroupTag(attr))
155*5e7646d2SAndroid Build Coastguard Worker       {
156*5e7646d2SAndroid Build Coastguard Worker         group = ippGetGroupTag(attr);
157*5e7646d2SAndroid Build Coastguard Worker         if (group != IPP_TAG_ZERO)
158*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s", ippTagString(group));
159*5e7646d2SAndroid Build Coastguard Worker       }
160*5e7646d2SAndroid Build Coastguard Worker 
161*5e7646d2SAndroid Build Coastguard Worker       if ((name = ippGetName(attr)) == NULL)
162*5e7646d2SAndroid Build Coastguard Worker         continue;
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker       ippAttributeString(attr, value, sizeof(value));
165*5e7646d2SAndroid Build Coastguard Worker 
166*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s %s%s '%s'", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), value);
167*5e7646d2SAndroid Build Coastguard Worker     }
168*5e7646d2SAndroid Build Coastguard Worker   }
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker  /*
171*5e7646d2SAndroid Build Coastguard Worker   * First build an empty response message for this request...
172*5e7646d2SAndroid Build Coastguard Worker   */
173*5e7646d2SAndroid Build Coastguard Worker 
174*5e7646d2SAndroid Build Coastguard Worker   con->response = ippNew();
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.version[0] = con->request->request.op.version[0];
177*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.version[1] = con->request->request.op.version[1];
178*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.request_id = con->request->request.op.request_id;
179*5e7646d2SAndroid Build Coastguard Worker 
180*5e7646d2SAndroid Build Coastguard Worker  /*
181*5e7646d2SAndroid Build Coastguard Worker   * Then validate the request header and required attributes...
182*5e7646d2SAndroid Build Coastguard Worker   */
183*5e7646d2SAndroid Build Coastguard Worker 
184*5e7646d2SAndroid Build Coastguard Worker   if (con->request->request.any.version[0] != 1 && con->request->request.any.version[0] != 2)
185*5e7646d2SAndroid Build Coastguard Worker   {
186*5e7646d2SAndroid Build Coastguard Worker    /*
187*5e7646d2SAndroid Build Coastguard Worker     * Return an error, since we only support IPP 1.x and 2.x.
188*5e7646d2SAndroid Build Coastguard Worker     */
189*5e7646d2SAndroid Build Coastguard Worker 
190*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request version number %d.%d.", IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, con->http->hostname, con->request->request.any.version[0], con->request->request.any.version[1]);
191*5e7646d2SAndroid Build Coastguard Worker 
192*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, _("Bad request version number %d.%d."), con->request->request.any.version[0], con->request->request.any.version[1]);
193*5e7646d2SAndroid Build Coastguard Worker   }
194*5e7646d2SAndroid Build Coastguard Worker   else if (con->request->request.any.request_id < 1)
195*5e7646d2SAndroid Build Coastguard Worker   {
196*5e7646d2SAndroid Build Coastguard Worker    /*
197*5e7646d2SAndroid Build Coastguard Worker     * Return an error, since request IDs must be between 1 and 2^31-1
198*5e7646d2SAndroid Build Coastguard Worker     */
199*5e7646d2SAndroid Build Coastguard Worker 
200*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request ID %d.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname, con->request->request.any.request_id);
201*5e7646d2SAndroid Build Coastguard Worker 
202*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Bad request ID %d."), con->request->request.any.request_id);
203*5e7646d2SAndroid Build Coastguard Worker   }
204*5e7646d2SAndroid Build Coastguard Worker   else if (!con->request->attrs)
205*5e7646d2SAndroid Build Coastguard Worker   {
206*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s No attributes in request.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
207*5e7646d2SAndroid Build Coastguard Worker 
208*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("No attributes in request."));
209*5e7646d2SAndroid Build Coastguard Worker   }
210*5e7646d2SAndroid Build Coastguard Worker   else
211*5e7646d2SAndroid Build Coastguard Worker   {
212*5e7646d2SAndroid Build Coastguard Worker    /*
213*5e7646d2SAndroid Build Coastguard Worker     * Make sure that the attributes are provided in the correct order and
214*5e7646d2SAndroid Build Coastguard Worker     * don't repeat groups...
215*5e7646d2SAndroid Build Coastguard Worker     */
216*5e7646d2SAndroid Build Coastguard Worker 
217*5e7646d2SAndroid Build Coastguard Worker     for (attr = con->request->attrs, group = attr->group_tag;
218*5e7646d2SAndroid Build Coastguard Worker 	 attr;
219*5e7646d2SAndroid Build Coastguard Worker 	 attr = attr->next)
220*5e7646d2SAndroid Build Coastguard Worker       if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
221*5e7646d2SAndroid Build Coastguard Worker       {
222*5e7646d2SAndroid Build Coastguard Worker        /*
223*5e7646d2SAndroid Build Coastguard Worker 	* Out of order; return an error...
224*5e7646d2SAndroid Build Coastguard Worker 	*/
225*5e7646d2SAndroid Build Coastguard Worker 
226*5e7646d2SAndroid Build Coastguard Worker 	cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Attribute groups are out of order", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
227*5e7646d2SAndroid Build Coastguard Worker 
228*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute groups are out of order (%x < %x)."), attr->group_tag, group);
229*5e7646d2SAndroid Build Coastguard Worker 	break;
230*5e7646d2SAndroid Build Coastguard Worker       }
231*5e7646d2SAndroid Build Coastguard Worker       else
232*5e7646d2SAndroid Build Coastguard Worker 	group = attr->group_tag;
233*5e7646d2SAndroid Build Coastguard Worker 
234*5e7646d2SAndroid Build Coastguard Worker     if (!attr)
235*5e7646d2SAndroid Build Coastguard Worker     {
236*5e7646d2SAndroid Build Coastguard Worker      /*
237*5e7646d2SAndroid Build Coastguard Worker       * Then make sure that the first three attributes are:
238*5e7646d2SAndroid Build Coastguard Worker       *
239*5e7646d2SAndroid Build Coastguard Worker       *     attributes-charset
240*5e7646d2SAndroid Build Coastguard Worker       *     attributes-natural-language
241*5e7646d2SAndroid Build Coastguard Worker       *     printer-uri/job-uri
242*5e7646d2SAndroid Build Coastguard Worker       */
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker       attr = con->request->attrs;
245*5e7646d2SAndroid Build Coastguard Worker       if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET && attr->group_tag == IPP_TAG_OPERATION)
246*5e7646d2SAndroid Build Coastguard Worker 	charset = attr;
247*5e7646d2SAndroid Build Coastguard Worker       else
248*5e7646d2SAndroid Build Coastguard Worker 	charset = NULL;
249*5e7646d2SAndroid Build Coastguard Worker 
250*5e7646d2SAndroid Build Coastguard Worker       if (attr)
251*5e7646d2SAndroid Build Coastguard Worker         attr = attr->next;
252*5e7646d2SAndroid Build Coastguard Worker 
253*5e7646d2SAndroid Build Coastguard Worker       if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE && attr->group_tag == IPP_TAG_OPERATION)
254*5e7646d2SAndroid Build Coastguard Worker       {
255*5e7646d2SAndroid Build Coastguard Worker 	language = attr;
256*5e7646d2SAndroid Build Coastguard Worker 
257*5e7646d2SAndroid Build Coastguard Worker        /*
258*5e7646d2SAndroid Build Coastguard Worker         * Reset language for this request if different from Accept-Language.
259*5e7646d2SAndroid Build Coastguard Worker         */
260*5e7646d2SAndroid Build Coastguard Worker 
261*5e7646d2SAndroid Build Coastguard Worker 	if (!con->language ||
262*5e7646d2SAndroid Build Coastguard Worker 	    strcmp(attr->values[0].string.text, con->language->language))
263*5e7646d2SAndroid Build Coastguard Worker 	{
264*5e7646d2SAndroid Build Coastguard Worker 	  cupsLangFree(con->language);
265*5e7646d2SAndroid Build Coastguard Worker 	  con->language = cupsLangGet(attr->values[0].string.text);
266*5e7646d2SAndroid Build Coastguard Worker 	}
267*5e7646d2SAndroid Build Coastguard Worker       }
268*5e7646d2SAndroid Build Coastguard Worker       else
269*5e7646d2SAndroid Build Coastguard Worker 	language = NULL;
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker       if ((attr = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
272*5e7646d2SAndroid Build Coastguard Worker 	uri = attr;
273*5e7646d2SAndroid Build Coastguard Worker       else if ((attr = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
274*5e7646d2SAndroid Build Coastguard Worker 	uri = attr;
275*5e7646d2SAndroid Build Coastguard Worker       else if (con->request->request.op.operation_id == CUPS_GET_PPD && (attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL && attr->group_tag == IPP_TAG_OPERATION)
276*5e7646d2SAndroid Build Coastguard Worker         uri = attr;
277*5e7646d2SAndroid Build Coastguard Worker       else
278*5e7646d2SAndroid Build Coastguard Worker 	uri = NULL;
279*5e7646d2SAndroid Build Coastguard Worker 
280*5e7646d2SAndroid Build Coastguard Worker       if (charset)
281*5e7646d2SAndroid Build Coastguard Worker 	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, charset->values[0].string.text);
282*5e7646d2SAndroid Build Coastguard Worker       else
283*5e7646d2SAndroid Build Coastguard Worker 	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8");
284*5e7646d2SAndroid Build Coastguard Worker 
285*5e7646d2SAndroid Build Coastguard Worker       if (language)
286*5e7646d2SAndroid Build Coastguard Worker 	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->values[0].string.text);
287*5e7646d2SAndroid Build Coastguard Worker       else
288*5e7646d2SAndroid Build Coastguard Worker 	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, DefaultLanguage);
289*5e7646d2SAndroid Build Coastguard Worker 
290*5e7646d2SAndroid Build Coastguard Worker       if (charset && _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && _cups_strcasecmp(charset->values[0].string.text, "utf-8"))
291*5e7646d2SAndroid Build Coastguard Worker       {
292*5e7646d2SAndroid Build Coastguard Worker        /*
293*5e7646d2SAndroid Build Coastguard Worker         * Bad character set...
294*5e7646d2SAndroid Build Coastguard Worker 	*/
295*5e7646d2SAndroid Build Coastguard Worker 
296*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"",
297*5e7646d2SAndroid Build Coastguard Worker 	                charset->values[0].string.text);
298*5e7646d2SAndroid Build Coastguard Worker 	cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Unsupported attributes-charset value \"%s\".", IPP_STATUS_ERROR_CHARSET, con->http->hostname, charset->values[0].string.text);
299*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_ERROR_CHARSET, _("Unsupported character set \"%s\"."), charset->values[0].string.text);
300*5e7646d2SAndroid Build Coastguard Worker       }
301*5e7646d2SAndroid Build Coastguard Worker       else if (!charset || !language ||
302*5e7646d2SAndroid Build Coastguard Worker 	       (!uri &&
303*5e7646d2SAndroid Build Coastguard Worker 	        con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
304*5e7646d2SAndroid Build Coastguard Worker 	        con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
305*5e7646d2SAndroid Build Coastguard Worker 	        con->request->request.op.operation_id != CUPS_GET_CLASSES &&
306*5e7646d2SAndroid Build Coastguard Worker 	        con->request->request.op.operation_id != CUPS_GET_DEVICES &&
307*5e7646d2SAndroid Build Coastguard Worker 	        con->request->request.op.operation_id != CUPS_GET_PPDS))
308*5e7646d2SAndroid Build Coastguard Worker       {
309*5e7646d2SAndroid Build Coastguard Worker        /*
310*5e7646d2SAndroid Build Coastguard Worker 	* Return an error, since attributes-charset,
311*5e7646d2SAndroid Build Coastguard Worker 	* attributes-natural-language, and printer-uri/job-uri are required
312*5e7646d2SAndroid Build Coastguard Worker 	* for all operations.
313*5e7646d2SAndroid Build Coastguard Worker 	*/
314*5e7646d2SAndroid Build Coastguard Worker 
315*5e7646d2SAndroid Build Coastguard Worker         if (!charset)
316*5e7646d2SAndroid Build Coastguard Worker 	{
317*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_ERROR, "Missing attributes-charset attribute.");
318*5e7646d2SAndroid Build Coastguard Worker 
319*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-charset attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
320*5e7646d2SAndroid Build Coastguard Worker         }
321*5e7646d2SAndroid Build Coastguard Worker 
322*5e7646d2SAndroid Build Coastguard Worker         if (!language)
323*5e7646d2SAndroid Build Coastguard Worker 	{
324*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_ERROR,
325*5e7646d2SAndroid Build Coastguard Worker 	                  "Missing attributes-natural-language attribute.");
326*5e7646d2SAndroid Build Coastguard Worker 
327*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-natural-language attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
328*5e7646d2SAndroid Build Coastguard Worker         }
329*5e7646d2SAndroid Build Coastguard Worker 
330*5e7646d2SAndroid Build Coastguard Worker         if (!uri)
331*5e7646d2SAndroid Build Coastguard Worker 	{
332*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_ERROR, "Missing printer-uri, job-uri, or ppd-name attribute.");
333*5e7646d2SAndroid Build Coastguard Worker 
334*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing printer-uri, job-uri, or ppd-name attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
335*5e7646d2SAndroid Build Coastguard Worker         }
336*5e7646d2SAndroid Build Coastguard Worker 
337*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker 	for (attr = con->request->attrs; attr; attr = attr->next)
340*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_DEBUG,
341*5e7646d2SAndroid Build Coastguard Worker 	        	  "attr \"%s\": group_tag = %x, value_tag = %x",
342*5e7646d2SAndroid Build Coastguard Worker 	        	  attr->name ? attr->name : "(null)", attr->group_tag,
343*5e7646d2SAndroid Build Coastguard Worker 			  attr->value_tag);
344*5e7646d2SAndroid Build Coastguard Worker 
345*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes...");
346*5e7646d2SAndroid Build Coastguard Worker 
347*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_BAD_REQUEST,
348*5e7646d2SAndroid Build Coastguard Worker 	                _("Missing required attributes."));
349*5e7646d2SAndroid Build Coastguard Worker       }
350*5e7646d2SAndroid Build Coastguard Worker       else
351*5e7646d2SAndroid Build Coastguard Worker       {
352*5e7646d2SAndroid Build Coastguard Worker        /*
353*5e7646d2SAndroid Build Coastguard Worker 	* OK, all the checks pass so far; validate "requesting-user-name"
354*5e7646d2SAndroid Build Coastguard Worker 	* attribute value...
355*5e7646d2SAndroid Build Coastguard Worker 	*/
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker         if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_ZERO)) != NULL)
358*5e7646d2SAndroid Build Coastguard Worker         {
359*5e7646d2SAndroid Build Coastguard Worker          /*
360*5e7646d2SAndroid Build Coastguard Worker           * Validate "requesting-user-name"...
361*5e7646d2SAndroid Build Coastguard Worker           */
362*5e7646d2SAndroid Build Coastguard Worker 
363*5e7646d2SAndroid Build Coastguard Worker           if (username->group_tag != IPP_TAG_OPERATION && StrictConformance)
364*5e7646d2SAndroid Build Coastguard Worker           {
365*5e7646d2SAndroid Build Coastguard Worker 	    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute in wrong group.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
366*5e7646d2SAndroid Build Coastguard Worker 	    send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("\"requesting-user-name\" attribute in wrong group."));
367*5e7646d2SAndroid Build Coastguard Worker 	    valid = 0;
368*5e7646d2SAndroid Build Coastguard Worker           }
369*5e7646d2SAndroid Build Coastguard Worker           else if (username->value_tag != IPP_TAG_NAME && username->value_tag != IPP_TAG_NAMELANG)
370*5e7646d2SAndroid Build Coastguard Worker           {
371*5e7646d2SAndroid Build Coastguard Worker 	    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with wrong syntax.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
372*5e7646d2SAndroid Build Coastguard Worker 	    send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
373*5e7646d2SAndroid Build Coastguard Worker 	    if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
374*5e7646d2SAndroid Build Coastguard Worker 	      attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
375*5e7646d2SAndroid Build Coastguard Worker 	    valid = 0;
376*5e7646d2SAndroid Build Coastguard Worker           }
377*5e7646d2SAndroid Build Coastguard Worker           else if (!ippValidateAttribute(username))
378*5e7646d2SAndroid Build Coastguard Worker           {
379*5e7646d2SAndroid Build Coastguard Worker 	    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with bad value.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker             if (StrictConformance)
382*5e7646d2SAndroid Build Coastguard Worker             {
383*5e7646d2SAndroid Build Coastguard Worker              /*
384*5e7646d2SAndroid Build Coastguard Worker               * Throw an error...
385*5e7646d2SAndroid Build Coastguard Worker               */
386*5e7646d2SAndroid Build Coastguard Worker 
387*5e7646d2SAndroid Build Coastguard Worker 	      send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
388*5e7646d2SAndroid Build Coastguard Worker               if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
389*5e7646d2SAndroid Build Coastguard Worker                 attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
390*5e7646d2SAndroid Build Coastguard Worker 	      valid = 0;
391*5e7646d2SAndroid Build Coastguard Worker 	    }
392*5e7646d2SAndroid Build Coastguard Worker 	    else
393*5e7646d2SAndroid Build Coastguard Worker 	    {
394*5e7646d2SAndroid Build Coastguard Worker 	     /*
395*5e7646d2SAndroid Build Coastguard Worker 	      * Map bad "requesting-user-name" to 'anonymous'...
396*5e7646d2SAndroid Build Coastguard Worker 	      */
397*5e7646d2SAndroid Build Coastguard Worker 
398*5e7646d2SAndroid Build Coastguard Worker               ippSetString(con->request, &username, 0, "anonymous");
399*5e7646d2SAndroid Build Coastguard Worker 	    }
400*5e7646d2SAndroid Build Coastguard Worker           }
401*5e7646d2SAndroid Build Coastguard Worker           else if (!strcmp(username->values[0].string.text, "root") && _cups_strcasecmp(con->http->hostname, "localhost") && strcmp(con->username, "root"))
402*5e7646d2SAndroid Build Coastguard Worker 	  {
403*5e7646d2SAndroid Build Coastguard Worker 	   /*
404*5e7646d2SAndroid Build Coastguard Worker 	    * Remote unauthenticated user masquerading as local root...
405*5e7646d2SAndroid Build Coastguard Worker 	    */
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker             ippSetString(con->request, &username, 0, RemoteRoot);
408*5e7646d2SAndroid Build Coastguard Worker 	  }
409*5e7646d2SAndroid Build Coastguard Worker 	}
410*5e7646d2SAndroid Build Coastguard Worker 
411*5e7646d2SAndroid Build Coastguard Worker         if ((attr = ippFindAttribute(con->request, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL)
412*5e7646d2SAndroid Build Coastguard Worker 	  sub_id = attr->values[0].integer;
413*5e7646d2SAndroid Build Coastguard Worker 	else
414*5e7646d2SAndroid Build Coastguard Worker 	  sub_id = 0;
415*5e7646d2SAndroid Build Coastguard Worker 
416*5e7646d2SAndroid Build Coastguard Worker         if (valid)
417*5e7646d2SAndroid Build Coastguard Worker         {
418*5e7646d2SAndroid Build Coastguard Worker 	 /*
419*5e7646d2SAndroid Build Coastguard Worker 	  * Try processing the operation...
420*5e7646d2SAndroid Build Coastguard Worker 	  */
421*5e7646d2SAndroid Build Coastguard Worker 
422*5e7646d2SAndroid Build Coastguard Worker 	  if (uri)
423*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", ippOpString(con->request->request.op.operation_id), uri->values[0].string.text);
424*5e7646d2SAndroid Build Coastguard Worker 	  else
425*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", ippOpString(con->request->request.op.operation_id));
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker 	  switch (con->request->request.op.operation_id)
428*5e7646d2SAndroid Build Coastguard Worker 	  {
429*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_PRINT_JOB :
430*5e7646d2SAndroid Build Coastguard Worker 		print_job(con, uri);
431*5e7646d2SAndroid Build Coastguard Worker 		break;
432*5e7646d2SAndroid Build Coastguard Worker 
433*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_VALIDATE_JOB :
434*5e7646d2SAndroid Build Coastguard Worker 		validate_job(con, uri);
435*5e7646d2SAndroid Build Coastguard Worker 		break;
436*5e7646d2SAndroid Build Coastguard Worker 
437*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CREATE_JOB :
438*5e7646d2SAndroid Build Coastguard Worker 		create_job(con, uri);
439*5e7646d2SAndroid Build Coastguard Worker 		break;
440*5e7646d2SAndroid Build Coastguard Worker 
441*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_SEND_DOCUMENT :
442*5e7646d2SAndroid Build Coastguard Worker 		send_document(con, uri);
443*5e7646d2SAndroid Build Coastguard Worker 		break;
444*5e7646d2SAndroid Build Coastguard Worker 
445*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CANCEL_JOB :
446*5e7646d2SAndroid Build Coastguard Worker 		cancel_job(con, uri);
447*5e7646d2SAndroid Build Coastguard Worker 		break;
448*5e7646d2SAndroid Build Coastguard Worker 
449*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_JOB_ATTRIBUTES :
450*5e7646d2SAndroid Build Coastguard Worker 		get_job_attrs(con, uri);
451*5e7646d2SAndroid Build Coastguard Worker 		break;
452*5e7646d2SAndroid Build Coastguard Worker 
453*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_JOBS :
454*5e7646d2SAndroid Build Coastguard Worker 		get_jobs(con, uri);
455*5e7646d2SAndroid Build Coastguard Worker 		break;
456*5e7646d2SAndroid Build Coastguard Worker 
457*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_PRINTER_ATTRIBUTES :
458*5e7646d2SAndroid Build Coastguard Worker 		get_printer_attrs(con, uri);
459*5e7646d2SAndroid Build Coastguard Worker 		break;
460*5e7646d2SAndroid Build Coastguard Worker 
461*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_PRINTER_SUPPORTED_VALUES :
462*5e7646d2SAndroid Build Coastguard Worker 		get_printer_supported(con, uri);
463*5e7646d2SAndroid Build Coastguard Worker 		break;
464*5e7646d2SAndroid Build Coastguard Worker 
465*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_HOLD_JOB :
466*5e7646d2SAndroid Build Coastguard Worker 		hold_job(con, uri);
467*5e7646d2SAndroid Build Coastguard Worker 		break;
468*5e7646d2SAndroid Build Coastguard Worker 
469*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_RELEASE_JOB :
470*5e7646d2SAndroid Build Coastguard Worker 		release_job(con, uri);
471*5e7646d2SAndroid Build Coastguard Worker 		break;
472*5e7646d2SAndroid Build Coastguard Worker 
473*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_RESTART_JOB :
474*5e7646d2SAndroid Build Coastguard Worker 		restart_job(con, uri);
475*5e7646d2SAndroid Build Coastguard Worker 		break;
476*5e7646d2SAndroid Build Coastguard Worker 
477*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_PAUSE_PRINTER :
478*5e7646d2SAndroid Build Coastguard Worker 		stop_printer(con, uri);
479*5e7646d2SAndroid Build Coastguard Worker 		break;
480*5e7646d2SAndroid Build Coastguard Worker 
481*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_RESUME_PRINTER :
482*5e7646d2SAndroid Build Coastguard Worker 		start_printer(con, uri);
483*5e7646d2SAndroid Build Coastguard Worker 		break;
484*5e7646d2SAndroid Build Coastguard Worker 
485*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_PURGE_JOBS :
486*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CANCEL_JOBS :
487*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CANCEL_MY_JOBS :
488*5e7646d2SAndroid Build Coastguard Worker 		cancel_all_jobs(con, uri);
489*5e7646d2SAndroid Build Coastguard Worker 		break;
490*5e7646d2SAndroid Build Coastguard Worker 
491*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_SET_JOB_ATTRIBUTES :
492*5e7646d2SAndroid Build Coastguard Worker 		set_job_attrs(con, uri);
493*5e7646d2SAndroid Build Coastguard Worker 		break;
494*5e7646d2SAndroid Build Coastguard Worker 
495*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_SET_PRINTER_ATTRIBUTES :
496*5e7646d2SAndroid Build Coastguard Worker 		set_printer_attrs(con, uri);
497*5e7646d2SAndroid Build Coastguard Worker 		break;
498*5e7646d2SAndroid Build Coastguard Worker 
499*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_HOLD_NEW_JOBS :
500*5e7646d2SAndroid Build Coastguard Worker 		hold_new_jobs(con, uri);
501*5e7646d2SAndroid Build Coastguard Worker 		break;
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_RELEASE_HELD_NEW_JOBS :
504*5e7646d2SAndroid Build Coastguard Worker 		release_held_new_jobs(con, uri);
505*5e7646d2SAndroid Build Coastguard Worker 		break;
506*5e7646d2SAndroid Build Coastguard Worker 
507*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CLOSE_JOB :
508*5e7646d2SAndroid Build Coastguard Worker 		close_job(con, uri);
509*5e7646d2SAndroid Build Coastguard Worker 		break;
510*5e7646d2SAndroid Build Coastguard Worker 
511*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_DEFAULT :
512*5e7646d2SAndroid Build Coastguard Worker 		get_default(con);
513*5e7646d2SAndroid Build Coastguard Worker 		break;
514*5e7646d2SAndroid Build Coastguard Worker 
515*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_PRINTERS :
516*5e7646d2SAndroid Build Coastguard Worker 		get_printers(con, 0);
517*5e7646d2SAndroid Build Coastguard Worker 		break;
518*5e7646d2SAndroid Build Coastguard Worker 
519*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_CLASSES :
520*5e7646d2SAndroid Build Coastguard Worker 		get_printers(con, CUPS_PRINTER_CLASS);
521*5e7646d2SAndroid Build Coastguard Worker 		break;
522*5e7646d2SAndroid Build Coastguard Worker 
523*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_ADD_MODIFY_PRINTER :
524*5e7646d2SAndroid Build Coastguard Worker 		add_printer(con, uri);
525*5e7646d2SAndroid Build Coastguard Worker 		break;
526*5e7646d2SAndroid Build Coastguard Worker 
527*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_DELETE_PRINTER :
528*5e7646d2SAndroid Build Coastguard Worker 		delete_printer(con, uri);
529*5e7646d2SAndroid Build Coastguard Worker 		break;
530*5e7646d2SAndroid Build Coastguard Worker 
531*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_ADD_MODIFY_CLASS :
532*5e7646d2SAndroid Build Coastguard Worker 		add_class(con, uri);
533*5e7646d2SAndroid Build Coastguard Worker 		break;
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_DELETE_CLASS :
536*5e7646d2SAndroid Build Coastguard Worker 		delete_printer(con, uri);
537*5e7646d2SAndroid Build Coastguard Worker 		break;
538*5e7646d2SAndroid Build Coastguard Worker 
539*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_ACCEPT_JOBS :
540*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_ENABLE_PRINTER :
541*5e7646d2SAndroid Build Coastguard Worker 		accept_jobs(con, uri);
542*5e7646d2SAndroid Build Coastguard Worker 		break;
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_REJECT_JOBS :
545*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_DISABLE_PRINTER :
546*5e7646d2SAndroid Build Coastguard Worker 		reject_jobs(con, uri);
547*5e7646d2SAndroid Build Coastguard Worker 		break;
548*5e7646d2SAndroid Build Coastguard Worker 
549*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_SET_DEFAULT :
550*5e7646d2SAndroid Build Coastguard Worker 		set_default(con, uri);
551*5e7646d2SAndroid Build Coastguard Worker 		break;
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_DEVICES :
554*5e7646d2SAndroid Build Coastguard Worker 		get_devices(con);
555*5e7646d2SAndroid Build Coastguard Worker 		break;
556*5e7646d2SAndroid Build Coastguard Worker 
557*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_DOCUMENT :
558*5e7646d2SAndroid Build Coastguard Worker 		get_document(con, uri);
559*5e7646d2SAndroid Build Coastguard Worker 		break;
560*5e7646d2SAndroid Build Coastguard Worker 
561*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_PPD :
562*5e7646d2SAndroid Build Coastguard Worker 		get_ppd(con, uri);
563*5e7646d2SAndroid Build Coastguard Worker 		break;
564*5e7646d2SAndroid Build Coastguard Worker 
565*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_GET_PPDS :
566*5e7646d2SAndroid Build Coastguard Worker 		get_ppds(con);
567*5e7646d2SAndroid Build Coastguard Worker 		break;
568*5e7646d2SAndroid Build Coastguard Worker 
569*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_MOVE_JOB :
570*5e7646d2SAndroid Build Coastguard Worker 		move_job(con, uri);
571*5e7646d2SAndroid Build Coastguard Worker 		break;
572*5e7646d2SAndroid Build Coastguard Worker 
573*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_AUTHENTICATE_JOB :
574*5e7646d2SAndroid Build Coastguard Worker 		authenticate_job(con, uri);
575*5e7646d2SAndroid Build Coastguard Worker 		break;
576*5e7646d2SAndroid Build Coastguard Worker 
577*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS :
578*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CREATE_JOB_SUBSCRIPTIONS :
579*5e7646d2SAndroid Build Coastguard Worker 		create_subscriptions(con, uri);
580*5e7646d2SAndroid Build Coastguard Worker 		break;
581*5e7646d2SAndroid Build Coastguard Worker 
582*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES :
583*5e7646d2SAndroid Build Coastguard Worker 		get_subscription_attrs(con, sub_id);
584*5e7646d2SAndroid Build Coastguard Worker 		break;
585*5e7646d2SAndroid Build Coastguard Worker 
586*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_SUBSCRIPTIONS :
587*5e7646d2SAndroid Build Coastguard Worker 		get_subscriptions(con, uri);
588*5e7646d2SAndroid Build Coastguard Worker 		break;
589*5e7646d2SAndroid Build Coastguard Worker 
590*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_RENEW_SUBSCRIPTION :
591*5e7646d2SAndroid Build Coastguard Worker 		renew_subscription(con, sub_id);
592*5e7646d2SAndroid Build Coastguard Worker 		break;
593*5e7646d2SAndroid Build Coastguard Worker 
594*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CANCEL_SUBSCRIPTION :
595*5e7646d2SAndroid Build Coastguard Worker 		cancel_subscription(con, sub_id);
596*5e7646d2SAndroid Build Coastguard Worker 		break;
597*5e7646d2SAndroid Build Coastguard Worker 
598*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_GET_NOTIFICATIONS :
599*5e7646d2SAndroid Build Coastguard Worker 		get_notifications(con);
600*5e7646d2SAndroid Build Coastguard Worker 		break;
601*5e7646d2SAndroid Build Coastguard Worker 
602*5e7646d2SAndroid Build Coastguard Worker 	    case IPP_OP_CUPS_CREATE_LOCAL_PRINTER :
603*5e7646d2SAndroid Build Coastguard Worker 		create_local_printer(con);
604*5e7646d2SAndroid Build Coastguard Worker 		break;
605*5e7646d2SAndroid Build Coastguard Worker 
606*5e7646d2SAndroid Build Coastguard Worker 	    default :
607*5e7646d2SAndroid Build Coastguard Worker 		cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Operation %04X (%s) not supported.", IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, con->http->hostname, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
608*5e7646d2SAndroid Build Coastguard Worker 
609*5e7646d2SAndroid Build Coastguard Worker 		send_ipp_status(con, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, _("%s not supported."), ippOpString(con->request->request.op.operation_id));
610*5e7646d2SAndroid Build Coastguard Worker 		break;
611*5e7646d2SAndroid Build Coastguard Worker 	  }
612*5e7646d2SAndroid Build Coastguard Worker 	}
613*5e7646d2SAndroid Build Coastguard Worker       }
614*5e7646d2SAndroid Build Coastguard Worker     }
615*5e7646d2SAndroid Build Coastguard Worker   }
616*5e7646d2SAndroid Build Coastguard Worker 
617*5e7646d2SAndroid Build Coastguard Worker   if (con->response)
618*5e7646d2SAndroid Build Coastguard Worker   {
619*5e7646d2SAndroid Build Coastguard Worker    /*
620*5e7646d2SAndroid Build Coastguard Worker     * Sending data from the scheduler...
621*5e7646d2SAndroid Build Coastguard Worker     */
622*5e7646d2SAndroid Build Coastguard Worker 
623*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.",  ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname);
624*5e7646d2SAndroid Build Coastguard Worker 
625*5e7646d2SAndroid Build Coastguard Worker     httpClearFields(con->http);
626*5e7646d2SAndroid Build Coastguard Worker 
627*5e7646d2SAndroid Build Coastguard Worker #ifdef CUPSD_USE_CHUNKING
628*5e7646d2SAndroid Build Coastguard Worker    /*
629*5e7646d2SAndroid Build Coastguard Worker     * Because older versions of CUPS (1.1.17 and older) and some IPP
630*5e7646d2SAndroid Build Coastguard Worker     * clients do not implement chunking properly, we cannot use
631*5e7646d2SAndroid Build Coastguard Worker     * chunking by default.  This may become the default in future
632*5e7646d2SAndroid Build Coastguard Worker     * CUPS releases, or we might add a configuration directive for
633*5e7646d2SAndroid Build Coastguard Worker     * it.
634*5e7646d2SAndroid Build Coastguard Worker     */
635*5e7646d2SAndroid Build Coastguard Worker 
636*5e7646d2SAndroid Build Coastguard Worker     if (con->http->version == HTTP_1_1)
637*5e7646d2SAndroid Build Coastguard Worker     {
638*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked");
639*5e7646d2SAndroid Build Coastguard Worker       cupsdSetLength(con->http, 0);
640*5e7646d2SAndroid Build Coastguard Worker     }
641*5e7646d2SAndroid Build Coastguard Worker     else
642*5e7646d2SAndroid Build Coastguard Worker #endif /* CUPSD_USE_CHUNKING */
643*5e7646d2SAndroid Build Coastguard Worker     {
644*5e7646d2SAndroid Build Coastguard Worker       size_t	length;			/* Length of response */
645*5e7646d2SAndroid Build Coastguard Worker 
646*5e7646d2SAndroid Build Coastguard Worker 
647*5e7646d2SAndroid Build Coastguard Worker       length = ippLength(con->response);
648*5e7646d2SAndroid Build Coastguard Worker 
649*5e7646d2SAndroid Build Coastguard Worker       if (con->file >= 0 && !con->pipe_pid)
650*5e7646d2SAndroid Build Coastguard Worker       {
651*5e7646d2SAndroid Build Coastguard Worker 	struct stat	fileinfo;	/* File information */
652*5e7646d2SAndroid Build Coastguard Worker 
653*5e7646d2SAndroid Build Coastguard Worker 	if (!fstat(con->file, &fileinfo))
654*5e7646d2SAndroid Build Coastguard Worker 	  length += (size_t)fileinfo.st_size;
655*5e7646d2SAndroid Build Coastguard Worker       }
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length);
658*5e7646d2SAndroid Build Coastguard Worker       httpSetLength(con->http, length);
659*5e7646d2SAndroid Build Coastguard Worker     }
660*5e7646d2SAndroid Build Coastguard Worker 
661*5e7646d2SAndroid Build Coastguard Worker     if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE))
662*5e7646d2SAndroid Build Coastguard Worker     {
663*5e7646d2SAndroid Build Coastguard Worker      /*
664*5e7646d2SAndroid Build Coastguard Worker       * Tell the caller the response header was sent successfully...
665*5e7646d2SAndroid Build Coastguard Worker       */
666*5e7646d2SAndroid Build Coastguard Worker 
667*5e7646d2SAndroid Build Coastguard Worker       cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con);
668*5e7646d2SAndroid Build Coastguard Worker 
669*5e7646d2SAndroid Build Coastguard Worker       return (1);
670*5e7646d2SAndroid Build Coastguard Worker     }
671*5e7646d2SAndroid Build Coastguard Worker     else
672*5e7646d2SAndroid Build Coastguard Worker     {
673*5e7646d2SAndroid Build Coastguard Worker      /*
674*5e7646d2SAndroid Build Coastguard Worker       * Tell the caller the response header could not be sent...
675*5e7646d2SAndroid Build Coastguard Worker       */
676*5e7646d2SAndroid Build Coastguard Worker 
677*5e7646d2SAndroid Build Coastguard Worker       return (0);
678*5e7646d2SAndroid Build Coastguard Worker     }
679*5e7646d2SAndroid Build Coastguard Worker   }
680*5e7646d2SAndroid Build Coastguard Worker   else
681*5e7646d2SAndroid Build Coastguard Worker   {
682*5e7646d2SAndroid Build Coastguard Worker    /*
683*5e7646d2SAndroid Build Coastguard Worker     * Sending data from a subprocess like cups-deviced; tell the caller
684*5e7646d2SAndroid Build Coastguard Worker     * everything is A-OK so far...
685*5e7646d2SAndroid Build Coastguard Worker     */
686*5e7646d2SAndroid Build Coastguard Worker 
687*5e7646d2SAndroid Build Coastguard Worker     return (1);
688*5e7646d2SAndroid Build Coastguard Worker   }
689*5e7646d2SAndroid Build Coastguard Worker }
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker 
692*5e7646d2SAndroid Build Coastguard Worker /*
693*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdTimeoutJob()' - Timeout a job waiting on job files.
694*5e7646d2SAndroid Build Coastguard Worker  */
695*5e7646d2SAndroid Build Coastguard Worker 
696*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on error */
cupsdTimeoutJob(cupsd_job_t * job)697*5e7646d2SAndroid Build Coastguard Worker cupsdTimeoutJob(cupsd_job_t *job)	/* I - Job to timeout */
698*5e7646d2SAndroid Build Coastguard Worker {
699*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Destination printer or class */
700*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* job-sheets attribute */
701*5e7646d2SAndroid Build Coastguard Worker   int			kbytes;		/* Kilobytes in banner */
702*5e7646d2SAndroid Build Coastguard Worker 
703*5e7646d2SAndroid Build Coastguard Worker 
704*5e7646d2SAndroid Build Coastguard Worker   job->pending_timeout = 0;
705*5e7646d2SAndroid Build Coastguard Worker 
706*5e7646d2SAndroid Build Coastguard Worker  /*
707*5e7646d2SAndroid Build Coastguard Worker   * See if we need to add the ending sheet...
708*5e7646d2SAndroid Build Coastguard Worker   */
709*5e7646d2SAndroid Build Coastguard Worker 
710*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdLoadJob(job))
711*5e7646d2SAndroid Build Coastguard Worker     return (-1);
712*5e7646d2SAndroid Build Coastguard Worker 
713*5e7646d2SAndroid Build Coastguard Worker   printer = cupsdFindDest(job->dest);
714*5e7646d2SAndroid Build Coastguard Worker   attr    = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
715*5e7646d2SAndroid Build Coastguard Worker 
716*5e7646d2SAndroid Build Coastguard Worker   if (printer && !(printer->type & CUPS_PRINTER_REMOTE) &&
717*5e7646d2SAndroid Build Coastguard Worker       attr && attr->num_values > 1)
718*5e7646d2SAndroid Build Coastguard Worker   {
719*5e7646d2SAndroid Build Coastguard Worker    /*
720*5e7646d2SAndroid Build Coastguard Worker     * Yes...
721*5e7646d2SAndroid Build Coastguard Worker     */
722*5e7646d2SAndroid Build Coastguard Worker 
723*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_INFO, "Adding end banner page \"%s\".",
724*5e7646d2SAndroid Build Coastguard Worker                 attr->values[1].string.text);
725*5e7646d2SAndroid Build Coastguard Worker 
726*5e7646d2SAndroid Build Coastguard Worker     if ((kbytes = copy_banner(NULL, job, attr->values[1].string.text)) < 0)
727*5e7646d2SAndroid Build Coastguard Worker       return (-1);
728*5e7646d2SAndroid Build Coastguard Worker 
729*5e7646d2SAndroid Build Coastguard Worker     cupsdUpdateQuota(printer, job->username, 0, kbytes);
730*5e7646d2SAndroid Build Coastguard Worker   }
731*5e7646d2SAndroid Build Coastguard Worker 
732*5e7646d2SAndroid Build Coastguard Worker   return (0);
733*5e7646d2SAndroid Build Coastguard Worker }
734*5e7646d2SAndroid Build Coastguard Worker 
735*5e7646d2SAndroid Build Coastguard Worker 
736*5e7646d2SAndroid Build Coastguard Worker /*
737*5e7646d2SAndroid Build Coastguard Worker  * 'accept_jobs()' - Accept print jobs to a printer.
738*5e7646d2SAndroid Build Coastguard Worker  */
739*5e7646d2SAndroid Build Coastguard Worker 
740*5e7646d2SAndroid Build Coastguard Worker static void
accept_jobs(cupsd_client_t * con,ipp_attribute_t * uri)741*5e7646d2SAndroid Build Coastguard Worker accept_jobs(cupsd_client_t  *con,	/* I - Client connection */
742*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - Printer or class URI */
743*5e7646d2SAndroid Build Coastguard Worker {
744*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
745*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type (printer/class) */
746*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer data */
747*5e7646d2SAndroid Build Coastguard Worker 
748*5e7646d2SAndroid Build Coastguard Worker 
749*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con,
750*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
751*5e7646d2SAndroid Build Coastguard Worker 
752*5e7646d2SAndroid Build Coastguard Worker  /*
753*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
754*5e7646d2SAndroid Build Coastguard Worker   */
755*5e7646d2SAndroid Build Coastguard Worker 
756*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
757*5e7646d2SAndroid Build Coastguard Worker   {
758*5e7646d2SAndroid Build Coastguard Worker    /*
759*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
760*5e7646d2SAndroid Build Coastguard Worker     */
761*5e7646d2SAndroid Build Coastguard Worker 
762*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
763*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
764*5e7646d2SAndroid Build Coastguard Worker     return;
765*5e7646d2SAndroid Build Coastguard Worker   }
766*5e7646d2SAndroid Build Coastguard Worker 
767*5e7646d2SAndroid Build Coastguard Worker  /*
768*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
769*5e7646d2SAndroid Build Coastguard Worker   */
770*5e7646d2SAndroid Build Coastguard Worker 
771*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
772*5e7646d2SAndroid Build Coastguard Worker   {
773*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
774*5e7646d2SAndroid Build Coastguard Worker     return;
775*5e7646d2SAndroid Build Coastguard Worker   }
776*5e7646d2SAndroid Build Coastguard Worker 
777*5e7646d2SAndroid Build Coastguard Worker  /*
778*5e7646d2SAndroid Build Coastguard Worker   * Accept jobs sent to the printer...
779*5e7646d2SAndroid Build Coastguard Worker   */
780*5e7646d2SAndroid Build Coastguard Worker 
781*5e7646d2SAndroid Build Coastguard Worker   printer->accepting        = 1;
782*5e7646d2SAndroid Build Coastguard Worker   printer->state_message[0] = '\0';
783*5e7646d2SAndroid Build Coastguard Worker 
784*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
785*5e7646d2SAndroid Build Coastguard Worker                 "Now accepting jobs.");
786*5e7646d2SAndroid Build Coastguard Worker 
787*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
788*5e7646d2SAndroid Build Coastguard Worker   {
789*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
790*5e7646d2SAndroid Build Coastguard Worker 
791*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").",
792*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
793*5e7646d2SAndroid Build Coastguard Worker   }
794*5e7646d2SAndroid Build Coastguard Worker   else
795*5e7646d2SAndroid Build Coastguard Worker   {
796*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
797*5e7646d2SAndroid Build Coastguard Worker 
798*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
799*5e7646d2SAndroid Build Coastguard Worker                     "Printer \"%s\" now accepting jobs (\"%s\").",
800*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
801*5e7646d2SAndroid Build Coastguard Worker   }
802*5e7646d2SAndroid Build Coastguard Worker 
803*5e7646d2SAndroid Build Coastguard Worker  /*
804*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
805*5e7646d2SAndroid Build Coastguard Worker   */
806*5e7646d2SAndroid Build Coastguard Worker 
807*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
808*5e7646d2SAndroid Build Coastguard Worker }
809*5e7646d2SAndroid Build Coastguard Worker 
810*5e7646d2SAndroid Build Coastguard Worker 
811*5e7646d2SAndroid Build Coastguard Worker /*
812*5e7646d2SAndroid Build Coastguard Worker  * 'add_class()' - Add a class to the system.
813*5e7646d2SAndroid Build Coastguard Worker  */
814*5e7646d2SAndroid Build Coastguard Worker 
815*5e7646d2SAndroid Build Coastguard Worker static void
add_class(cupsd_client_t * con,ipp_attribute_t * uri)816*5e7646d2SAndroid Build Coastguard Worker add_class(cupsd_client_t  *con,		/* I - Client connection */
817*5e7646d2SAndroid Build Coastguard Worker           ipp_attribute_t *uri)		/* I - URI of class */
818*5e7646d2SAndroid Build Coastguard Worker {
819*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
820*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
821*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
822*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
823*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
824*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
825*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
826*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *pclass,		/* Class */
827*5e7646d2SAndroid Build Coastguard Worker 		*member;		/* Member printer/class */
828*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type */
829*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Printer attribute */
830*5e7646d2SAndroid Build Coastguard Worker   int		modify;			/* Non-zero if we just modified */
831*5e7646d2SAndroid Build Coastguard Worker   int		need_restart_job;	/* Need to restart job? */
832*5e7646d2SAndroid Build Coastguard Worker 
833*5e7646d2SAndroid Build Coastguard Worker 
834*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con,
835*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
836*5e7646d2SAndroid Build Coastguard Worker 
837*5e7646d2SAndroid Build Coastguard Worker  /*
838*5e7646d2SAndroid Build Coastguard Worker   * Do we have a valid URI?
839*5e7646d2SAndroid Build Coastguard Worker   */
840*5e7646d2SAndroid Build Coastguard Worker 
841*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
842*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), username, sizeof(username), host,
843*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
844*5e7646d2SAndroid Build Coastguard Worker 
845*5e7646d2SAndroid Build Coastguard Worker 
846*5e7646d2SAndroid Build Coastguard Worker   if (strncmp(resource, "/classes/", 9) || strlen(resource) == 9)
847*5e7646d2SAndroid Build Coastguard Worker   {
848*5e7646d2SAndroid Build Coastguard Worker    /*
849*5e7646d2SAndroid Build Coastguard Worker     * No, return an error...
850*5e7646d2SAndroid Build Coastguard Worker     */
851*5e7646d2SAndroid Build Coastguard Worker 
852*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
853*5e7646d2SAndroid Build Coastguard Worker                     _("The printer-uri must be of the form "
854*5e7646d2SAndroid Build Coastguard Worker 		      "\"ipp://HOSTNAME/classes/CLASSNAME\"."));
855*5e7646d2SAndroid Build Coastguard Worker     return;
856*5e7646d2SAndroid Build Coastguard Worker   }
857*5e7646d2SAndroid Build Coastguard Worker 
858*5e7646d2SAndroid Build Coastguard Worker  /*
859*5e7646d2SAndroid Build Coastguard Worker   * Do we have a valid printer name?
860*5e7646d2SAndroid Build Coastguard Worker   */
861*5e7646d2SAndroid Build Coastguard Worker 
862*5e7646d2SAndroid Build Coastguard Worker   if (!validate_name(resource + 9))
863*5e7646d2SAndroid Build Coastguard Worker   {
864*5e7646d2SAndroid Build Coastguard Worker    /*
865*5e7646d2SAndroid Build Coastguard Worker     * No, return an error...
866*5e7646d2SAndroid Build Coastguard Worker     */
867*5e7646d2SAndroid Build Coastguard Worker 
868*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
869*5e7646d2SAndroid Build Coastguard Worker                     _("The printer-uri \"%s\" contains invalid characters."),
870*5e7646d2SAndroid Build Coastguard Worker 		    uri->values[0].string.text);
871*5e7646d2SAndroid Build Coastguard Worker     return;
872*5e7646d2SAndroid Build Coastguard Worker   }
873*5e7646d2SAndroid Build Coastguard Worker 
874*5e7646d2SAndroid Build Coastguard Worker  /*
875*5e7646d2SAndroid Build Coastguard Worker   * See if the class already exists; if not, create a new class...
876*5e7646d2SAndroid Build Coastguard Worker   */
877*5e7646d2SAndroid Build Coastguard Worker 
878*5e7646d2SAndroid Build Coastguard Worker   if ((pclass = cupsdFindClass(resource + 9)) == NULL)
879*5e7646d2SAndroid Build Coastguard Worker   {
880*5e7646d2SAndroid Build Coastguard Worker    /*
881*5e7646d2SAndroid Build Coastguard Worker     * Class doesn't exist; see if we have a printer of the same name...
882*5e7646d2SAndroid Build Coastguard Worker     */
883*5e7646d2SAndroid Build Coastguard Worker 
884*5e7646d2SAndroid Build Coastguard Worker     if (cupsdFindPrinter(resource + 9))
885*5e7646d2SAndroid Build Coastguard Worker     {
886*5e7646d2SAndroid Build Coastguard Worker      /*
887*5e7646d2SAndroid Build Coastguard Worker       * Yes, return an error...
888*5e7646d2SAndroid Build Coastguard Worker       */
889*5e7646d2SAndroid Build Coastguard Worker 
890*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE,
891*5e7646d2SAndroid Build Coastguard Worker                       _("A printer named \"%s\" already exists."),
892*5e7646d2SAndroid Build Coastguard Worker 		      resource + 9);
893*5e7646d2SAndroid Build Coastguard Worker       return;
894*5e7646d2SAndroid Build Coastguard Worker     }
895*5e7646d2SAndroid Build Coastguard Worker 
896*5e7646d2SAndroid Build Coastguard Worker    /*
897*5e7646d2SAndroid Build Coastguard Worker     * No, check the default policy and then add the class...
898*5e7646d2SAndroid Build Coastguard Worker     */
899*5e7646d2SAndroid Build Coastguard Worker 
900*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
901*5e7646d2SAndroid Build Coastguard Worker     {
902*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, NULL);
903*5e7646d2SAndroid Build Coastguard Worker       return;
904*5e7646d2SAndroid Build Coastguard Worker     }
905*5e7646d2SAndroid Build Coastguard Worker 
906*5e7646d2SAndroid Build Coastguard Worker     pclass = cupsdAddClass(resource + 9);
907*5e7646d2SAndroid Build Coastguard Worker     modify = 0;
908*5e7646d2SAndroid Build Coastguard Worker 
909*5e7646d2SAndroid Build Coastguard Worker     pclass->printer_id = NextPrinterId ++;
910*5e7646d2SAndroid Build Coastguard Worker   }
911*5e7646d2SAndroid Build Coastguard Worker   else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con,
912*5e7646d2SAndroid Build Coastguard Worker                                       NULL)) != HTTP_OK)
913*5e7646d2SAndroid Build Coastguard Worker   {
914*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, pclass);
915*5e7646d2SAndroid Build Coastguard Worker     return;
916*5e7646d2SAndroid Build Coastguard Worker   }
917*5e7646d2SAndroid Build Coastguard Worker   else
918*5e7646d2SAndroid Build Coastguard Worker     modify = 1;
919*5e7646d2SAndroid Build Coastguard Worker 
920*5e7646d2SAndroid Build Coastguard Worker  /*
921*5e7646d2SAndroid Build Coastguard Worker   * Look for attributes and copy them over as needed...
922*5e7646d2SAndroid Build Coastguard Worker   */
923*5e7646d2SAndroid Build Coastguard Worker 
924*5e7646d2SAndroid Build Coastguard Worker   need_restart_job = 0;
925*5e7646d2SAndroid Build Coastguard Worker 
926*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL)
927*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&pclass->location, attr->values[0].string.text);
928*5e7646d2SAndroid Build Coastguard Worker 
929*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
930*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&pclass->geo_location, attr->values[0].string.text);
931*5e7646d2SAndroid Build Coastguard Worker 
932*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
933*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&pclass->organization, attr->values[0].string.text);
934*5e7646d2SAndroid Build Coastguard Worker 
935*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
936*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&pclass->organizational_unit, attr->values[0].string.text);
937*5e7646d2SAndroid Build Coastguard Worker 
938*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-info",
939*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
940*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&pclass->info, attr->values[0].string.text);
941*5e7646d2SAndroid Build Coastguard Worker 
942*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
943*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_BOOLEAN)) != NULL &&
944*5e7646d2SAndroid Build Coastguard Worker       attr->values[0].boolean != pclass->accepting)
945*5e7646d2SAndroid Build Coastguard Worker   {
946*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
947*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s printer-is-accepting-jobs to %d (was %d.)",
948*5e7646d2SAndroid Build Coastguard Worker                     pclass->name, attr->values[0].boolean, pclass->accepting);
949*5e7646d2SAndroid Build Coastguard Worker 
950*5e7646d2SAndroid Build Coastguard Worker     pclass->accepting = attr->values[0].boolean;
951*5e7646d2SAndroid Build Coastguard Worker 
952*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.",
953*5e7646d2SAndroid Build Coastguard Worker 		  pclass->accepting ? "Now" : "No longer");
954*5e7646d2SAndroid Build Coastguard Worker   }
955*5e7646d2SAndroid Build Coastguard Worker 
956*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
957*5e7646d2SAndroid Build Coastguard Worker   {
958*5e7646d2SAndroid Build Coastguard Worker     if (pclass->type & CUPS_PRINTER_REMOTE)
959*5e7646d2SAndroid Build Coastguard Worker     {
960*5e7646d2SAndroid Build Coastguard Worker      /*
961*5e7646d2SAndroid Build Coastguard Worker       * Cannot re-share remote printers.
962*5e7646d2SAndroid Build Coastguard Worker       */
963*5e7646d2SAndroid Build Coastguard Worker 
964*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
965*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
966*5e7646d2SAndroid Build Coastguard Worker 	cupsdDeletePrinter(pclass, 0);
967*5e7646d2SAndroid Build Coastguard Worker 
968*5e7646d2SAndroid Build Coastguard Worker       return;
969*5e7646d2SAndroid Build Coastguard Worker     }
970*5e7646d2SAndroid Build Coastguard Worker 
971*5e7646d2SAndroid Build Coastguard Worker     if (pclass->shared && !ippGetBoolean(attr, 0))
972*5e7646d2SAndroid Build Coastguard Worker       cupsdDeregisterPrinter(pclass, 1);
973*5e7646d2SAndroid Build Coastguard Worker 
974*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
975*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s printer-is-shared to %d (was %d.)",
976*5e7646d2SAndroid Build Coastguard Worker                     pclass->name, attr->values[0].boolean, pclass->shared);
977*5e7646d2SAndroid Build Coastguard Worker 
978*5e7646d2SAndroid Build Coastguard Worker     pclass->shared = ippGetBoolean(attr, 0);
979*5e7646d2SAndroid Build Coastguard Worker   }
980*5e7646d2SAndroid Build Coastguard Worker 
981*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state",
982*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ENUM)) != NULL)
983*5e7646d2SAndroid Build Coastguard Worker   {
984*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer != IPP_PRINTER_IDLE &&
985*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != IPP_PRINTER_STOPPED)
986*5e7646d2SAndroid Build Coastguard Worker     {
987*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
988*5e7646d2SAndroid Build Coastguard Worker                       _("Attempt to set %s printer-state to bad value %d."),
989*5e7646d2SAndroid Build Coastguard Worker                       pclass->name, attr->values[0].integer);
990*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
991*5e7646d2SAndroid Build Coastguard Worker 	cupsdDeletePrinter(pclass, 0);
992*5e7646d2SAndroid Build Coastguard Worker 
993*5e7646d2SAndroid Build Coastguard Worker       return;
994*5e7646d2SAndroid Build Coastguard Worker     }
995*5e7646d2SAndroid Build Coastguard Worker 
996*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
997*5e7646d2SAndroid Build Coastguard Worker                     pclass->name, attr->values[0].integer, pclass->state);
998*5e7646d2SAndroid Build Coastguard Worker 
999*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1000*5e7646d2SAndroid Build Coastguard Worker       cupsdStopPrinter(pclass, 0);
1001*5e7646d2SAndroid Build Coastguard Worker     else
1002*5e7646d2SAndroid Build Coastguard Worker     {
1003*5e7646d2SAndroid Build Coastguard Worker       cupsdSetPrinterState(pclass, (ipp_pstate_t)(attr->values[0].integer), 0);
1004*5e7646d2SAndroid Build Coastguard Worker       need_restart_job = 1;
1005*5e7646d2SAndroid Build Coastguard Worker     }
1006*5e7646d2SAndroid Build Coastguard Worker   }
1007*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state-message",
1008*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
1009*5e7646d2SAndroid Build Coastguard Worker   {
1010*5e7646d2SAndroid Build Coastguard Worker     strlcpy(pclass->state_message, attr->values[0].string.text,
1011*5e7646d2SAndroid Build Coastguard Worker             sizeof(pclass->state_message));
1012*5e7646d2SAndroid Build Coastguard Worker 
1013*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s",
1014*5e7646d2SAndroid Build Coastguard Worker                   pclass->state_message);
1015*5e7646d2SAndroid Build Coastguard Worker   }
1016*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "member-uris",
1017*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_URI)) != NULL)
1018*5e7646d2SAndroid Build Coastguard Worker   {
1019*5e7646d2SAndroid Build Coastguard Worker    /*
1020*5e7646d2SAndroid Build Coastguard Worker     * Clear the printer array as needed...
1021*5e7646d2SAndroid Build Coastguard Worker     */
1022*5e7646d2SAndroid Build Coastguard Worker 
1023*5e7646d2SAndroid Build Coastguard Worker     need_restart_job = 1;
1024*5e7646d2SAndroid Build Coastguard Worker 
1025*5e7646d2SAndroid Build Coastguard Worker     if (pclass->num_printers > 0)
1026*5e7646d2SAndroid Build Coastguard Worker     {
1027*5e7646d2SAndroid Build Coastguard Worker       free(pclass->printers);
1028*5e7646d2SAndroid Build Coastguard Worker       pclass->num_printers = 0;
1029*5e7646d2SAndroid Build Coastguard Worker     }
1030*5e7646d2SAndroid Build Coastguard Worker 
1031*5e7646d2SAndroid Build Coastguard Worker    /*
1032*5e7646d2SAndroid Build Coastguard Worker     * Add each printer or class that is listed...
1033*5e7646d2SAndroid Build Coastguard Worker     */
1034*5e7646d2SAndroid Build Coastguard Worker 
1035*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < attr->num_values; i ++)
1036*5e7646d2SAndroid Build Coastguard Worker     {
1037*5e7646d2SAndroid Build Coastguard Worker      /*
1038*5e7646d2SAndroid Build Coastguard Worker       * Search for the printer or class URI...
1039*5e7646d2SAndroid Build Coastguard Worker       */
1040*5e7646d2SAndroid Build Coastguard Worker 
1041*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdValidateDest(attr->values[i].string.text, &dtype, &member))
1042*5e7646d2SAndroid Build Coastguard Worker       {
1043*5e7646d2SAndroid Build Coastguard Worker        /*
1044*5e7646d2SAndroid Build Coastguard Worker 	* Bad URI...
1045*5e7646d2SAndroid Build Coastguard Worker 	*/
1046*5e7646d2SAndroid Build Coastguard Worker 
1047*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND,
1048*5e7646d2SAndroid Build Coastguard Worker                 	_("The printer or class does not exist."));
1049*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
1050*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(pclass, 0);
1051*5e7646d2SAndroid Build Coastguard Worker 
1052*5e7646d2SAndroid Build Coastguard Worker 	return;
1053*5e7646d2SAndroid Build Coastguard Worker       }
1054*5e7646d2SAndroid Build Coastguard Worker       else if (dtype & CUPS_PRINTER_CLASS)
1055*5e7646d2SAndroid Build Coastguard Worker       {
1056*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_BAD_REQUEST,
1057*5e7646d2SAndroid Build Coastguard Worker 			_("Nested classes are not allowed."));
1058*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
1059*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(pclass, 0);
1060*5e7646d2SAndroid Build Coastguard Worker 
1061*5e7646d2SAndroid Build Coastguard Worker         return;
1062*5e7646d2SAndroid Build Coastguard Worker       }
1063*5e7646d2SAndroid Build Coastguard Worker 
1064*5e7646d2SAndroid Build Coastguard Worker      /*
1065*5e7646d2SAndroid Build Coastguard Worker       * Add it to the class...
1066*5e7646d2SAndroid Build Coastguard Worker       */
1067*5e7646d2SAndroid Build Coastguard Worker 
1068*5e7646d2SAndroid Build Coastguard Worker       cupsdAddPrinterToClass(pclass, member);
1069*5e7646d2SAndroid Build Coastguard Worker     }
1070*5e7646d2SAndroid Build Coastguard Worker   }
1071*5e7646d2SAndroid Build Coastguard Worker 
1072*5e7646d2SAndroid Build Coastguard Worker   if (!set_printer_defaults(con, pclass))
1073*5e7646d2SAndroid Build Coastguard Worker   {
1074*5e7646d2SAndroid Build Coastguard Worker     if (!modify)
1075*5e7646d2SAndroid Build Coastguard Worker       cupsdDeletePrinter(pclass, 0);
1076*5e7646d2SAndroid Build Coastguard Worker 
1077*5e7646d2SAndroid Build Coastguard Worker     return;
1078*5e7646d2SAndroid Build Coastguard Worker   }
1079*5e7646d2SAndroid Build Coastguard Worker 
1080*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "auth-info-required",
1081*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
1082*5e7646d2SAndroid Build Coastguard Worker     cupsdSetAuthInfoRequired(pclass, NULL, attr);
1083*5e7646d2SAndroid Build Coastguard Worker 
1084*5e7646d2SAndroid Build Coastguard Worker   pclass->config_time = time(NULL);
1085*5e7646d2SAndroid Build Coastguard Worker 
1086*5e7646d2SAndroid Build Coastguard Worker  /*
1087*5e7646d2SAndroid Build Coastguard Worker   * Update the printer class attributes and return...
1088*5e7646d2SAndroid Build Coastguard Worker   */
1089*5e7646d2SAndroid Build Coastguard Worker 
1090*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterAttrs(pclass);
1091*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
1092*5e7646d2SAndroid Build Coastguard Worker 
1093*5e7646d2SAndroid Build Coastguard Worker   if (need_restart_job && pclass->job)
1094*5e7646d2SAndroid Build Coastguard Worker   {
1095*5e7646d2SAndroid Build Coastguard Worker    /*
1096*5e7646d2SAndroid Build Coastguard Worker     * Reset the current job to a "pending" status...
1097*5e7646d2SAndroid Build Coastguard Worker     */
1098*5e7646d2SAndroid Build Coastguard Worker 
1099*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(pclass->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
1100*5e7646d2SAndroid Build Coastguard Worker                      "Job restarted because the class was modified.");
1101*5e7646d2SAndroid Build Coastguard Worker   }
1102*5e7646d2SAndroid Build Coastguard Worker 
1103*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
1104*5e7646d2SAndroid Build Coastguard Worker 
1105*5e7646d2SAndroid Build Coastguard Worker   if (modify)
1106*5e7646d2SAndroid Build Coastguard Worker   {
1107*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
1108*5e7646d2SAndroid Build Coastguard Worker 		  pclass, NULL, "Class \"%s\" modified by \"%s\".",
1109*5e7646d2SAndroid Build Coastguard Worker 		  pclass->name, get_username(con));
1110*5e7646d2SAndroid Build Coastguard Worker 
1111*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".",
1112*5e7646d2SAndroid Build Coastguard Worker                     pclass->name, get_username(con));
1113*5e7646d2SAndroid Build Coastguard Worker   }
1114*5e7646d2SAndroid Build Coastguard Worker   else
1115*5e7646d2SAndroid Build Coastguard Worker   {
1116*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
1117*5e7646d2SAndroid Build Coastguard Worker 		  pclass, NULL, "New class \"%s\" added by \"%s\".",
1118*5e7646d2SAndroid Build Coastguard Worker 		  pclass->name, get_username(con));
1119*5e7646d2SAndroid Build Coastguard Worker 
1120*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".",
1121*5e7646d2SAndroid Build Coastguard Worker                     pclass->name, get_username(con));
1122*5e7646d2SAndroid Build Coastguard Worker   }
1123*5e7646d2SAndroid Build Coastguard Worker 
1124*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
1125*5e7646d2SAndroid Build Coastguard Worker }
1126*5e7646d2SAndroid Build Coastguard Worker 
1127*5e7646d2SAndroid Build Coastguard Worker 
1128*5e7646d2SAndroid Build Coastguard Worker /*
1129*5e7646d2SAndroid Build Coastguard Worker  * 'add_file()' - Add a file to a job.
1130*5e7646d2SAndroid Build Coastguard Worker  */
1131*5e7646d2SAndroid Build Coastguard Worker 
1132*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on error */
add_file(cupsd_client_t * con,cupsd_job_t * job,mime_type_t * filetype,int compression)1133*5e7646d2SAndroid Build Coastguard Worker add_file(cupsd_client_t *con,		/* I - Connection to client */
1134*5e7646d2SAndroid Build Coastguard Worker          cupsd_job_t    *job,		/* I - Job to add to */
1135*5e7646d2SAndroid Build Coastguard Worker          mime_type_t    *filetype,	/* I - Type of file */
1136*5e7646d2SAndroid Build Coastguard Worker 	 int            compression)	/* I - Compression */
1137*5e7646d2SAndroid Build Coastguard Worker {
1138*5e7646d2SAndroid Build Coastguard Worker   mime_type_t	**filetypes;		/* New filetypes array... */
1139*5e7646d2SAndroid Build Coastguard Worker   int		*compressions;		/* New compressions array... */
1140*5e7646d2SAndroid Build Coastguard Worker 
1141*5e7646d2SAndroid Build Coastguard Worker 
1142*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
1143*5e7646d2SAndroid Build Coastguard Worker         	  "add_file(con=%p[%d], job=%d, filetype=%s/%s, "
1144*5e7646d2SAndroid Build Coastguard Worker 		  "compression=%d)", con, con ? con->number : -1, job->id,
1145*5e7646d2SAndroid Build Coastguard Worker 		  filetype->super, filetype->type, compression);
1146*5e7646d2SAndroid Build Coastguard Worker 
1147*5e7646d2SAndroid Build Coastguard Worker  /*
1148*5e7646d2SAndroid Build Coastguard Worker   * Add the file to the job...
1149*5e7646d2SAndroid Build Coastguard Worker   */
1150*5e7646d2SAndroid Build Coastguard Worker 
1151*5e7646d2SAndroid Build Coastguard Worker   if (job->num_files == 0)
1152*5e7646d2SAndroid Build Coastguard Worker   {
1153*5e7646d2SAndroid Build Coastguard Worker     compressions = (int *)malloc(sizeof(int));
1154*5e7646d2SAndroid Build Coastguard Worker     filetypes    = (mime_type_t **)malloc(sizeof(mime_type_t *));
1155*5e7646d2SAndroid Build Coastguard Worker   }
1156*5e7646d2SAndroid Build Coastguard Worker   else
1157*5e7646d2SAndroid Build Coastguard Worker   {
1158*5e7646d2SAndroid Build Coastguard Worker     compressions = (int *)realloc(job->compressions,
1159*5e7646d2SAndroid Build Coastguard Worker                                   (size_t)(job->num_files + 1) * sizeof(int));
1160*5e7646d2SAndroid Build Coastguard Worker     filetypes    = (mime_type_t **)realloc(job->filetypes,
1161*5e7646d2SAndroid Build Coastguard Worker                                            (size_t)(job->num_files + 1) *
1162*5e7646d2SAndroid Build Coastguard Worker 					   sizeof(mime_type_t *));
1163*5e7646d2SAndroid Build Coastguard Worker   }
1164*5e7646d2SAndroid Build Coastguard Worker 
1165*5e7646d2SAndroid Build Coastguard Worker   if (compressions)
1166*5e7646d2SAndroid Build Coastguard Worker     job->compressions = compressions;
1167*5e7646d2SAndroid Build Coastguard Worker 
1168*5e7646d2SAndroid Build Coastguard Worker   if (filetypes)
1169*5e7646d2SAndroid Build Coastguard Worker     job->filetypes = filetypes;
1170*5e7646d2SAndroid Build Coastguard Worker 
1171*5e7646d2SAndroid Build Coastguard Worker   if (!compressions || !filetypes)
1172*5e7646d2SAndroid Build Coastguard Worker   {
1173*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
1174*5e7646d2SAndroid Build Coastguard Worker                      "Job aborted because the scheduler ran out of memory.");
1175*5e7646d2SAndroid Build Coastguard Worker 
1176*5e7646d2SAndroid Build Coastguard Worker     if (con)
1177*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_INTERNAL_ERROR,
1178*5e7646d2SAndroid Build Coastguard Worker 		      _("Unable to allocate memory for file types."));
1179*5e7646d2SAndroid Build Coastguard Worker 
1180*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1181*5e7646d2SAndroid Build Coastguard Worker   }
1182*5e7646d2SAndroid Build Coastguard Worker 
1183*5e7646d2SAndroid Build Coastguard Worker   job->compressions[job->num_files] = compression;
1184*5e7646d2SAndroid Build Coastguard Worker   job->filetypes[job->num_files]    = filetype;
1185*5e7646d2SAndroid Build Coastguard Worker 
1186*5e7646d2SAndroid Build Coastguard Worker   job->num_files ++;
1187*5e7646d2SAndroid Build Coastguard Worker 
1188*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
1189*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
1190*5e7646d2SAndroid Build Coastguard Worker 
1191*5e7646d2SAndroid Build Coastguard Worker   return (0);
1192*5e7646d2SAndroid Build Coastguard Worker }
1193*5e7646d2SAndroid Build Coastguard Worker 
1194*5e7646d2SAndroid Build Coastguard Worker 
1195*5e7646d2SAndroid Build Coastguard Worker /*
1196*5e7646d2SAndroid Build Coastguard Worker  * 'add_job()' - Add a job to a print queue.
1197*5e7646d2SAndroid Build Coastguard Worker  */
1198*5e7646d2SAndroid Build Coastguard Worker 
1199*5e7646d2SAndroid Build Coastguard Worker static cupsd_job_t *			/* O - Job object */
add_job(cupsd_client_t * con,cupsd_printer_t * printer,mime_type_t * filetype)1200*5e7646d2SAndroid Build Coastguard Worker add_job(cupsd_client_t  *con,		/* I - Client connection */
1201*5e7646d2SAndroid Build Coastguard Worker 	cupsd_printer_t *printer,	/* I - Destination printer */
1202*5e7646d2SAndroid Build Coastguard Worker 	mime_type_t     *filetype)	/* I - First print file type, if any */
1203*5e7646d2SAndroid Build Coastguard Worker {
1204*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
1205*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr,		/* Current attribute */
1206*5e7646d2SAndroid Build Coastguard Worker 		*auth_info;		/* auth-info attribute */
1207*5e7646d2SAndroid Build Coastguard Worker   const char	*mandatory;		/* Current mandatory job attribute */
1208*5e7646d2SAndroid Build Coastguard Worker   const char	*val;			/* Default option value */
1209*5e7646d2SAndroid Build Coastguard Worker   int		priority;		/* Job priority */
1210*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
1211*5e7646d2SAndroid Build Coastguard Worker   char		job_uri[HTTP_MAX_URI];	/* Job URI */
1212*5e7646d2SAndroid Build Coastguard Worker   int		kbytes;			/* Size of print file */
1213*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
1214*5e7646d2SAndroid Build Coastguard Worker   int		lowerpagerange;		/* Page range bound */
1215*5e7646d2SAndroid Build Coastguard Worker   int		exact;			/* Did we have an exact match? */
1216*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *media_col,		/* media-col attribute */
1217*5e7646d2SAndroid Build Coastguard Worker 		*media_margin;		/* media-*-margin attribute */
1218*5e7646d2SAndroid Build Coastguard Worker   ipp_t		*unsup_col;		/* media-col in unsupported response */
1219*5e7646d2SAndroid Build Coastguard Worker   static const char * const readonly[] =/* List of read-only attributes */
1220*5e7646d2SAndroid Build Coastguard Worker   {
1221*5e7646d2SAndroid Build Coastguard Worker     "date-time-at-completed",
1222*5e7646d2SAndroid Build Coastguard Worker     "date-time-at-creation",
1223*5e7646d2SAndroid Build Coastguard Worker     "date-time-at-processing",
1224*5e7646d2SAndroid Build Coastguard Worker     "job-detailed-status-messages",
1225*5e7646d2SAndroid Build Coastguard Worker     "job-document-access-errors",
1226*5e7646d2SAndroid Build Coastguard Worker     "job-id",
1227*5e7646d2SAndroid Build Coastguard Worker     "job-impressions-completed",
1228*5e7646d2SAndroid Build Coastguard Worker     "job-k-octets-completed",
1229*5e7646d2SAndroid Build Coastguard Worker     "job-media-sheets-completed",
1230*5e7646d2SAndroid Build Coastguard Worker     "job-pages-completed",
1231*5e7646d2SAndroid Build Coastguard Worker     "job-printer-up-time",
1232*5e7646d2SAndroid Build Coastguard Worker     "job-printer-uri",
1233*5e7646d2SAndroid Build Coastguard Worker     "job-state",
1234*5e7646d2SAndroid Build Coastguard Worker     "job-state-message",
1235*5e7646d2SAndroid Build Coastguard Worker     "job-state-reasons",
1236*5e7646d2SAndroid Build Coastguard Worker     "job-uri",
1237*5e7646d2SAndroid Build Coastguard Worker     "number-of-documents",
1238*5e7646d2SAndroid Build Coastguard Worker     "number-of-intervening-jobs",
1239*5e7646d2SAndroid Build Coastguard Worker     "output-device-assigned",
1240*5e7646d2SAndroid Build Coastguard Worker     "time-at-completed",
1241*5e7646d2SAndroid Build Coastguard Worker     "time-at-creation",
1242*5e7646d2SAndroid Build Coastguard Worker     "time-at-processing"
1243*5e7646d2SAndroid Build Coastguard Worker   };
1244*5e7646d2SAndroid Build Coastguard Worker 
1245*5e7646d2SAndroid Build Coastguard Worker 
1246*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
1247*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, printer, printer->name,
1248*5e7646d2SAndroid Build Coastguard Worker 		  filetype, filetype ? filetype->super : "none",
1249*5e7646d2SAndroid Build Coastguard Worker 		  filetype ? filetype->type : "none");
1250*5e7646d2SAndroid Build Coastguard Worker 
1251*5e7646d2SAndroid Build Coastguard Worker  /*
1252*5e7646d2SAndroid Build Coastguard Worker   * Check remote printing to non-shared printer...
1253*5e7646d2SAndroid Build Coastguard Worker   */
1254*5e7646d2SAndroid Build Coastguard Worker 
1255*5e7646d2SAndroid Build Coastguard Worker   if (!printer->shared &&
1256*5e7646d2SAndroid Build Coastguard Worker       _cups_strcasecmp(con->http->hostname, "localhost") &&
1257*5e7646d2SAndroid Build Coastguard Worker       _cups_strcasecmp(con->http->hostname, ServerName))
1258*5e7646d2SAndroid Build Coastguard Worker   {
1259*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_AUTHORIZED,
1260*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class is not shared."));
1261*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1262*5e7646d2SAndroid Build Coastguard Worker   }
1263*5e7646d2SAndroid Build Coastguard Worker 
1264*5e7646d2SAndroid Build Coastguard Worker  /*
1265*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
1266*5e7646d2SAndroid Build Coastguard Worker   */
1267*5e7646d2SAndroid Build Coastguard Worker 
1268*5e7646d2SAndroid Build Coastguard Worker   auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
1269*5e7646d2SAndroid Build Coastguard Worker 
1270*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
1271*5e7646d2SAndroid Build Coastguard Worker   {
1272*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
1273*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1274*5e7646d2SAndroid Build Coastguard Worker   }
1275*5e7646d2SAndroid Build Coastguard Worker   else if (printer->num_auth_info_required == 1 &&
1276*5e7646d2SAndroid Build Coastguard Worker            !strcmp(printer->auth_info_required[0], "negotiate") &&
1277*5e7646d2SAndroid Build Coastguard Worker            !con->username[0])
1278*5e7646d2SAndroid Build Coastguard Worker   {
1279*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, HTTP_UNAUTHORIZED, printer);
1280*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1281*5e7646d2SAndroid Build Coastguard Worker   }
1282*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
1283*5e7646d2SAndroid Build Coastguard Worker   else if (auth_info && !con->http->tls &&
1284*5e7646d2SAndroid Build Coastguard Worker            !httpAddrLocalhost(con->http->hostaddr))
1285*5e7646d2SAndroid Build Coastguard Worker   {
1286*5e7646d2SAndroid Build Coastguard Worker    /*
1287*5e7646d2SAndroid Build Coastguard Worker     * Require encryption of auth-info over non-local connections...
1288*5e7646d2SAndroid Build Coastguard Worker     */
1289*5e7646d2SAndroid Build Coastguard Worker 
1290*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
1291*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1292*5e7646d2SAndroid Build Coastguard Worker   }
1293*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
1294*5e7646d2SAndroid Build Coastguard Worker 
1295*5e7646d2SAndroid Build Coastguard Worker  /*
1296*5e7646d2SAndroid Build Coastguard Worker   * See if the printer is accepting jobs...
1297*5e7646d2SAndroid Build Coastguard Worker   */
1298*5e7646d2SAndroid Build Coastguard Worker 
1299*5e7646d2SAndroid Build Coastguard Worker   if (!printer->accepting)
1300*5e7646d2SAndroid Build Coastguard Worker   {
1301*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_ACCEPTING,
1302*5e7646d2SAndroid Build Coastguard Worker                     _("Destination \"%s\" is not accepting jobs."),
1303*5e7646d2SAndroid Build Coastguard Worker                     printer->name);
1304*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1305*5e7646d2SAndroid Build Coastguard Worker   }
1306*5e7646d2SAndroid Build Coastguard Worker 
1307*5e7646d2SAndroid Build Coastguard Worker  /*
1308*5e7646d2SAndroid Build Coastguard Worker   * Validate job template attributes; for now just document-format,
1309*5e7646d2SAndroid Build Coastguard Worker   * copies, job-sheets, number-up, page-ranges, mandatory attributes, and
1310*5e7646d2SAndroid Build Coastguard Worker   * media...
1311*5e7646d2SAndroid Build Coastguard Worker   */
1312*5e7646d2SAndroid Build Coastguard Worker 
1313*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < (int)(sizeof(readonly) / sizeof(readonly[0])); i ++)
1314*5e7646d2SAndroid Build Coastguard Worker   {
1315*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, readonly[i], IPP_TAG_ZERO)) != NULL)
1316*5e7646d2SAndroid Build Coastguard Worker     {
1317*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(con->request, attr);
1318*5e7646d2SAndroid Build Coastguard Worker 
1319*5e7646d2SAndroid Build Coastguard Worker       if (StrictConformance)
1320*5e7646d2SAndroid Build Coastguard Worker       {
1321*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_BAD_REQUEST, _("The '%s' Job Status attribute cannot be supplied in a job creation request."), readonly[i]);
1322*5e7646d2SAndroid Build Coastguard Worker 	return (NULL);
1323*5e7646d2SAndroid Build Coastguard Worker       }
1324*5e7646d2SAndroid Build Coastguard Worker 
1325*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Unexpected '%s' Job Status attribute in a job creation request.", readonly[i]);
1326*5e7646d2SAndroid Build Coastguard Worker     }
1327*5e7646d2SAndroid Build Coastguard Worker   }
1328*5e7646d2SAndroid Build Coastguard Worker 
1329*5e7646d2SAndroid Build Coastguard Worker   if (printer->pc)
1330*5e7646d2SAndroid Build Coastguard Worker   {
1331*5e7646d2SAndroid Build Coastguard Worker     for (mandatory = (char *)cupsArrayFirst(printer->pc->mandatory);
1332*5e7646d2SAndroid Build Coastguard Worker 	 mandatory;
1333*5e7646d2SAndroid Build Coastguard Worker 	 mandatory = (char *)cupsArrayNext(printer->pc->mandatory))
1334*5e7646d2SAndroid Build Coastguard Worker     {
1335*5e7646d2SAndroid Build Coastguard Worker       if (!ippFindAttribute(con->request, mandatory, IPP_TAG_ZERO))
1336*5e7646d2SAndroid Build Coastguard Worker       {
1337*5e7646d2SAndroid Build Coastguard Worker        /*
1338*5e7646d2SAndroid Build Coastguard Worker 	* Missing a required attribute...
1339*5e7646d2SAndroid Build Coastguard Worker 	*/
1340*5e7646d2SAndroid Build Coastguard Worker 
1341*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_CONFLICT,
1342*5e7646d2SAndroid Build Coastguard Worker 			_("The \"%s\" attribute is required for print jobs."),
1343*5e7646d2SAndroid Build Coastguard Worker 			mandatory);
1344*5e7646d2SAndroid Build Coastguard Worker 	return (NULL);
1345*5e7646d2SAndroid Build Coastguard Worker       }
1346*5e7646d2SAndroid Build Coastguard Worker     }
1347*5e7646d2SAndroid Build Coastguard Worker   }
1348*5e7646d2SAndroid Build Coastguard Worker 
1349*5e7646d2SAndroid Build Coastguard Worker   if (filetype && printer->filetypes &&
1350*5e7646d2SAndroid Build Coastguard Worker       !cupsArrayFind(printer->filetypes, filetype))
1351*5e7646d2SAndroid Build Coastguard Worker   {
1352*5e7646d2SAndroid Build Coastguard Worker     char	mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
1353*5e7646d2SAndroid Build Coastguard Worker 					/* MIME media type string */
1354*5e7646d2SAndroid Build Coastguard Worker 
1355*5e7646d2SAndroid Build Coastguard Worker 
1356*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
1357*5e7646d2SAndroid Build Coastguard Worker              filetype->type);
1358*5e7646d2SAndroid Build Coastguard Worker 
1359*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_DOCUMENT_FORMAT,
1360*5e7646d2SAndroid Build Coastguard Worker                     _("Unsupported format \"%s\"."), mimetype);
1361*5e7646d2SAndroid Build Coastguard Worker 
1362*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
1363*5e7646d2SAndroid Build Coastguard Worker                  "document-format", NULL, mimetype);
1364*5e7646d2SAndroid Build Coastguard Worker 
1365*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1366*5e7646d2SAndroid Build Coastguard Worker   }
1367*5e7646d2SAndroid Build Coastguard Worker 
1368*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "copies",
1369*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
1370*5e7646d2SAndroid Build Coastguard Worker   {
1371*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies)
1372*5e7646d2SAndroid Build Coastguard Worker     {
1373*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."),
1374*5e7646d2SAndroid Build Coastguard Worker                       attr->values[0].integer);
1375*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
1376*5e7646d2SAndroid Build Coastguard Worker 	            "copies", attr->values[0].integer);
1377*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1378*5e7646d2SAndroid Build Coastguard Worker     }
1379*5e7646d2SAndroid Build Coastguard Worker   }
1380*5e7646d2SAndroid Build Coastguard Worker 
1381*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-sheets",
1382*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ZERO)) != NULL)
1383*5e7646d2SAndroid Build Coastguard Worker   {
1384*5e7646d2SAndroid Build Coastguard Worker     if (attr->value_tag != IPP_TAG_KEYWORD &&
1385*5e7646d2SAndroid Build Coastguard Worker         attr->value_tag != IPP_TAG_NAME)
1386*5e7646d2SAndroid Build Coastguard Worker     {
1387*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type."));
1388*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1389*5e7646d2SAndroid Build Coastguard Worker     }
1390*5e7646d2SAndroid Build Coastguard Worker 
1391*5e7646d2SAndroid Build Coastguard Worker     if (attr->num_values > 2)
1392*5e7646d2SAndroid Build Coastguard Worker     {
1393*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
1394*5e7646d2SAndroid Build Coastguard Worker                       _("Too many job-sheets values (%d > 2)."),
1395*5e7646d2SAndroid Build Coastguard Worker 		      attr->num_values);
1396*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1397*5e7646d2SAndroid Build Coastguard Worker     }
1398*5e7646d2SAndroid Build Coastguard Worker 
1399*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < attr->num_values; i ++)
1400*5e7646d2SAndroid Build Coastguard Worker       if (strcmp(attr->values[i].string.text, "none") &&
1401*5e7646d2SAndroid Build Coastguard Worker           !cupsdFindBanner(attr->values[i].string.text))
1402*5e7646d2SAndroid Build Coastguard Worker       {
1403*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"."),
1404*5e7646d2SAndroid Build Coastguard Worker 			attr->values[i].string.text);
1405*5e7646d2SAndroid Build Coastguard Worker 	return (NULL);
1406*5e7646d2SAndroid Build Coastguard Worker       }
1407*5e7646d2SAndroid Build Coastguard Worker   }
1408*5e7646d2SAndroid Build Coastguard Worker 
1409*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "number-up",
1410*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
1411*5e7646d2SAndroid Build Coastguard Worker   {
1412*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer != 1 &&
1413*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != 2 &&
1414*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != 4 &&
1415*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != 6 &&
1416*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != 9 &&
1417*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != 16)
1418*5e7646d2SAndroid Build Coastguard Worker     {
1419*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES, _("Bad number-up value %d."),
1420*5e7646d2SAndroid Build Coastguard Worker                       attr->values[0].integer);
1421*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
1422*5e7646d2SAndroid Build Coastguard Worker 	            "number-up", attr->values[0].integer);
1423*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1424*5e7646d2SAndroid Build Coastguard Worker     }
1425*5e7646d2SAndroid Build Coastguard Worker   }
1426*5e7646d2SAndroid Build Coastguard Worker 
1427*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "page-ranges",
1428*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_RANGE)) != NULL)
1429*5e7646d2SAndroid Build Coastguard Worker   {
1430*5e7646d2SAndroid Build Coastguard Worker     for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
1431*5e7646d2SAndroid Build Coastguard Worker     {
1432*5e7646d2SAndroid Build Coastguard Worker       if (attr->values[i].range.lower < lowerpagerange ||
1433*5e7646d2SAndroid Build Coastguard Worker 	  attr->values[i].range.lower > attr->values[i].range.upper)
1434*5e7646d2SAndroid Build Coastguard Worker       {
1435*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_BAD_REQUEST,
1436*5e7646d2SAndroid Build Coastguard Worker 	                _("Bad page-ranges values %d-%d."),
1437*5e7646d2SAndroid Build Coastguard Worker 	                attr->values[i].range.lower,
1438*5e7646d2SAndroid Build Coastguard Worker 			attr->values[i].range.upper);
1439*5e7646d2SAndroid Build Coastguard Worker 	return (NULL);
1440*5e7646d2SAndroid Build Coastguard Worker       }
1441*5e7646d2SAndroid Build Coastguard Worker 
1442*5e7646d2SAndroid Build Coastguard Worker       lowerpagerange = attr->values[i].range.upper + 1;
1443*5e7646d2SAndroid Build Coastguard Worker     }
1444*5e7646d2SAndroid Build Coastguard Worker   }
1445*5e7646d2SAndroid Build Coastguard Worker 
1446*5e7646d2SAndroid Build Coastguard Worker  /*
1447*5e7646d2SAndroid Build Coastguard Worker   * Do media selection as needed...
1448*5e7646d2SAndroid Build Coastguard Worker   */
1449*5e7646d2SAndroid Build Coastguard Worker 
1450*5e7646d2SAndroid Build Coastguard Worker   if (!ippFindAttribute(con->request, "PageRegion", IPP_TAG_ZERO) &&
1451*5e7646d2SAndroid Build Coastguard Worker       !ippFindAttribute(con->request, "PageSize", IPP_TAG_ZERO) &&
1452*5e7646d2SAndroid Build Coastguard Worker       _ppdCacheGetPageSize(printer->pc, con->request, NULL, &exact))
1453*5e7646d2SAndroid Build Coastguard Worker   {
1454*5e7646d2SAndroid Build Coastguard Worker     if (!exact &&
1455*5e7646d2SAndroid Build Coastguard Worker         (media_col = ippFindAttribute(con->request, "media-col",
1456*5e7646d2SAndroid Build Coastguard Worker 	                              IPP_TAG_BEGIN_COLLECTION)) != NULL)
1457*5e7646d2SAndroid Build Coastguard Worker     {
1458*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_OK_SUBST, _("Unsupported margins."));
1459*5e7646d2SAndroid Build Coastguard Worker 
1460*5e7646d2SAndroid Build Coastguard Worker       unsup_col = ippNew();
1461*5e7646d2SAndroid Build Coastguard Worker       if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1462*5e7646d2SAndroid Build Coastguard Worker                                            "media-bottom-margin",
1463*5e7646d2SAndroid Build Coastguard Worker 					   IPP_TAG_INTEGER)) != NULL)
1464*5e7646d2SAndroid Build Coastguard Worker         ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1465*5e7646d2SAndroid Build Coastguard Worker 	              "media-bottom-margin", media_margin->values[0].integer);
1466*5e7646d2SAndroid Build Coastguard Worker 
1467*5e7646d2SAndroid Build Coastguard Worker       if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1468*5e7646d2SAndroid Build Coastguard Worker                                            "media-left-margin",
1469*5e7646d2SAndroid Build Coastguard Worker 					   IPP_TAG_INTEGER)) != NULL)
1470*5e7646d2SAndroid Build Coastguard Worker         ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1471*5e7646d2SAndroid Build Coastguard Worker 	              "media-left-margin", media_margin->values[0].integer);
1472*5e7646d2SAndroid Build Coastguard Worker 
1473*5e7646d2SAndroid Build Coastguard Worker       if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1474*5e7646d2SAndroid Build Coastguard Worker                                            "media-right-margin",
1475*5e7646d2SAndroid Build Coastguard Worker 					   IPP_TAG_INTEGER)) != NULL)
1476*5e7646d2SAndroid Build Coastguard Worker         ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1477*5e7646d2SAndroid Build Coastguard Worker 	              "media-right-margin", media_margin->values[0].integer);
1478*5e7646d2SAndroid Build Coastguard Worker 
1479*5e7646d2SAndroid Build Coastguard Worker       if ((media_margin = ippFindAttribute(media_col->values[0].collection,
1480*5e7646d2SAndroid Build Coastguard Worker                                            "media-top-margin",
1481*5e7646d2SAndroid Build Coastguard Worker 					   IPP_TAG_INTEGER)) != NULL)
1482*5e7646d2SAndroid Build Coastguard Worker         ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1483*5e7646d2SAndroid Build Coastguard Worker 	              "media-top-margin", media_margin->values[0].integer);
1484*5e7646d2SAndroid Build Coastguard Worker 
1485*5e7646d2SAndroid Build Coastguard Worker       ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col",
1486*5e7646d2SAndroid Build Coastguard Worker                        unsup_col);
1487*5e7646d2SAndroid Build Coastguard Worker       ippDelete(unsup_col);
1488*5e7646d2SAndroid Build Coastguard Worker     }
1489*5e7646d2SAndroid Build Coastguard Worker   }
1490*5e7646d2SAndroid Build Coastguard Worker 
1491*5e7646d2SAndroid Build Coastguard Worker  /*
1492*5e7646d2SAndroid Build Coastguard Worker   * Make sure we aren't over our limit...
1493*5e7646d2SAndroid Build Coastguard Worker   */
1494*5e7646d2SAndroid Build Coastguard Worker 
1495*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
1496*5e7646d2SAndroid Build Coastguard Worker     cupsdCleanJobs();
1497*5e7646d2SAndroid Build Coastguard Worker 
1498*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
1499*5e7646d2SAndroid Build Coastguard Worker   {
1500*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE, _("Too many active jobs."));
1501*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1502*5e7646d2SAndroid Build Coastguard Worker   }
1503*5e7646d2SAndroid Build Coastguard Worker 
1504*5e7646d2SAndroid Build Coastguard Worker   if ((i = check_quotas(con, printer)) < 0)
1505*5e7646d2SAndroid Build Coastguard Worker   {
1506*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
1507*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1508*5e7646d2SAndroid Build Coastguard Worker   }
1509*5e7646d2SAndroid Build Coastguard Worker   else if (i == 0)
1510*5e7646d2SAndroid Build Coastguard Worker   {
1511*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
1512*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1513*5e7646d2SAndroid Build Coastguard Worker   }
1514*5e7646d2SAndroid Build Coastguard Worker 
1515*5e7646d2SAndroid Build Coastguard Worker  /*
1516*5e7646d2SAndroid Build Coastguard Worker   * Create the job and set things up...
1517*5e7646d2SAndroid Build Coastguard Worker   */
1518*5e7646d2SAndroid Build Coastguard Worker 
1519*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-priority",
1520*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
1521*5e7646d2SAndroid Build Coastguard Worker     priority = attr->values[0].integer;
1522*5e7646d2SAndroid Build Coastguard Worker   else
1523*5e7646d2SAndroid Build Coastguard Worker   {
1524*5e7646d2SAndroid Build Coastguard Worker     if ((val = cupsGetOption("job-priority", printer->num_options,
1525*5e7646d2SAndroid Build Coastguard Worker                              printer->options)) != NULL)
1526*5e7646d2SAndroid Build Coastguard Worker       priority = atoi(val);
1527*5e7646d2SAndroid Build Coastguard Worker     else
1528*5e7646d2SAndroid Build Coastguard Worker       priority = 50;
1529*5e7646d2SAndroid Build Coastguard Worker 
1530*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
1531*5e7646d2SAndroid Build Coastguard Worker                   priority);
1532*5e7646d2SAndroid Build Coastguard Worker   }
1533*5e7646d2SAndroid Build Coastguard Worker 
1534*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL)
1535*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1536*5e7646d2SAndroid Build Coastguard Worker   else if ((attr->value_tag != IPP_TAG_NAME &&
1537*5e7646d2SAndroid Build Coastguard Worker             attr->value_tag != IPP_TAG_NAMELANG) ||
1538*5e7646d2SAndroid Build Coastguard Worker            attr->num_values != 1)
1539*5e7646d2SAndroid Build Coastguard Worker   {
1540*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_ATTRIBUTES,
1541*5e7646d2SAndroid Build Coastguard Worker                     _("Bad job-name value: Wrong type or count."));
1542*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
1543*5e7646d2SAndroid Build Coastguard Worker       attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
1544*5e7646d2SAndroid Build Coastguard Worker 
1545*5e7646d2SAndroid Build Coastguard Worker     if (StrictConformance)
1546*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1547*5e7646d2SAndroid Build Coastguard Worker 
1548*5e7646d2SAndroid Build Coastguard Worker     /* Don't use invalid attribute */
1549*5e7646d2SAndroid Build Coastguard Worker     ippDeleteAttribute(con->request, attr);
1550*5e7646d2SAndroid Build Coastguard Worker 
1551*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1552*5e7646d2SAndroid Build Coastguard Worker   }
1553*5e7646d2SAndroid Build Coastguard Worker   else if (!ippValidateAttribute(attr))
1554*5e7646d2SAndroid Build Coastguard Worker   {
1555*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"),
1556*5e7646d2SAndroid Build Coastguard Worker                     cupsLastErrorString());
1557*5e7646d2SAndroid Build Coastguard Worker 
1558*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
1559*5e7646d2SAndroid Build Coastguard Worker       attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
1560*5e7646d2SAndroid Build Coastguard Worker 
1561*5e7646d2SAndroid Build Coastguard Worker     if (StrictConformance)
1562*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
1563*5e7646d2SAndroid Build Coastguard Worker 
1564*5e7646d2SAndroid Build Coastguard Worker     /* Don't use invalid attribute */
1565*5e7646d2SAndroid Build Coastguard Worker     ippDeleteAttribute(con->request, attr);
1566*5e7646d2SAndroid Build Coastguard Worker 
1567*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
1568*5e7646d2SAndroid Build Coastguard Worker   }
1569*5e7646d2SAndroid Build Coastguard Worker 
1570*5e7646d2SAndroid Build Coastguard Worker   attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
1571*5e7646d2SAndroid Build Coastguard Worker 
1572*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdAddJob(priority, printer->name)) == NULL)
1573*5e7646d2SAndroid Build Coastguard Worker   {
1574*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_INTERNAL_ERROR,
1575*5e7646d2SAndroid Build Coastguard Worker                     _("Unable to add job for destination \"%s\"."),
1576*5e7646d2SAndroid Build Coastguard Worker 		    printer->name);
1577*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
1578*5e7646d2SAndroid Build Coastguard Worker   }
1579*5e7646d2SAndroid Build Coastguard Worker 
1580*5e7646d2SAndroid Build Coastguard Worker   job->dtype   = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
1581*5e7646d2SAndroid Build Coastguard Worker   job->attrs   = con->request;
1582*5e7646d2SAndroid Build Coastguard Worker   job->dirty   = 1;
1583*5e7646d2SAndroid Build Coastguard Worker   con->request = ippNewRequest(job->attrs->request.op.operation_id);
1584*5e7646d2SAndroid Build Coastguard Worker 
1585*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
1586*5e7646d2SAndroid Build Coastguard Worker 
1587*5e7646d2SAndroid Build Coastguard Worker   add_job_uuid(job);
1588*5e7646d2SAndroid Build Coastguard Worker   apply_printer_defaults(printer, job);
1589*5e7646d2SAndroid Build Coastguard Worker 
1590*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0])
1591*5e7646d2SAndroid Build Coastguard Worker   {
1592*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&job->username, con->username);
1593*5e7646d2SAndroid Build Coastguard Worker 
1594*5e7646d2SAndroid Build Coastguard Worker     if (attr)
1595*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &attr, 0, con->username);
1596*5e7646d2SAndroid Build Coastguard Worker   }
1597*5e7646d2SAndroid Build Coastguard Worker   else if (attr)
1598*5e7646d2SAndroid Build Coastguard Worker   {
1599*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG,
1600*5e7646d2SAndroid Build Coastguard Worker                     "add_job: requesting-user-name=\"%s\"",
1601*5e7646d2SAndroid Build Coastguard Worker                     attr->values[0].string.text);
1602*5e7646d2SAndroid Build Coastguard Worker 
1603*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&job->username, attr->values[0].string.text);
1604*5e7646d2SAndroid Build Coastguard Worker   }
1605*5e7646d2SAndroid Build Coastguard Worker   else
1606*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&job->username, "anonymous");
1607*5e7646d2SAndroid Build Coastguard Worker 
1608*5e7646d2SAndroid Build Coastguard Worker   if (!attr)
1609*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
1610*5e7646d2SAndroid Build Coastguard Worker                  "job-originating-user-name", NULL, job->username);
1611*5e7646d2SAndroid Build Coastguard Worker   else
1612*5e7646d2SAndroid Build Coastguard Worker   {
1613*5e7646d2SAndroid Build Coastguard Worker     ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
1614*5e7646d2SAndroid Build Coastguard Worker     ippSetName(job->attrs, &attr, "job-originating-user-name");
1615*5e7646d2SAndroid Build Coastguard Worker   }
1616*5e7646d2SAndroid Build Coastguard Worker 
1617*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0] || auth_info)
1618*5e7646d2SAndroid Build Coastguard Worker   {
1619*5e7646d2SAndroid Build Coastguard Worker     save_auth_info(con, job, auth_info);
1620*5e7646d2SAndroid Build Coastguard Worker 
1621*5e7646d2SAndroid Build Coastguard Worker    /*
1622*5e7646d2SAndroid Build Coastguard Worker     * Remove the auth-info attribute from the attribute data...
1623*5e7646d2SAndroid Build Coastguard Worker     */
1624*5e7646d2SAndroid Build Coastguard Worker 
1625*5e7646d2SAndroid Build Coastguard Worker     if (auth_info)
1626*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(job->attrs, auth_info);
1627*5e7646d2SAndroid Build Coastguard Worker   }
1628*5e7646d2SAndroid Build Coastguard Worker 
1629*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL)
1630*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&(job->name), attr->values[0].string.text);
1631*5e7646d2SAndroid Build Coastguard Worker 
1632*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
1633*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ZERO)) != NULL)
1634*5e7646d2SAndroid Build Coastguard Worker   {
1635*5e7646d2SAndroid Build Coastguard Worker    /*
1636*5e7646d2SAndroid Build Coastguard Worker     * Request contains a job-originating-host-name attribute; validate it...
1637*5e7646d2SAndroid Build Coastguard Worker     */
1638*5e7646d2SAndroid Build Coastguard Worker 
1639*5e7646d2SAndroid Build Coastguard Worker     if (attr->value_tag != IPP_TAG_NAME ||
1640*5e7646d2SAndroid Build Coastguard Worker         attr->num_values != 1 ||
1641*5e7646d2SAndroid Build Coastguard Worker         strcmp(con->http->hostname, "localhost"))
1642*5e7646d2SAndroid Build Coastguard Worker     {
1643*5e7646d2SAndroid Build Coastguard Worker      /*
1644*5e7646d2SAndroid Build Coastguard Worker       * Can't override the value if we aren't connected via localhost.
1645*5e7646d2SAndroid Build Coastguard Worker       * Also, we can only have 1 value and it must be a name value.
1646*5e7646d2SAndroid Build Coastguard Worker       */
1647*5e7646d2SAndroid Build Coastguard Worker 
1648*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(job->attrs, attr);
1649*5e7646d2SAndroid Build Coastguard Worker       ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http->hostname);
1650*5e7646d2SAndroid Build Coastguard Worker     }
1651*5e7646d2SAndroid Build Coastguard Worker     else
1652*5e7646d2SAndroid Build Coastguard Worker       ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
1653*5e7646d2SAndroid Build Coastguard Worker   }
1654*5e7646d2SAndroid Build Coastguard Worker   else
1655*5e7646d2SAndroid Build Coastguard Worker   {
1656*5e7646d2SAndroid Build Coastguard Worker    /*
1657*5e7646d2SAndroid Build Coastguard Worker     * No job-originating-host-name attribute, so use the hostname from
1658*5e7646d2SAndroid Build Coastguard Worker     * the connection...
1659*5e7646d2SAndroid Build Coastguard Worker     */
1660*5e7646d2SAndroid Build Coastguard Worker 
1661*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
1662*5e7646d2SAndroid Build Coastguard Worker         	 "job-originating-host-name", NULL, con->http->hostname);
1663*5e7646d2SAndroid Build Coastguard Worker   }
1664*5e7646d2SAndroid Build Coastguard Worker 
1665*5e7646d2SAndroid Build Coastguard Worker   ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed");
1666*5e7646d2SAndroid Build Coastguard Worker   ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(NULL)));
1667*5e7646d2SAndroid Build Coastguard Worker   ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing");
1668*5e7646d2SAndroid Build Coastguard Worker   ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-completed");
1669*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", time(NULL));
1670*5e7646d2SAndroid Build Coastguard Worker   ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-processing");
1671*5e7646d2SAndroid Build Coastguard Worker 
1672*5e7646d2SAndroid Build Coastguard Worker  /*
1673*5e7646d2SAndroid Build Coastguard Worker   * Add remaining job attributes...
1674*5e7646d2SAndroid Build Coastguard Worker   */
1675*5e7646d2SAndroid Build Coastguard Worker 
1676*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
1677*5e7646d2SAndroid Build Coastguard Worker   job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
1678*5e7646d2SAndroid Build Coastguard Worker                              "job-state", IPP_JOB_STOPPED);
1679*5e7646d2SAndroid Build Coastguard Worker   job->state_value = (ipp_jstate_t)job->state->values[0].integer;
1680*5e7646d2SAndroid Build Coastguard Worker   job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
1681*5e7646d2SAndroid Build Coastguard Worker                               "job-state-reasons", NULL, "job-incoming");
1682*5e7646d2SAndroid Build Coastguard Worker   job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0);
1683*5e7646d2SAndroid Build Coastguard Worker   job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
1684*5e7646d2SAndroid Build Coastguard Worker                               "job-media-sheets-completed", 0);
1685*5e7646d2SAndroid Build Coastguard Worker   ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
1686*5e7646d2SAndroid Build Coastguard Worker                printer->uri);
1687*5e7646d2SAndroid Build Coastguard Worker 
1688*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
1689*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer = 0;
1690*5e7646d2SAndroid Build Coastguard Worker   else
1691*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0);
1692*5e7646d2SAndroid Build Coastguard Worker 
1693*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
1694*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) == NULL)
1695*5e7646d2SAndroid Build Coastguard Worker     attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
1696*5e7646d2SAndroid Build Coastguard Worker   if (!attr)
1697*5e7646d2SAndroid Build Coastguard Worker   {
1698*5e7646d2SAndroid Build Coastguard Worker     if ((val = cupsGetOption("job-hold-until", printer->num_options,
1699*5e7646d2SAndroid Build Coastguard Worker                              printer->options)) == NULL)
1700*5e7646d2SAndroid Build Coastguard Worker       val = "no-hold";
1701*5e7646d2SAndroid Build Coastguard Worker 
1702*5e7646d2SAndroid Build Coastguard Worker     attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
1703*5e7646d2SAndroid Build Coastguard Worker                         "job-hold-until", NULL, val);
1704*5e7646d2SAndroid Build Coastguard Worker   }
1705*5e7646d2SAndroid Build Coastguard Worker 
1706*5e7646d2SAndroid Build Coastguard Worker   if (printer->holding_new_jobs)
1707*5e7646d2SAndroid Build Coastguard Worker   {
1708*5e7646d2SAndroid Build Coastguard Worker    /*
1709*5e7646d2SAndroid Build Coastguard Worker     * Hold all new jobs on this printer...
1710*5e7646d2SAndroid Build Coastguard Worker     */
1711*5e7646d2SAndroid Build Coastguard Worker 
1712*5e7646d2SAndroid Build Coastguard Worker     if (attr && strcmp(attr->values[0].string.text, "no-hold"))
1713*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobHoldUntil(job, ippGetString(attr, 0, NULL), 0);
1714*5e7646d2SAndroid Build Coastguard Worker     else
1715*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobHoldUntil(job, "indefinite", 0);
1716*5e7646d2SAndroid Build Coastguard Worker 
1717*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_HELD;
1718*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_HELD;
1719*5e7646d2SAndroid Build Coastguard Worker 
1720*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "job-held-on-create");
1721*5e7646d2SAndroid Build Coastguard Worker   }
1722*5e7646d2SAndroid Build Coastguard Worker   else if (attr && strcmp(attr->values[0].string.text, "no-hold"))
1723*5e7646d2SAndroid Build Coastguard Worker   {
1724*5e7646d2SAndroid Build Coastguard Worker    /*
1725*5e7646d2SAndroid Build Coastguard Worker     * Hold job until specified time...
1726*5e7646d2SAndroid Build Coastguard Worker     */
1727*5e7646d2SAndroid Build Coastguard Worker 
1728*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0);
1729*5e7646d2SAndroid Build Coastguard Worker 
1730*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_HELD;
1731*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_HELD;
1732*5e7646d2SAndroid Build Coastguard Worker 
1733*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified");
1734*5e7646d2SAndroid Build Coastguard Worker   }
1735*5e7646d2SAndroid Build Coastguard Worker   else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB)
1736*5e7646d2SAndroid Build Coastguard Worker   {
1737*5e7646d2SAndroid Build Coastguard Worker     job->hold_until               = time(NULL) + MultipleOperationTimeout;
1738*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_HELD;
1739*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_HELD;
1740*5e7646d2SAndroid Build Coastguard Worker   }
1741*5e7646d2SAndroid Build Coastguard Worker   else
1742*5e7646d2SAndroid Build Coastguard Worker   {
1743*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_PENDING;
1744*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_PENDING;
1745*5e7646d2SAndroid Build Coastguard Worker 
1746*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "none");
1747*5e7646d2SAndroid Build Coastguard Worker   }
1748*5e7646d2SAndroid Build Coastguard Worker 
1749*5e7646d2SAndroid Build Coastguard Worker   if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification)
1750*5e7646d2SAndroid Build Coastguard Worker   {
1751*5e7646d2SAndroid Build Coastguard Worker    /*
1752*5e7646d2SAndroid Build Coastguard Worker     * Add job sheets options...
1753*5e7646d2SAndroid Build Coastguard Worker     */
1754*5e7646d2SAndroid Build Coastguard Worker 
1755*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1756*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_ZERO)) == NULL)
1757*5e7646d2SAndroid Build Coastguard Worker     {
1758*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
1759*5e7646d2SAndroid Build Coastguard Worker                       "Adding default job-sheets values \"%s,%s\"...",
1760*5e7646d2SAndroid Build Coastguard Worker                       printer->job_sheets[0], printer->job_sheets[1]);
1761*5e7646d2SAndroid Build Coastguard Worker 
1762*5e7646d2SAndroid Build Coastguard Worker       attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
1763*5e7646d2SAndroid Build Coastguard Worker                            2, NULL, NULL);
1764*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
1765*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
1766*5e7646d2SAndroid Build Coastguard Worker     }
1767*5e7646d2SAndroid Build Coastguard Worker 
1768*5e7646d2SAndroid Build Coastguard Worker     job->job_sheets = attr;
1769*5e7646d2SAndroid Build Coastguard Worker 
1770*5e7646d2SAndroid Build Coastguard Worker    /*
1771*5e7646d2SAndroid Build Coastguard Worker     * Enforce classification level if set...
1772*5e7646d2SAndroid Build Coastguard Worker     */
1773*5e7646d2SAndroid Build Coastguard Worker 
1774*5e7646d2SAndroid Build Coastguard Worker     if (Classification)
1775*5e7646d2SAndroid Build Coastguard Worker     {
1776*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO,
1777*5e7646d2SAndroid Build Coastguard Worker                       "Classification=\"%s\", ClassifyOverride=%d",
1778*5e7646d2SAndroid Build Coastguard Worker                       Classification ? Classification : "(null)",
1779*5e7646d2SAndroid Build Coastguard Worker 		      ClassifyOverride);
1780*5e7646d2SAndroid Build Coastguard Worker 
1781*5e7646d2SAndroid Build Coastguard Worker       if (ClassifyOverride)
1782*5e7646d2SAndroid Build Coastguard Worker       {
1783*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(attr->values[0].string.text, "none") &&
1784*5e7646d2SAndroid Build Coastguard Worker 	    (attr->num_values == 1 ||
1785*5e7646d2SAndroid Build Coastguard Worker 	     !strcmp(attr->values[1].string.text, "none")))
1786*5e7646d2SAndroid Build Coastguard Worker         {
1787*5e7646d2SAndroid Build Coastguard Worker 	 /*
1788*5e7646d2SAndroid Build Coastguard Worker           * Force the leading banner to have the classification on it...
1789*5e7646d2SAndroid Build Coastguard Worker 	  */
1790*5e7646d2SAndroid Build Coastguard Worker 
1791*5e7646d2SAndroid Build Coastguard Worker           ippSetString(job->attrs, &attr, 0, Classification);
1792*5e7646d2SAndroid Build Coastguard Worker 
1793*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
1794*5e7646d2SAndroid Build Coastguard Worker 	                		     "job-sheets=\"%s,none\", "
1795*5e7646d2SAndroid Build Coastguard Worker 					     "job-originating-user-name=\"%s\"",
1796*5e7646d2SAndroid Build Coastguard Worker 	              Classification, job->username);
1797*5e7646d2SAndroid Build Coastguard Worker 	}
1798*5e7646d2SAndroid Build Coastguard Worker 	else if (attr->num_values == 2 &&
1799*5e7646d2SAndroid Build Coastguard Worker 	         strcmp(attr->values[0].string.text,
1800*5e7646d2SAndroid Build Coastguard Worker 		        attr->values[1].string.text) &&
1801*5e7646d2SAndroid Build Coastguard Worker 		 strcmp(attr->values[0].string.text, "none") &&
1802*5e7646d2SAndroid Build Coastguard Worker 		 strcmp(attr->values[1].string.text, "none"))
1803*5e7646d2SAndroid Build Coastguard Worker         {
1804*5e7646d2SAndroid Build Coastguard Worker 	 /*
1805*5e7646d2SAndroid Build Coastguard Worker 	  * Can't put two different security markings on the same document!
1806*5e7646d2SAndroid Build Coastguard Worker 	  */
1807*5e7646d2SAndroid Build Coastguard Worker 
1808*5e7646d2SAndroid Build Coastguard Worker           ippSetString(job->attrs, &attr, 1, attr->values[0].string.text);
1809*5e7646d2SAndroid Build Coastguard Worker 
1810*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
1811*5e7646d2SAndroid Build Coastguard Worker 	                		     "job-sheets=\"%s,%s\", "
1812*5e7646d2SAndroid Build Coastguard Worker 					     "job-originating-user-name=\"%s\"",
1813*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[0].string.text,
1814*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[1].string.text, job->username);
1815*5e7646d2SAndroid Build Coastguard Worker 	}
1816*5e7646d2SAndroid Build Coastguard Worker 	else if (strcmp(attr->values[0].string.text, Classification) &&
1817*5e7646d2SAndroid Build Coastguard Worker 	         strcmp(attr->values[0].string.text, "none") &&
1818*5e7646d2SAndroid Build Coastguard Worker 		 (attr->num_values == 1 ||
1819*5e7646d2SAndroid Build Coastguard Worker 	          (strcmp(attr->values[1].string.text, Classification) &&
1820*5e7646d2SAndroid Build Coastguard Worker 	           strcmp(attr->values[1].string.text, "none"))))
1821*5e7646d2SAndroid Build Coastguard Worker         {
1822*5e7646d2SAndroid Build Coastguard Worker 	  if (attr->num_values == 1)
1823*5e7646d2SAndroid Build Coastguard Worker             cupsdLogJob(job, CUPSD_LOG_NOTICE,
1824*5e7646d2SAndroid Build Coastguard Worker 			"CLASSIFICATION OVERRIDDEN "
1825*5e7646d2SAndroid Build Coastguard Worker 			"job-sheets=\"%s\", "
1826*5e7646d2SAndroid Build Coastguard Worker 			"job-originating-user-name=\"%s\"",
1827*5e7646d2SAndroid Build Coastguard Worker 	                attr->values[0].string.text, job->username);
1828*5e7646d2SAndroid Build Coastguard Worker           else
1829*5e7646d2SAndroid Build Coastguard Worker             cupsdLogJob(job, CUPSD_LOG_NOTICE,
1830*5e7646d2SAndroid Build Coastguard Worker 			"CLASSIFICATION OVERRIDDEN "
1831*5e7646d2SAndroid Build Coastguard Worker 			"job-sheets=\"%s,%s\",fffff "
1832*5e7646d2SAndroid Build Coastguard Worker 			"job-originating-user-name=\"%s\"",
1833*5e7646d2SAndroid Build Coastguard Worker 			attr->values[0].string.text,
1834*5e7646d2SAndroid Build Coastguard Worker 			attr->values[1].string.text, job->username);
1835*5e7646d2SAndroid Build Coastguard Worker         }
1836*5e7646d2SAndroid Build Coastguard Worker       }
1837*5e7646d2SAndroid Build Coastguard Worker       else if (strcmp(attr->values[0].string.text, Classification) &&
1838*5e7646d2SAndroid Build Coastguard Worker                (attr->num_values == 1 ||
1839*5e7646d2SAndroid Build Coastguard Worker 	       strcmp(attr->values[1].string.text, Classification)))
1840*5e7646d2SAndroid Build Coastguard Worker       {
1841*5e7646d2SAndroid Build Coastguard Worker        /*
1842*5e7646d2SAndroid Build Coastguard Worker         * Force the banner to have the classification on it...
1843*5e7646d2SAndroid Build Coastguard Worker 	*/
1844*5e7646d2SAndroid Build Coastguard Worker 
1845*5e7646d2SAndroid Build Coastguard Worker         if (attr->num_values > 1 &&
1846*5e7646d2SAndroid Build Coastguard Worker 	    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
1847*5e7646d2SAndroid Build Coastguard Worker 	{
1848*5e7646d2SAndroid Build Coastguard Worker           ippSetString(job->attrs, &attr, 0, Classification);
1849*5e7646d2SAndroid Build Coastguard Worker           ippSetString(job->attrs, &attr, 1, Classification);
1850*5e7646d2SAndroid Build Coastguard Worker 	}
1851*5e7646d2SAndroid Build Coastguard Worker         else
1852*5e7646d2SAndroid Build Coastguard Worker 	{
1853*5e7646d2SAndroid Build Coastguard Worker           if (attr->num_values == 1 ||
1854*5e7646d2SAndroid Build Coastguard Worker 	      strcmp(attr->values[0].string.text, "none"))
1855*5e7646d2SAndroid Build Coastguard Worker             ippSetString(job->attrs, &attr, 0, Classification);
1856*5e7646d2SAndroid Build Coastguard Worker 
1857*5e7646d2SAndroid Build Coastguard Worker           if (attr->num_values > 1 &&
1858*5e7646d2SAndroid Build Coastguard Worker 	      strcmp(attr->values[1].string.text, "none"))
1859*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &attr, 1, Classification);
1860*5e7646d2SAndroid Build Coastguard Worker         }
1861*5e7646d2SAndroid Build Coastguard Worker 
1862*5e7646d2SAndroid Build Coastguard Worker         if (attr->num_values > 1)
1863*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_NOTICE,
1864*5e7646d2SAndroid Build Coastguard Worker 		      "CLASSIFICATION FORCED "
1865*5e7646d2SAndroid Build Coastguard Worker 		      "job-sheets=\"%s,%s\", "
1866*5e7646d2SAndroid Build Coastguard Worker 		      "job-originating-user-name=\"%s\"",
1867*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[0].string.text,
1868*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[1].string.text, job->username);
1869*5e7646d2SAndroid Build Coastguard Worker         else
1870*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_NOTICE,
1871*5e7646d2SAndroid Build Coastguard Worker 		      "CLASSIFICATION FORCED "
1872*5e7646d2SAndroid Build Coastguard Worker 		      "job-sheets=\"%s\", "
1873*5e7646d2SAndroid Build Coastguard Worker 		      "job-originating-user-name=\"%s\"",
1874*5e7646d2SAndroid Build Coastguard Worker 		      Classification, job->username);
1875*5e7646d2SAndroid Build Coastguard Worker       }
1876*5e7646d2SAndroid Build Coastguard Worker     }
1877*5e7646d2SAndroid Build Coastguard Worker 
1878*5e7646d2SAndroid Build Coastguard Worker    /*
1879*5e7646d2SAndroid Build Coastguard Worker     * See if we need to add the starting sheet...
1880*5e7646d2SAndroid Build Coastguard Worker     */
1881*5e7646d2SAndroid Build Coastguard Worker 
1882*5e7646d2SAndroid Build Coastguard Worker     if (!(printer->type & CUPS_PRINTER_REMOTE))
1883*5e7646d2SAndroid Build Coastguard Worker     {
1884*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_INFO, "Adding start banner page \"%s\".",
1885*5e7646d2SAndroid Build Coastguard Worker 		  attr->values[0].string.text);
1886*5e7646d2SAndroid Build Coastguard Worker 
1887*5e7646d2SAndroid Build Coastguard Worker       if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0)
1888*5e7646d2SAndroid Build Coastguard Worker       {
1889*5e7646d2SAndroid Build Coastguard Worker         cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
1890*5e7646d2SAndroid Build Coastguard Worker 	                 "Aborting job because the start banner could not be "
1891*5e7646d2SAndroid Build Coastguard Worker 			 "copied.");
1892*5e7646d2SAndroid Build Coastguard Worker         return (NULL);
1893*5e7646d2SAndroid Build Coastguard Worker       }
1894*5e7646d2SAndroid Build Coastguard Worker 
1895*5e7646d2SAndroid Build Coastguard Worker       cupsdUpdateQuota(printer, job->username, 0, kbytes);
1896*5e7646d2SAndroid Build Coastguard Worker     }
1897*5e7646d2SAndroid Build Coastguard Worker   }
1898*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1899*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_ZERO)) != NULL)
1900*5e7646d2SAndroid Build Coastguard Worker     job->job_sheets = attr;
1901*5e7646d2SAndroid Build Coastguard Worker 
1902*5e7646d2SAndroid Build Coastguard Worker  /*
1903*5e7646d2SAndroid Build Coastguard Worker   * Fill in the response info...
1904*5e7646d2SAndroid Build Coastguard Worker   */
1905*5e7646d2SAndroid Build Coastguard Worker 
1906*5e7646d2SAndroid Build Coastguard Worker   httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, con->clientname, con->clientport, "/jobs/%d", job->id);
1907*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
1908*5e7646d2SAndroid Build Coastguard Worker 
1909*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
1910*5e7646d2SAndroid Build Coastguard Worker 
1911*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
1912*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_TEXT, "job-state-message", NULL, "");
1913*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, job->reasons->values[0].string.text);
1914*5e7646d2SAndroid Build Coastguard Worker 
1915*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
1916*5e7646d2SAndroid Build Coastguard Worker 
1917*5e7646d2SAndroid Build Coastguard Worker  /*
1918*5e7646d2SAndroid Build Coastguard Worker   * Add any job subscriptions...
1919*5e7646d2SAndroid Build Coastguard Worker   */
1920*5e7646d2SAndroid Build Coastguard Worker 
1921*5e7646d2SAndroid Build Coastguard Worker   add_job_subscriptions(con, job);
1922*5e7646d2SAndroid Build Coastguard Worker 
1923*5e7646d2SAndroid Build Coastguard Worker  /*
1924*5e7646d2SAndroid Build Coastguard Worker   * Set all but the first two attributes to the job attributes group...
1925*5e7646d2SAndroid Build Coastguard Worker   */
1926*5e7646d2SAndroid Build Coastguard Worker 
1927*5e7646d2SAndroid Build Coastguard Worker   for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
1928*5e7646d2SAndroid Build Coastguard Worker     attr->group_tag = IPP_TAG_JOB;
1929*5e7646d2SAndroid Build Coastguard Worker 
1930*5e7646d2SAndroid Build Coastguard Worker  /*
1931*5e7646d2SAndroid Build Coastguard Worker   * Fire the "job created" event...
1932*5e7646d2SAndroid Build Coastguard Worker   */
1933*5e7646d2SAndroid Build Coastguard Worker 
1934*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created.");
1935*5e7646d2SAndroid Build Coastguard Worker 
1936*5e7646d2SAndroid Build Coastguard Worker  /*
1937*5e7646d2SAndroid Build Coastguard Worker   * Return the new job...
1938*5e7646d2SAndroid Build Coastguard Worker   */
1939*5e7646d2SAndroid Build Coastguard Worker 
1940*5e7646d2SAndroid Build Coastguard Worker   return (job);
1941*5e7646d2SAndroid Build Coastguard Worker }
1942*5e7646d2SAndroid Build Coastguard Worker 
1943*5e7646d2SAndroid Build Coastguard Worker 
1944*5e7646d2SAndroid Build Coastguard Worker /*
1945*5e7646d2SAndroid Build Coastguard Worker  * 'add_job_subscriptions()' - Add any subscriptions for a job.
1946*5e7646d2SAndroid Build Coastguard Worker  */
1947*5e7646d2SAndroid Build Coastguard Worker 
1948*5e7646d2SAndroid Build Coastguard Worker static void
add_job_subscriptions(cupsd_client_t * con,cupsd_job_t * job)1949*5e7646d2SAndroid Build Coastguard Worker add_job_subscriptions(
1950*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
1951*5e7646d2SAndroid Build Coastguard Worker     cupsd_job_t    *job)		/* I - Newly created job */
1952*5e7646d2SAndroid Build Coastguard Worker {
1953*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
1954*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*prev,		/* Previous attribute */
1955*5e7646d2SAndroid Build Coastguard Worker 			*next,		/* Next attribute */
1956*5e7646d2SAndroid Build Coastguard Worker 			*attr;		/* Current attribute */
1957*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription object */
1958*5e7646d2SAndroid Build Coastguard Worker   const char		*recipient,	/* notify-recipient-uri */
1959*5e7646d2SAndroid Build Coastguard Worker 			*pullmethod;	/* notify-pull-method */
1960*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*user_data;	/* notify-user-data */
1961*5e7646d2SAndroid Build Coastguard Worker   int			interval;	/* notify-time-interval */
1962*5e7646d2SAndroid Build Coastguard Worker   unsigned		mask;		/* notify-events */
1963*5e7646d2SAndroid Build Coastguard Worker 
1964*5e7646d2SAndroid Build Coastguard Worker 
1965*5e7646d2SAndroid Build Coastguard Worker  /*
1966*5e7646d2SAndroid Build Coastguard Worker   * Find the first subscription group attribute; return if we have
1967*5e7646d2SAndroid Build Coastguard Worker   * none...
1968*5e7646d2SAndroid Build Coastguard Worker   */
1969*5e7646d2SAndroid Build Coastguard Worker 
1970*5e7646d2SAndroid Build Coastguard Worker   for (attr = job->attrs->attrs; attr; attr = attr->next)
1971*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
1972*5e7646d2SAndroid Build Coastguard Worker       break;
1973*5e7646d2SAndroid Build Coastguard Worker 
1974*5e7646d2SAndroid Build Coastguard Worker   if (!attr)
1975*5e7646d2SAndroid Build Coastguard Worker     return;
1976*5e7646d2SAndroid Build Coastguard Worker 
1977*5e7646d2SAndroid Build Coastguard Worker  /*
1978*5e7646d2SAndroid Build Coastguard Worker   * Process the subscription attributes in the request...
1979*5e7646d2SAndroid Build Coastguard Worker   */
1980*5e7646d2SAndroid Build Coastguard Worker 
1981*5e7646d2SAndroid Build Coastguard Worker   while (attr)
1982*5e7646d2SAndroid Build Coastguard Worker   {
1983*5e7646d2SAndroid Build Coastguard Worker     recipient = NULL;
1984*5e7646d2SAndroid Build Coastguard Worker     pullmethod = NULL;
1985*5e7646d2SAndroid Build Coastguard Worker     user_data  = NULL;
1986*5e7646d2SAndroid Build Coastguard Worker     interval   = 0;
1987*5e7646d2SAndroid Build Coastguard Worker     mask       = CUPSD_EVENT_NONE;
1988*5e7646d2SAndroid Build Coastguard Worker 
1989*5e7646d2SAndroid Build Coastguard Worker     while (attr && attr->group_tag != IPP_TAG_ZERO)
1990*5e7646d2SAndroid Build Coastguard Worker     {
1991*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->name, "notify-recipient-uri") &&
1992*5e7646d2SAndroid Build Coastguard Worker           attr->value_tag == IPP_TAG_URI)
1993*5e7646d2SAndroid Build Coastguard Worker       {
1994*5e7646d2SAndroid Build Coastguard Worker        /*
1995*5e7646d2SAndroid Build Coastguard Worker         * Validate the recipient scheme against the ServerBin/notifier
1996*5e7646d2SAndroid Build Coastguard Worker 	* directory...
1997*5e7646d2SAndroid Build Coastguard Worker 	*/
1998*5e7646d2SAndroid Build Coastguard Worker 
1999*5e7646d2SAndroid Build Coastguard Worker 	char	notifier[1024],		/* Notifier filename */
2000*5e7646d2SAndroid Build Coastguard Worker 		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
2001*5e7646d2SAndroid Build Coastguard Worker 		userpass[HTTP_MAX_URI],	/* Username portion of URI */
2002*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
2003*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
2004*5e7646d2SAndroid Build Coastguard Worker         int	port;			/* Port portion of URI */
2005*5e7646d2SAndroid Build Coastguard Worker         struct stat info;		/* File information */
2006*5e7646d2SAndroid Build Coastguard Worker 
2007*5e7646d2SAndroid Build Coastguard Worker         recipient = attr->values[0].string.text;
2008*5e7646d2SAndroid Build Coastguard Worker 
2009*5e7646d2SAndroid Build Coastguard Worker 	if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
2010*5e7646d2SAndroid Build Coastguard Worker 	                    scheme, sizeof(scheme), userpass, sizeof(userpass),
2011*5e7646d2SAndroid Build Coastguard Worker 			    host, sizeof(host), &port,
2012*5e7646d2SAndroid Build Coastguard Worker 			    resource, sizeof(resource)) < HTTP_URI_OK)
2013*5e7646d2SAndroid Build Coastguard Worker         {
2014*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
2015*5e7646d2SAndroid Build Coastguard Worker 	                  _("Bad notify-recipient-uri \"%s\"."), recipient);
2016*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2017*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_URI_SCHEME);
2018*5e7646d2SAndroid Build Coastguard Worker 	  return;
2019*5e7646d2SAndroid Build Coastguard Worker 	}
2020*5e7646d2SAndroid Build Coastguard Worker 
2021*5e7646d2SAndroid Build Coastguard Worker         snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme);
2022*5e7646d2SAndroid Build Coastguard Worker         if (access(notifier, X_OK) || stat(notifier, &info) || !S_ISREG(info.st_mode))
2023*5e7646d2SAndroid Build Coastguard Worker 	{
2024*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
2025*5e7646d2SAndroid Build Coastguard Worker 	                  _("notify-recipient-uri URI \"%s\" uses unknown "
2026*5e7646d2SAndroid Build Coastguard Worker 			    "scheme."), recipient);
2027*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2028*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_URI_SCHEME);
2029*5e7646d2SAndroid Build Coastguard Worker 	  return;
2030*5e7646d2SAndroid Build Coastguard Worker 	}
2031*5e7646d2SAndroid Build Coastguard Worker 
2032*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
2033*5e7646d2SAndroid Build Coastguard Worker 	{
2034*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
2035*5e7646d2SAndroid Build Coastguard Worker 	                  _("notify-recipient-uri URI \"%s\" is already used."),
2036*5e7646d2SAndroid Build Coastguard Worker 			  recipient);
2037*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2038*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_ATTRIBUTES);
2039*5e7646d2SAndroid Build Coastguard Worker 	  return;
2040*5e7646d2SAndroid Build Coastguard Worker 	}
2041*5e7646d2SAndroid Build Coastguard Worker       }
2042*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-pull-method") &&
2043*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_KEYWORD)
2044*5e7646d2SAndroid Build Coastguard Worker       {
2045*5e7646d2SAndroid Build Coastguard Worker         pullmethod = attr->values[0].string.text;
2046*5e7646d2SAndroid Build Coastguard Worker 
2047*5e7646d2SAndroid Build Coastguard Worker         if (strcmp(pullmethod, "ippget"))
2048*5e7646d2SAndroid Build Coastguard Worker 	{
2049*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
2050*5e7646d2SAndroid Build Coastguard Worker 	                  _("Bad notify-pull-method \"%s\"."), pullmethod);
2051*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
2052*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_ATTRIBUTES);
2053*5e7646d2SAndroid Build Coastguard Worker 	  return;
2054*5e7646d2SAndroid Build Coastguard Worker 	}
2055*5e7646d2SAndroid Build Coastguard Worker       }
2056*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-charset") &&
2057*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_CHARSET &&
2058*5e7646d2SAndroid Build Coastguard Worker 	       strcmp(attr->values[0].string.text, "us-ascii") &&
2059*5e7646d2SAndroid Build Coastguard Worker 	       strcmp(attr->values[0].string.text, "utf-8"))
2060*5e7646d2SAndroid Build Coastguard Worker       {
2061*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_CHARSET,
2062*5e7646d2SAndroid Build Coastguard Worker 	                _("Character set \"%s\" not supported."),
2063*5e7646d2SAndroid Build Coastguard Worker 			attr->values[0].string.text);
2064*5e7646d2SAndroid Build Coastguard Worker 	return;
2065*5e7646d2SAndroid Build Coastguard Worker       }
2066*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-natural-language") &&
2067*5e7646d2SAndroid Build Coastguard Worker                (attr->value_tag != IPP_TAG_LANGUAGE ||
2068*5e7646d2SAndroid Build Coastguard Worker 	        strcmp(attr->values[0].string.text, DefaultLanguage)))
2069*5e7646d2SAndroid Build Coastguard Worker       {
2070*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_CHARSET,
2071*5e7646d2SAndroid Build Coastguard Worker 	                _("Language \"%s\" not supported."),
2072*5e7646d2SAndroid Build Coastguard Worker 			attr->values[0].string.text);
2073*5e7646d2SAndroid Build Coastguard Worker 	return;
2074*5e7646d2SAndroid Build Coastguard Worker       }
2075*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-user-data") &&
2076*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_STRING)
2077*5e7646d2SAndroid Build Coastguard Worker       {
2078*5e7646d2SAndroid Build Coastguard Worker         if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
2079*5e7646d2SAndroid Build Coastguard Worker 	{
2080*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_REQUEST_VALUE,
2081*5e7646d2SAndroid Build Coastguard Worker 	                  _("The notify-user-data value is too large "
2082*5e7646d2SAndroid Build Coastguard Worker 			    "(%d > 63 octets)."),
2083*5e7646d2SAndroid Build Coastguard Worker 			  attr->values[0].unknown.length);
2084*5e7646d2SAndroid Build Coastguard Worker 	  return;
2085*5e7646d2SAndroid Build Coastguard Worker 	}
2086*5e7646d2SAndroid Build Coastguard Worker 
2087*5e7646d2SAndroid Build Coastguard Worker         user_data = attr;
2088*5e7646d2SAndroid Build Coastguard Worker       }
2089*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-events") &&
2090*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_KEYWORD)
2091*5e7646d2SAndroid Build Coastguard Worker       {
2092*5e7646d2SAndroid Build Coastguard Worker         for (i = 0; i < attr->num_values; i ++)
2093*5e7646d2SAndroid Build Coastguard Worker 	  mask |= cupsdEventValue(attr->values[i].string.text);
2094*5e7646d2SAndroid Build Coastguard Worker       }
2095*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-lease-duration"))
2096*5e7646d2SAndroid Build Coastguard Worker       {
2097*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_BAD_REQUEST,
2098*5e7646d2SAndroid Build Coastguard Worker 	                _("The notify-lease-duration attribute cannot be "
2099*5e7646d2SAndroid Build Coastguard Worker 			  "used with job subscriptions."));
2100*5e7646d2SAndroid Build Coastguard Worker 	return;
2101*5e7646d2SAndroid Build Coastguard Worker       }
2102*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-time-interval") &&
2103*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_INTEGER)
2104*5e7646d2SAndroid Build Coastguard Worker         interval = attr->values[0].integer;
2105*5e7646d2SAndroid Build Coastguard Worker 
2106*5e7646d2SAndroid Build Coastguard Worker       attr = attr->next;
2107*5e7646d2SAndroid Build Coastguard Worker     }
2108*5e7646d2SAndroid Build Coastguard Worker 
2109*5e7646d2SAndroid Build Coastguard Worker     if (!recipient && !pullmethod)
2110*5e7646d2SAndroid Build Coastguard Worker       break;
2111*5e7646d2SAndroid Build Coastguard Worker 
2112*5e7646d2SAndroid Build Coastguard Worker     if (mask == CUPSD_EVENT_NONE)
2113*5e7646d2SAndroid Build Coastguard Worker       mask = CUPSD_EVENT_JOB_COMPLETED;
2114*5e7646d2SAndroid Build Coastguard Worker 
2115*5e7646d2SAndroid Build Coastguard Worker     if ((sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job,
2116*5e7646d2SAndroid Build Coastguard Worker                                     recipient, 0)) != NULL)
2117*5e7646d2SAndroid Build Coastguard Worker     {
2118*5e7646d2SAndroid Build Coastguard Worker       sub->interval = interval;
2119*5e7646d2SAndroid Build Coastguard Worker 
2120*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&sub->owner, job->username);
2121*5e7646d2SAndroid Build Coastguard Worker 
2122*5e7646d2SAndroid Build Coastguard Worker       if (user_data)
2123*5e7646d2SAndroid Build Coastguard Worker       {
2124*5e7646d2SAndroid Build Coastguard Worker 	sub->user_data_len = user_data->values[0].unknown.length;
2125*5e7646d2SAndroid Build Coastguard Worker 	memcpy(sub->user_data, user_data->values[0].unknown.data,
2126*5e7646d2SAndroid Build Coastguard Worker 	       (size_t)sub->user_data_len);
2127*5e7646d2SAndroid Build Coastguard Worker       }
2128*5e7646d2SAndroid Build Coastguard Worker 
2129*5e7646d2SAndroid Build Coastguard Worker       ippAddSeparator(con->response);
2130*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
2131*5e7646d2SAndroid Build Coastguard Worker 		    "notify-subscription-id", sub->id);
2132*5e7646d2SAndroid Build Coastguard Worker 
2133*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d",
2134*5e7646d2SAndroid Build Coastguard Worker                       sub->id, job->id);
2135*5e7646d2SAndroid Build Coastguard Worker     }
2136*5e7646d2SAndroid Build Coastguard Worker 
2137*5e7646d2SAndroid Build Coastguard Worker     if (attr)
2138*5e7646d2SAndroid Build Coastguard Worker       attr = attr->next;
2139*5e7646d2SAndroid Build Coastguard Worker   }
2140*5e7646d2SAndroid Build Coastguard Worker 
2141*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
2142*5e7646d2SAndroid Build Coastguard Worker 
2143*5e7646d2SAndroid Build Coastguard Worker  /*
2144*5e7646d2SAndroid Build Coastguard Worker   * Remove all of the subscription attributes from the job request...
2145*5e7646d2SAndroid Build Coastguard Worker   *
2146*5e7646d2SAndroid Build Coastguard Worker   * TODO: Optimize this since subscription groups have to come at the
2147*5e7646d2SAndroid Build Coastguard Worker   * end of the request...
2148*5e7646d2SAndroid Build Coastguard Worker   */
2149*5e7646d2SAndroid Build Coastguard Worker 
2150*5e7646d2SAndroid Build Coastguard Worker   for (attr = job->attrs->attrs, prev = NULL; attr; attr = next)
2151*5e7646d2SAndroid Build Coastguard Worker   {
2152*5e7646d2SAndroid Build Coastguard Worker     next = attr->next;
2153*5e7646d2SAndroid Build Coastguard Worker 
2154*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag == IPP_TAG_SUBSCRIPTION ||
2155*5e7646d2SAndroid Build Coastguard Worker         attr->group_tag == IPP_TAG_ZERO)
2156*5e7646d2SAndroid Build Coastguard Worker     {
2157*5e7646d2SAndroid Build Coastguard Worker      /*
2158*5e7646d2SAndroid Build Coastguard Worker       * Free and remove this attribute...
2159*5e7646d2SAndroid Build Coastguard Worker       */
2160*5e7646d2SAndroid Build Coastguard Worker 
2161*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(NULL, attr);
2162*5e7646d2SAndroid Build Coastguard Worker 
2163*5e7646d2SAndroid Build Coastguard Worker       if (prev)
2164*5e7646d2SAndroid Build Coastguard Worker         prev->next = next;
2165*5e7646d2SAndroid Build Coastguard Worker       else
2166*5e7646d2SAndroid Build Coastguard Worker         job->attrs->attrs = next;
2167*5e7646d2SAndroid Build Coastguard Worker     }
2168*5e7646d2SAndroid Build Coastguard Worker     else
2169*5e7646d2SAndroid Build Coastguard Worker       prev = attr;
2170*5e7646d2SAndroid Build Coastguard Worker   }
2171*5e7646d2SAndroid Build Coastguard Worker 
2172*5e7646d2SAndroid Build Coastguard Worker   job->attrs->last    = prev;
2173*5e7646d2SAndroid Build Coastguard Worker   job->attrs->current = prev;
2174*5e7646d2SAndroid Build Coastguard Worker }
2175*5e7646d2SAndroid Build Coastguard Worker 
2176*5e7646d2SAndroid Build Coastguard Worker 
2177*5e7646d2SAndroid Build Coastguard Worker /*
2178*5e7646d2SAndroid Build Coastguard Worker  * 'add_job_uuid()' - Add job-uuid attribute to a job.
2179*5e7646d2SAndroid Build Coastguard Worker  *
2180*5e7646d2SAndroid Build Coastguard Worker  * See RFC 4122 for the definition of UUIDs and the format.
2181*5e7646d2SAndroid Build Coastguard Worker  */
2182*5e7646d2SAndroid Build Coastguard Worker 
2183*5e7646d2SAndroid Build Coastguard Worker static void
add_job_uuid(cupsd_job_t * job)2184*5e7646d2SAndroid Build Coastguard Worker add_job_uuid(cupsd_job_t *job)		/* I - Job */
2185*5e7646d2SAndroid Build Coastguard Worker {
2186*5e7646d2SAndroid Build Coastguard Worker   char			uuid[64];	/* job-uuid string */
2187*5e7646d2SAndroid Build Coastguard Worker 
2188*5e7646d2SAndroid Build Coastguard Worker 
2189*5e7646d2SAndroid Build Coastguard Worker  /*
2190*5e7646d2SAndroid Build Coastguard Worker   * Add a job-uuid attribute if none exists...
2191*5e7646d2SAndroid Build Coastguard Worker   */
2192*5e7646d2SAndroid Build Coastguard Worker 
2193*5e7646d2SAndroid Build Coastguard Worker   if (!ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI))
2194*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL,
2195*5e7646d2SAndroid Build Coastguard Worker 		 httpAssembleUUID(ServerName, RemotePort, job->dest, job->id,
2196*5e7646d2SAndroid Build Coastguard Worker 		                  uuid, sizeof(uuid)));
2197*5e7646d2SAndroid Build Coastguard Worker }
2198*5e7646d2SAndroid Build Coastguard Worker 
2199*5e7646d2SAndroid Build Coastguard Worker 
2200*5e7646d2SAndroid Build Coastguard Worker /*
2201*5e7646d2SAndroid Build Coastguard Worker  * 'add_printer()' - Add a printer to the system.
2202*5e7646d2SAndroid Build Coastguard Worker  */
2203*5e7646d2SAndroid Build Coastguard Worker 
2204*5e7646d2SAndroid Build Coastguard Worker static void
add_printer(cupsd_client_t * con,ipp_attribute_t * uri)2205*5e7646d2SAndroid Build Coastguard Worker add_printer(cupsd_client_t  *con,	/* I - Client connection */
2206*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - URI of printer */
2207*5e7646d2SAndroid Build Coastguard Worker {
2208*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
2209*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
2210*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
2211*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
2212*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
2213*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
2214*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
2215*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer/class */
2216*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Printer attribute */
2217*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			/* Script/PPD file */
2218*5e7646d2SAndroid Build Coastguard Worker   char		line[1024];		/* Line from file... */
2219*5e7646d2SAndroid Build Coastguard Worker   char		srcfile[1024],		/* Source Script/PPD file */
2220*5e7646d2SAndroid Build Coastguard Worker 		dstfile[1024];		/* Destination Script/PPD file */
2221*5e7646d2SAndroid Build Coastguard Worker   int		modify;			/* Non-zero if we are modifying */
2222*5e7646d2SAndroid Build Coastguard Worker   int		changed_driver,		/* Changed the PPD? */
2223*5e7646d2SAndroid Build Coastguard Worker 		need_restart_job,	/* Need to restart job? */
2224*5e7646d2SAndroid Build Coastguard Worker 		set_device_uri,		/* Did we set the device URI? */
2225*5e7646d2SAndroid Build Coastguard Worker 		set_port_monitor;	/* Did we set the port monitor? */
2226*5e7646d2SAndroid Build Coastguard Worker 
2227*5e7646d2SAndroid Build Coastguard Worker 
2228*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con,
2229*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
2230*5e7646d2SAndroid Build Coastguard Worker 
2231*5e7646d2SAndroid Build Coastguard Worker  /*
2232*5e7646d2SAndroid Build Coastguard Worker   * Do we have a valid URI?
2233*5e7646d2SAndroid Build Coastguard Worker   */
2234*5e7646d2SAndroid Build Coastguard Worker 
2235*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
2236*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), username, sizeof(username), host,
2237*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
2238*5e7646d2SAndroid Build Coastguard Worker 
2239*5e7646d2SAndroid Build Coastguard Worker   if (strncmp(resource, "/printers/", 10) || strlen(resource) == 10)
2240*5e7646d2SAndroid Build Coastguard Worker   {
2241*5e7646d2SAndroid Build Coastguard Worker    /*
2242*5e7646d2SAndroid Build Coastguard Worker     * No, return an error...
2243*5e7646d2SAndroid Build Coastguard Worker     */
2244*5e7646d2SAndroid Build Coastguard Worker 
2245*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
2246*5e7646d2SAndroid Build Coastguard Worker                     _("The printer-uri must be of the form "
2247*5e7646d2SAndroid Build Coastguard Worker 		      "\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
2248*5e7646d2SAndroid Build Coastguard Worker     return;
2249*5e7646d2SAndroid Build Coastguard Worker   }
2250*5e7646d2SAndroid Build Coastguard Worker 
2251*5e7646d2SAndroid Build Coastguard Worker  /*
2252*5e7646d2SAndroid Build Coastguard Worker   * Do we have a valid printer name?
2253*5e7646d2SAndroid Build Coastguard Worker   */
2254*5e7646d2SAndroid Build Coastguard Worker 
2255*5e7646d2SAndroid Build Coastguard Worker   if (!validate_name(resource + 10))
2256*5e7646d2SAndroid Build Coastguard Worker   {
2257*5e7646d2SAndroid Build Coastguard Worker    /*
2258*5e7646d2SAndroid Build Coastguard Worker     * No, return an error...
2259*5e7646d2SAndroid Build Coastguard Worker     */
2260*5e7646d2SAndroid Build Coastguard Worker 
2261*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
2262*5e7646d2SAndroid Build Coastguard Worker                     _("The printer-uri \"%s\" contains invalid characters."),
2263*5e7646d2SAndroid Build Coastguard Worker 		    uri->values[0].string.text);
2264*5e7646d2SAndroid Build Coastguard Worker     return;
2265*5e7646d2SAndroid Build Coastguard Worker   }
2266*5e7646d2SAndroid Build Coastguard Worker 
2267*5e7646d2SAndroid Build Coastguard Worker  /*
2268*5e7646d2SAndroid Build Coastguard Worker   * See if the printer already exists; if not, create a new printer...
2269*5e7646d2SAndroid Build Coastguard Worker   */
2270*5e7646d2SAndroid Build Coastguard Worker 
2271*5e7646d2SAndroid Build Coastguard Worker   if ((printer = cupsdFindPrinter(resource + 10)) == NULL)
2272*5e7646d2SAndroid Build Coastguard Worker   {
2273*5e7646d2SAndroid Build Coastguard Worker    /*
2274*5e7646d2SAndroid Build Coastguard Worker     * Printer doesn't exist; see if we have a class of the same name...
2275*5e7646d2SAndroid Build Coastguard Worker     */
2276*5e7646d2SAndroid Build Coastguard Worker 
2277*5e7646d2SAndroid Build Coastguard Worker     if (cupsdFindClass(resource + 10))
2278*5e7646d2SAndroid Build Coastguard Worker     {
2279*5e7646d2SAndroid Build Coastguard Worker      /*
2280*5e7646d2SAndroid Build Coastguard Worker       * Yes, return an error...
2281*5e7646d2SAndroid Build Coastguard Worker       */
2282*5e7646d2SAndroid Build Coastguard Worker 
2283*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE,
2284*5e7646d2SAndroid Build Coastguard Worker                       _("A class named \"%s\" already exists."),
2285*5e7646d2SAndroid Build Coastguard Worker         	      resource + 10);
2286*5e7646d2SAndroid Build Coastguard Worker       return;
2287*5e7646d2SAndroid Build Coastguard Worker     }
2288*5e7646d2SAndroid Build Coastguard Worker 
2289*5e7646d2SAndroid Build Coastguard Worker    /*
2290*5e7646d2SAndroid Build Coastguard Worker     * No, check the default policy then add the printer...
2291*5e7646d2SAndroid Build Coastguard Worker     */
2292*5e7646d2SAndroid Build Coastguard Worker 
2293*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
2294*5e7646d2SAndroid Build Coastguard Worker     {
2295*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, NULL);
2296*5e7646d2SAndroid Build Coastguard Worker       return;
2297*5e7646d2SAndroid Build Coastguard Worker     }
2298*5e7646d2SAndroid Build Coastguard Worker 
2299*5e7646d2SAndroid Build Coastguard Worker     printer = cupsdAddPrinter(resource + 10);
2300*5e7646d2SAndroid Build Coastguard Worker     modify  = 0;
2301*5e7646d2SAndroid Build Coastguard Worker 
2302*5e7646d2SAndroid Build Coastguard Worker     printer->printer_id = NextPrinterId ++;
2303*5e7646d2SAndroid Build Coastguard Worker   }
2304*5e7646d2SAndroid Build Coastguard Worker   else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
2305*5e7646d2SAndroid Build Coastguard Worker                                       NULL)) != HTTP_OK)
2306*5e7646d2SAndroid Build Coastguard Worker   {
2307*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
2308*5e7646d2SAndroid Build Coastguard Worker     return;
2309*5e7646d2SAndroid Build Coastguard Worker   }
2310*5e7646d2SAndroid Build Coastguard Worker   else
2311*5e7646d2SAndroid Build Coastguard Worker     modify = 1;
2312*5e7646d2SAndroid Build Coastguard Worker 
2313*5e7646d2SAndroid Build Coastguard Worker  /*
2314*5e7646d2SAndroid Build Coastguard Worker   * Look for attributes and copy them over as needed...
2315*5e7646d2SAndroid Build Coastguard Worker   */
2316*5e7646d2SAndroid Build Coastguard Worker 
2317*5e7646d2SAndroid Build Coastguard Worker   changed_driver   = 0;
2318*5e7646d2SAndroid Build Coastguard Worker   need_restart_job = 0;
2319*5e7646d2SAndroid Build Coastguard Worker 
2320*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-is-temporary", IPP_TAG_BOOLEAN)) != NULL)
2321*5e7646d2SAndroid Build Coastguard Worker     printer->temporary = ippGetBoolean(attr, 0);
2322*5e7646d2SAndroid Build Coastguard Worker 
2323*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-location",
2324*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
2325*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->location, attr->values[0].string.text);
2326*5e7646d2SAndroid Build Coastguard Worker 
2327*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
2328*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->geo_location, attr->values[0].string.text);
2329*5e7646d2SAndroid Build Coastguard Worker 
2330*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
2331*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->organization, attr->values[0].string.text);
2332*5e7646d2SAndroid Build Coastguard Worker 
2333*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
2334*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->organizational_unit, attr->values[0].string.text);
2335*5e7646d2SAndroid Build Coastguard Worker 
2336*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-info",
2337*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
2338*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->info, attr->values[0].string.text);
2339*5e7646d2SAndroid Build Coastguard Worker 
2340*5e7646d2SAndroid Build Coastguard Worker   set_device_uri = 0;
2341*5e7646d2SAndroid Build Coastguard Worker 
2342*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "device-uri",
2343*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_URI)) != NULL)
2344*5e7646d2SAndroid Build Coastguard Worker   {
2345*5e7646d2SAndroid Build Coastguard Worker    /*
2346*5e7646d2SAndroid Build Coastguard Worker     * Do we have a valid device URI?
2347*5e7646d2SAndroid Build Coastguard Worker     */
2348*5e7646d2SAndroid Build Coastguard Worker 
2349*5e7646d2SAndroid Build Coastguard Worker     http_uri_status_t	uri_status;	/* URI separation status */
2350*5e7646d2SAndroid Build Coastguard Worker     char		old_device_uri[1024];
2351*5e7646d2SAndroid Build Coastguard Worker 					/* Old device URI */
2352*5e7646d2SAndroid Build Coastguard Worker 
2353*5e7646d2SAndroid Build Coastguard Worker     need_restart_job = 1;
2354*5e7646d2SAndroid Build Coastguard Worker 
2355*5e7646d2SAndroid Build Coastguard Worker     uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
2356*5e7646d2SAndroid Build Coastguard Worker 				 attr->values[0].string.text,
2357*5e7646d2SAndroid Build Coastguard Worker 				 scheme, sizeof(scheme),
2358*5e7646d2SAndroid Build Coastguard Worker 				 username, sizeof(username),
2359*5e7646d2SAndroid Build Coastguard Worker 				 host, sizeof(host), &port,
2360*5e7646d2SAndroid Build Coastguard Worker 				 resource, sizeof(resource));
2361*5e7646d2SAndroid Build Coastguard Worker 
2362*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "%s device-uri: %s", printer->name, httpURIStatusString(uri_status));
2363*5e7646d2SAndroid Build Coastguard Worker 
2364*5e7646d2SAndroid Build Coastguard Worker     if (uri_status < HTTP_URI_OK)
2365*5e7646d2SAndroid Build Coastguard Worker     {
2366*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."),
2367*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[0].string.text);
2368*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2369*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2370*5e7646d2SAndroid Build Coastguard Worker 
2371*5e7646d2SAndroid Build Coastguard Worker       return;
2372*5e7646d2SAndroid Build Coastguard Worker     }
2373*5e7646d2SAndroid Build Coastguard Worker 
2374*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(scheme, "file"))
2375*5e7646d2SAndroid Build Coastguard Worker     {
2376*5e7646d2SAndroid Build Coastguard Worker      /*
2377*5e7646d2SAndroid Build Coastguard Worker       * See if the administrator has enabled file devices...
2378*5e7646d2SAndroid Build Coastguard Worker       */
2379*5e7646d2SAndroid Build Coastguard Worker 
2380*5e7646d2SAndroid Build Coastguard Worker       if (!FileDevice && strcmp(resource, "/dev/null"))
2381*5e7646d2SAndroid Build Coastguard Worker       {
2382*5e7646d2SAndroid Build Coastguard Worker        /*
2383*5e7646d2SAndroid Build Coastguard Worker         * File devices are disabled and the URL is not file:/dev/null...
2384*5e7646d2SAndroid Build Coastguard Worker 	*/
2385*5e7646d2SAndroid Build Coastguard Worker 
2386*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_POSSIBLE,
2387*5e7646d2SAndroid Build Coastguard Worker 	                _("File device URIs have been disabled. "
2388*5e7646d2SAndroid Build Coastguard Worker 	                  "To enable, see the FileDevice directive in "
2389*5e7646d2SAndroid Build Coastguard Worker 			  "\"%s/cups-files.conf\"."),
2390*5e7646d2SAndroid Build Coastguard Worker 			ServerRoot);
2391*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2392*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2393*5e7646d2SAndroid Build Coastguard Worker 
2394*5e7646d2SAndroid Build Coastguard Worker 	return;
2395*5e7646d2SAndroid Build Coastguard Worker       }
2396*5e7646d2SAndroid Build Coastguard Worker     }
2397*5e7646d2SAndroid Build Coastguard Worker     else
2398*5e7646d2SAndroid Build Coastguard Worker     {
2399*5e7646d2SAndroid Build Coastguard Worker      /*
2400*5e7646d2SAndroid Build Coastguard Worker       * See if the backend exists and is executable...
2401*5e7646d2SAndroid Build Coastguard Worker       */
2402*5e7646d2SAndroid Build Coastguard Worker 
2403*5e7646d2SAndroid Build Coastguard Worker       snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, scheme);
2404*5e7646d2SAndroid Build Coastguard Worker       if (access(srcfile, X_OK))
2405*5e7646d2SAndroid Build Coastguard Worker       {
2406*5e7646d2SAndroid Build Coastguard Worker        /*
2407*5e7646d2SAndroid Build Coastguard Worker         * Could not find device in list!
2408*5e7646d2SAndroid Build Coastguard Worker 	*/
2409*5e7646d2SAndroid Build Coastguard Worker 
2410*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_POSSIBLE,
2411*5e7646d2SAndroid Build Coastguard Worker                         _("Bad device-uri scheme \"%s\"."), scheme);
2412*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2413*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2414*5e7646d2SAndroid Build Coastguard Worker 
2415*5e7646d2SAndroid Build Coastguard Worker 	return;
2416*5e7646d2SAndroid Build Coastguard Worker       }
2417*5e7646d2SAndroid Build Coastguard Worker     }
2418*5e7646d2SAndroid Build Coastguard Worker 
2419*5e7646d2SAndroid Build Coastguard Worker     if (printer->sanitized_device_uri)
2420*5e7646d2SAndroid Build Coastguard Worker       strlcpy(old_device_uri, printer->sanitized_device_uri,
2421*5e7646d2SAndroid Build Coastguard Worker               sizeof(old_device_uri));
2422*5e7646d2SAndroid Build Coastguard Worker     else
2423*5e7646d2SAndroid Build Coastguard Worker       old_device_uri[0] = '\0';
2424*5e7646d2SAndroid Build Coastguard Worker 
2425*5e7646d2SAndroid Build Coastguard Worker     cupsdSetDeviceURI(printer, attr->values[0].string.text);
2426*5e7646d2SAndroid Build Coastguard Worker 
2427*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
2428*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s device-uri to \"%s\" (was \"%s\".)",
2429*5e7646d2SAndroid Build Coastguard Worker         	    printer->name, printer->sanitized_device_uri,
2430*5e7646d2SAndroid Build Coastguard Worker 		    old_device_uri);
2431*5e7646d2SAndroid Build Coastguard Worker 
2432*5e7646d2SAndroid Build Coastguard Worker     set_device_uri = 1;
2433*5e7646d2SAndroid Build Coastguard Worker   }
2434*5e7646d2SAndroid Build Coastguard Worker 
2435*5e7646d2SAndroid Build Coastguard Worker   set_port_monitor = 0;
2436*5e7646d2SAndroid Build Coastguard Worker 
2437*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "port-monitor",
2438*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_NAME)) != NULL)
2439*5e7646d2SAndroid Build Coastguard Worker   {
2440*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t	*supported;	/* port-monitor-supported attribute */
2441*5e7646d2SAndroid Build Coastguard Worker 
2442*5e7646d2SAndroid Build Coastguard Worker 
2443*5e7646d2SAndroid Build Coastguard Worker     need_restart_job = 1;
2444*5e7646d2SAndroid Build Coastguard Worker 
2445*5e7646d2SAndroid Build Coastguard Worker     supported = ippFindAttribute(printer->ppd_attrs, "port-monitor-supported",
2446*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_NAME);
2447*5e7646d2SAndroid Build Coastguard Worker     if (supported)
2448*5e7646d2SAndroid Build Coastguard Worker     {
2449*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < supported->num_values; i ++)
2450*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(supported->values[i].string.text,
2451*5e7646d2SAndroid Build Coastguard Worker                     attr->values[0].string.text))
2452*5e7646d2SAndroid Build Coastguard Worker           break;
2453*5e7646d2SAndroid Build Coastguard Worker     }
2454*5e7646d2SAndroid Build Coastguard Worker 
2455*5e7646d2SAndroid Build Coastguard Worker     if (!supported || i >= supported->num_values)
2456*5e7646d2SAndroid Build Coastguard Worker     {
2457*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."),
2458*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].string.text);
2459*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2460*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2461*5e7646d2SAndroid Build Coastguard Worker 
2462*5e7646d2SAndroid Build Coastguard Worker       return;
2463*5e7646d2SAndroid Build Coastguard Worker     }
2464*5e7646d2SAndroid Build Coastguard Worker 
2465*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
2466*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s port-monitor to \"%s\" (was \"%s\".)",
2467*5e7646d2SAndroid Build Coastguard Worker                     printer->name, attr->values[0].string.text,
2468*5e7646d2SAndroid Build Coastguard Worker 	            printer->port_monitor ? printer->port_monitor : "none");
2469*5e7646d2SAndroid Build Coastguard Worker 
2470*5e7646d2SAndroid Build Coastguard Worker     if (strcmp(attr->values[0].string.text, "none"))
2471*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->port_monitor, attr->values[0].string.text);
2472*5e7646d2SAndroid Build Coastguard Worker     else
2473*5e7646d2SAndroid Build Coastguard Worker       cupsdClearString(&printer->port_monitor);
2474*5e7646d2SAndroid Build Coastguard Worker 
2475*5e7646d2SAndroid Build Coastguard Worker     set_port_monitor = 1;
2476*5e7646d2SAndroid Build Coastguard Worker   }
2477*5e7646d2SAndroid Build Coastguard Worker 
2478*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
2479*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_BOOLEAN)) != NULL &&
2480*5e7646d2SAndroid Build Coastguard Worker       attr->values[0].boolean != printer->accepting)
2481*5e7646d2SAndroid Build Coastguard Worker   {
2482*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
2483*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s printer-is-accepting-jobs to %d (was %d.)",
2484*5e7646d2SAndroid Build Coastguard Worker                     printer->name, attr->values[0].boolean, printer->accepting);
2485*5e7646d2SAndroid Build Coastguard Worker 
2486*5e7646d2SAndroid Build Coastguard Worker     printer->accepting = attr->values[0].boolean;
2487*5e7646d2SAndroid Build Coastguard Worker 
2488*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
2489*5e7646d2SAndroid Build Coastguard Worker                   "%s accepting jobs.",
2490*5e7646d2SAndroid Build Coastguard Worker 		  printer->accepting ? "Now" : "No longer");
2491*5e7646d2SAndroid Build Coastguard Worker   }
2492*5e7646d2SAndroid Build Coastguard Worker 
2493*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
2494*5e7646d2SAndroid Build Coastguard Worker   {
2495*5e7646d2SAndroid Build Coastguard Worker     if (ippGetBoolean(attr, 0) &&
2496*5e7646d2SAndroid Build Coastguard Worker         printer->num_auth_info_required == 1 &&
2497*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(printer->auth_info_required[0], "negotiate"))
2498*5e7646d2SAndroid Build Coastguard Worker     {
2499*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
2500*5e7646d2SAndroid Build Coastguard Worker                       _("Cannot share a remote Kerberized printer."));
2501*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2502*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2503*5e7646d2SAndroid Build Coastguard Worker 
2504*5e7646d2SAndroid Build Coastguard Worker       return;
2505*5e7646d2SAndroid Build Coastguard Worker     }
2506*5e7646d2SAndroid Build Coastguard Worker 
2507*5e7646d2SAndroid Build Coastguard Worker     if (printer->type & CUPS_PRINTER_REMOTE)
2508*5e7646d2SAndroid Build Coastguard Worker     {
2509*5e7646d2SAndroid Build Coastguard Worker      /*
2510*5e7646d2SAndroid Build Coastguard Worker       * Cannot re-share remote printers.
2511*5e7646d2SAndroid Build Coastguard Worker       */
2512*5e7646d2SAndroid Build Coastguard Worker 
2513*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
2514*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2515*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2516*5e7646d2SAndroid Build Coastguard Worker 
2517*5e7646d2SAndroid Build Coastguard Worker       return;
2518*5e7646d2SAndroid Build Coastguard Worker     }
2519*5e7646d2SAndroid Build Coastguard Worker 
2520*5e7646d2SAndroid Build Coastguard Worker     if (printer->shared && !ippGetBoolean(attr, 0))
2521*5e7646d2SAndroid Build Coastguard Worker       cupsdDeregisterPrinter(printer, 1);
2522*5e7646d2SAndroid Build Coastguard Worker 
2523*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
2524*5e7646d2SAndroid Build Coastguard Worker                     "Setting %s printer-is-shared to %d (was %d.)",
2525*5e7646d2SAndroid Build Coastguard Worker                     printer->name, attr->values[0].boolean, printer->shared);
2526*5e7646d2SAndroid Build Coastguard Worker 
2527*5e7646d2SAndroid Build Coastguard Worker     printer->shared = ippGetBoolean(attr, 0);
2528*5e7646d2SAndroid Build Coastguard Worker     if (printer->shared && printer->temporary)
2529*5e7646d2SAndroid Build Coastguard Worker       printer->temporary = 0;
2530*5e7646d2SAndroid Build Coastguard Worker   }
2531*5e7646d2SAndroid Build Coastguard Worker 
2532*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state",
2533*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ENUM)) != NULL)
2534*5e7646d2SAndroid Build Coastguard Worker   {
2535*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer != IPP_PRINTER_IDLE &&
2536*5e7646d2SAndroid Build Coastguard Worker         attr->values[0].integer != IPP_PRINTER_STOPPED)
2537*5e7646d2SAndroid Build Coastguard Worker     {
2538*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."),
2539*5e7646d2SAndroid Build Coastguard Worker                       attr->values[0].integer);
2540*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2541*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2542*5e7646d2SAndroid Build Coastguard Worker 
2543*5e7646d2SAndroid Build Coastguard Worker       return;
2544*5e7646d2SAndroid Build Coastguard Worker     }
2545*5e7646d2SAndroid Build Coastguard Worker 
2546*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
2547*5e7646d2SAndroid Build Coastguard Worker                     printer->name, attr->values[0].integer, printer->state);
2548*5e7646d2SAndroid Build Coastguard Worker 
2549*5e7646d2SAndroid Build Coastguard Worker     if (attr->values[0].integer == IPP_PRINTER_STOPPED)
2550*5e7646d2SAndroid Build Coastguard Worker       cupsdStopPrinter(printer, 0);
2551*5e7646d2SAndroid Build Coastguard Worker     else
2552*5e7646d2SAndroid Build Coastguard Worker     {
2553*5e7646d2SAndroid Build Coastguard Worker       need_restart_job = 1;
2554*5e7646d2SAndroid Build Coastguard Worker       cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0);
2555*5e7646d2SAndroid Build Coastguard Worker     }
2556*5e7646d2SAndroid Build Coastguard Worker   }
2557*5e7646d2SAndroid Build Coastguard Worker 
2558*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state-message",
2559*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
2560*5e7646d2SAndroid Build Coastguard Worker   {
2561*5e7646d2SAndroid Build Coastguard Worker     strlcpy(printer->state_message, attr->values[0].string.text,
2562*5e7646d2SAndroid Build Coastguard Worker             sizeof(printer->state_message));
2563*5e7646d2SAndroid Build Coastguard Worker 
2564*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s",
2565*5e7646d2SAndroid Build Coastguard Worker                   printer->state_message);
2566*5e7646d2SAndroid Build Coastguard Worker   }
2567*5e7646d2SAndroid Build Coastguard Worker 
2568*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state-reasons",
2569*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
2570*5e7646d2SAndroid Build Coastguard Worker   {
2571*5e7646d2SAndroid Build Coastguard Worker     if (attr->num_values >
2572*5e7646d2SAndroid Build Coastguard Worker             (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0])))
2573*5e7646d2SAndroid Build Coastguard Worker     {
2574*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE,
2575*5e7646d2SAndroid Build Coastguard Worker                       _("Too many printer-state-reasons values (%d > %d)."),
2576*5e7646d2SAndroid Build Coastguard Worker 		      attr->num_values,
2577*5e7646d2SAndroid Build Coastguard Worker 		      (int)(sizeof(printer->reasons) /
2578*5e7646d2SAndroid Build Coastguard Worker 		            sizeof(printer->reasons[0])));
2579*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2580*5e7646d2SAndroid Build Coastguard Worker         cupsdDeletePrinter(printer, 0);
2581*5e7646d2SAndroid Build Coastguard Worker 
2582*5e7646d2SAndroid Build Coastguard Worker       return;
2583*5e7646d2SAndroid Build Coastguard Worker     }
2584*5e7646d2SAndroid Build Coastguard Worker 
2585*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < printer->num_reasons; i ++)
2586*5e7646d2SAndroid Build Coastguard Worker       _cupsStrFree(printer->reasons[i]);
2587*5e7646d2SAndroid Build Coastguard Worker 
2588*5e7646d2SAndroid Build Coastguard Worker     printer->num_reasons = 0;
2589*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < attr->num_values; i ++)
2590*5e7646d2SAndroid Build Coastguard Worker     {
2591*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->values[i].string.text, "none"))
2592*5e7646d2SAndroid Build Coastguard Worker         continue;
2593*5e7646d2SAndroid Build Coastguard Worker 
2594*5e7646d2SAndroid Build Coastguard Worker       printer->reasons[printer->num_reasons] = _cupsStrAlloc(attr->values[i].string.text);
2595*5e7646d2SAndroid Build Coastguard Worker       printer->num_reasons ++;
2596*5e7646d2SAndroid Build Coastguard Worker 
2597*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->values[i].string.text, "paused") &&
2598*5e7646d2SAndroid Build Coastguard Worker           printer->state != IPP_PRINTER_STOPPED)
2599*5e7646d2SAndroid Build Coastguard Worker       {
2600*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogMessage(CUPSD_LOG_INFO,
2601*5e7646d2SAndroid Build Coastguard Worker 	                "Setting %s printer-state to %d (was %d.)",
2602*5e7646d2SAndroid Build Coastguard Worker 			printer->name, IPP_PRINTER_STOPPED, printer->state);
2603*5e7646d2SAndroid Build Coastguard Worker 	cupsdStopPrinter(printer, 0);
2604*5e7646d2SAndroid Build Coastguard Worker       }
2605*5e7646d2SAndroid Build Coastguard Worker     }
2606*5e7646d2SAndroid Build Coastguard Worker 
2607*5e7646d2SAndroid Build Coastguard Worker     if (PrintcapFormat == PRINTCAP_PLIST)
2608*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
2609*5e7646d2SAndroid Build Coastguard Worker 
2610*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
2611*5e7646d2SAndroid Build Coastguard Worker                   "Printer \"%s\" state changed.", printer->name);
2612*5e7646d2SAndroid Build Coastguard Worker   }
2613*5e7646d2SAndroid Build Coastguard Worker 
2614*5e7646d2SAndroid Build Coastguard Worker   if (!set_printer_defaults(con, printer))
2615*5e7646d2SAndroid Build Coastguard Worker   {
2616*5e7646d2SAndroid Build Coastguard Worker     if (!modify)
2617*5e7646d2SAndroid Build Coastguard Worker       cupsdDeletePrinter(printer, 0);
2618*5e7646d2SAndroid Build Coastguard Worker 
2619*5e7646d2SAndroid Build Coastguard Worker     return;
2620*5e7646d2SAndroid Build Coastguard Worker   }
2621*5e7646d2SAndroid Build Coastguard Worker 
2622*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "auth-info-required",
2623*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
2624*5e7646d2SAndroid Build Coastguard Worker     cupsdSetAuthInfoRequired(printer, NULL, attr);
2625*5e7646d2SAndroid Build Coastguard Worker 
2626*5e7646d2SAndroid Build Coastguard Worker  /*
2627*5e7646d2SAndroid Build Coastguard Worker   * See if we have all required attributes...
2628*5e7646d2SAndroid Build Coastguard Worker   */
2629*5e7646d2SAndroid Build Coastguard Worker 
2630*5e7646d2SAndroid Build Coastguard Worker   if (!printer->device_uri)
2631*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->device_uri, "file:///dev/null");
2632*5e7646d2SAndroid Build Coastguard Worker 
2633*5e7646d2SAndroid Build Coastguard Worker  /*
2634*5e7646d2SAndroid Build Coastguard Worker   * See if we have a PPD file attached to the request...
2635*5e7646d2SAndroid Build Coastguard Worker   */
2636*5e7646d2SAndroid Build Coastguard Worker 
2637*5e7646d2SAndroid Build Coastguard Worker   if (con->filename)
2638*5e7646d2SAndroid Build Coastguard Worker   {
2639*5e7646d2SAndroid Build Coastguard Worker     need_restart_job = 1;
2640*5e7646d2SAndroid Build Coastguard Worker     changed_driver   = 1;
2641*5e7646d2SAndroid Build Coastguard Worker 
2642*5e7646d2SAndroid Build Coastguard Worker     strlcpy(srcfile, con->filename, sizeof(srcfile));
2643*5e7646d2SAndroid Build Coastguard Worker 
2644*5e7646d2SAndroid Build Coastguard Worker     if ((fp = cupsFileOpen(srcfile, "rb")))
2645*5e7646d2SAndroid Build Coastguard Worker     {
2646*5e7646d2SAndroid Build Coastguard Worker      /*
2647*5e7646d2SAndroid Build Coastguard Worker       * Yes; get the first line from it...
2648*5e7646d2SAndroid Build Coastguard Worker       */
2649*5e7646d2SAndroid Build Coastguard Worker 
2650*5e7646d2SAndroid Build Coastguard Worker       line[0] = '\0';
2651*5e7646d2SAndroid Build Coastguard Worker       cupsFileGets(fp, line, sizeof(line));
2652*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(fp);
2653*5e7646d2SAndroid Build Coastguard Worker 
2654*5e7646d2SAndroid Build Coastguard Worker      /*
2655*5e7646d2SAndroid Build Coastguard Worker       * Then see what kind of file it is...
2656*5e7646d2SAndroid Build Coastguard Worker       */
2657*5e7646d2SAndroid Build Coastguard Worker 
2658*5e7646d2SAndroid Build Coastguard Worker       if (strncmp(line, "*PPD-Adobe", 10))
2659*5e7646d2SAndroid Build Coastguard Worker       {
2660*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, _("Bad PPD file."));
2661*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2662*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2663*5e7646d2SAndroid Build Coastguard Worker 
2664*5e7646d2SAndroid Build Coastguard Worker 	return;
2665*5e7646d2SAndroid Build Coastguard Worker       }
2666*5e7646d2SAndroid Build Coastguard Worker 
2667*5e7646d2SAndroid Build Coastguard Worker       snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
2668*5e7646d2SAndroid Build Coastguard Worker                printer->name);
2669*5e7646d2SAndroid Build Coastguard Worker 
2670*5e7646d2SAndroid Build Coastguard Worker      /*
2671*5e7646d2SAndroid Build Coastguard Worker       * The new file is a PPD file, so move the file over to the ppd
2672*5e7646d2SAndroid Build Coastguard Worker       * directory...
2673*5e7646d2SAndroid Build Coastguard Worker       */
2674*5e7646d2SAndroid Build Coastguard Worker 
2675*5e7646d2SAndroid Build Coastguard Worker       if (copy_file(srcfile, dstfile, ConfigFilePerm))
2676*5e7646d2SAndroid Build Coastguard Worker       {
2677*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file - %s"), strerror(errno));
2678*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2679*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2680*5e7646d2SAndroid Build Coastguard Worker 
2681*5e7646d2SAndroid Build Coastguard Worker 	return;
2682*5e7646d2SAndroid Build Coastguard Worker       }
2683*5e7646d2SAndroid Build Coastguard Worker 
2684*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully");
2685*5e7646d2SAndroid Build Coastguard Worker     }
2686*5e7646d2SAndroid Build Coastguard Worker   }
2687*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL)
2688*5e7646d2SAndroid Build Coastguard Worker   {
2689*5e7646d2SAndroid Build Coastguard Worker     const char *ppd_name = ippGetString(attr, 0, NULL);
2690*5e7646d2SAndroid Build Coastguard Worker 					/* ppd-name value */
2691*5e7646d2SAndroid Build Coastguard Worker 
2692*5e7646d2SAndroid Build Coastguard Worker     need_restart_job = 1;
2693*5e7646d2SAndroid Build Coastguard Worker     changed_driver   = 1;
2694*5e7646d2SAndroid Build Coastguard Worker 
2695*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(ppd_name, "everywhere"))
2696*5e7646d2SAndroid Build Coastguard Worker     {
2697*5e7646d2SAndroid Build Coastguard Worker       // Create IPP Everywhere PPD...
2698*5e7646d2SAndroid Build Coastguard Worker       if (!printer->device_uri || (strncmp(printer->device_uri, "dnssd://", 8) && strncmp(printer->device_uri, "ipp://", 6) && strncmp(printer->device_uri, "ipps://", 7) && strncmp(printer->device_uri, "ippusb://", 9)))
2699*5e7646d2SAndroid Build Coastguard Worker       {
2700*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_INTERNAL_ERROR, _("IPP Everywhere driver requires an IPP connection."));
2701*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2702*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2703*5e7646d2SAndroid Build Coastguard Worker 
2704*5e7646d2SAndroid Build Coastguard Worker 	return;
2705*5e7646d2SAndroid Build Coastguard Worker       }
2706*5e7646d2SAndroid Build Coastguard Worker 
2707*5e7646d2SAndroid Build Coastguard Worker       // Run a background thread to create the PPD...
2708*5e7646d2SAndroid Build Coastguard Worker       _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
2709*5e7646d2SAndroid Build Coastguard Worker     }
2710*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(ppd_name, "raw"))
2711*5e7646d2SAndroid Build Coastguard Worker     {
2712*5e7646d2SAndroid Build Coastguard Worker      /*
2713*5e7646d2SAndroid Build Coastguard Worker       * Raw driver, remove any existing PPD file.
2714*5e7646d2SAndroid Build Coastguard Worker       */
2715*5e7646d2SAndroid Build Coastguard Worker 
2716*5e7646d2SAndroid Build Coastguard Worker       snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name);
2717*5e7646d2SAndroid Build Coastguard Worker       unlink(dstfile);
2718*5e7646d2SAndroid Build Coastguard Worker     }
2719*5e7646d2SAndroid Build Coastguard Worker     else if (strstr(ppd_name, "../"))
2720*5e7646d2SAndroid Build Coastguard Worker     {
2721*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value."));
2722*5e7646d2SAndroid Build Coastguard Worker       if (!modify)
2723*5e7646d2SAndroid Build Coastguard Worker 	cupsdDeletePrinter(printer, 0);
2724*5e7646d2SAndroid Build Coastguard Worker 
2725*5e7646d2SAndroid Build Coastguard Worker       return;
2726*5e7646d2SAndroid Build Coastguard Worker     }
2727*5e7646d2SAndroid Build Coastguard Worker     else
2728*5e7646d2SAndroid Build Coastguard Worker     {
2729*5e7646d2SAndroid Build Coastguard Worker      /*
2730*5e7646d2SAndroid Build Coastguard Worker       * PPD model file...
2731*5e7646d2SAndroid Build Coastguard Worker       */
2732*5e7646d2SAndroid Build Coastguard Worker 
2733*5e7646d2SAndroid Build Coastguard Worker       snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name);
2734*5e7646d2SAndroid Build Coastguard Worker 
2735*5e7646d2SAndroid Build Coastguard Worker       if (copy_model(con, ppd_name, dstfile))
2736*5e7646d2SAndroid Build Coastguard Worker       {
2737*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file."));
2738*5e7646d2SAndroid Build Coastguard Worker 	if (!modify)
2739*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeletePrinter(printer, 0);
2740*5e7646d2SAndroid Build Coastguard Worker 
2741*5e7646d2SAndroid Build Coastguard Worker 	return;
2742*5e7646d2SAndroid Build Coastguard Worker       }
2743*5e7646d2SAndroid Build Coastguard Worker 
2744*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully");
2745*5e7646d2SAndroid Build Coastguard Worker     }
2746*5e7646d2SAndroid Build Coastguard Worker   }
2747*5e7646d2SAndroid Build Coastguard Worker 
2748*5e7646d2SAndroid Build Coastguard Worker   if (changed_driver)
2749*5e7646d2SAndroid Build Coastguard Worker   {
2750*5e7646d2SAndroid Build Coastguard Worker    /*
2751*5e7646d2SAndroid Build Coastguard Worker     * If we changed the PPD, then remove the printer's cache file and clear the
2752*5e7646d2SAndroid Build Coastguard Worker     * printer-state-reasons...
2753*5e7646d2SAndroid Build Coastguard Worker     */
2754*5e7646d2SAndroid Build Coastguard Worker 
2755*5e7646d2SAndroid Build Coastguard Worker     char cache_name[1024];		/* Cache filename for printer attrs */
2756*5e7646d2SAndroid Build Coastguard Worker 
2757*5e7646d2SAndroid Build Coastguard Worker     snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, printer->name);
2758*5e7646d2SAndroid Build Coastguard Worker     unlink(cache_name);
2759*5e7646d2SAndroid Build Coastguard Worker 
2760*5e7646d2SAndroid Build Coastguard Worker     cupsdSetPrinterReasons(printer, "none");
2761*5e7646d2SAndroid Build Coastguard Worker 
2762*5e7646d2SAndroid Build Coastguard Worker    /*
2763*5e7646d2SAndroid Build Coastguard Worker     * (Re)register color profiles...
2764*5e7646d2SAndroid Build Coastguard Worker     */
2765*5e7646d2SAndroid Build Coastguard Worker 
2766*5e7646d2SAndroid Build Coastguard Worker     cupsdRegisterColor(printer);
2767*5e7646d2SAndroid Build Coastguard Worker   }
2768*5e7646d2SAndroid Build Coastguard Worker 
2769*5e7646d2SAndroid Build Coastguard Worker  /*
2770*5e7646d2SAndroid Build Coastguard Worker   * If we set the device URI but not the port monitor, check which port
2771*5e7646d2SAndroid Build Coastguard Worker   * monitor to use by default...
2772*5e7646d2SAndroid Build Coastguard Worker   */
2773*5e7646d2SAndroid Build Coastguard Worker 
2774*5e7646d2SAndroid Build Coastguard Worker   if (set_device_uri && !set_port_monitor)
2775*5e7646d2SAndroid Build Coastguard Worker   {
2776*5e7646d2SAndroid Build Coastguard Worker     ppd_file_t	*ppd;			/* PPD file */
2777*5e7646d2SAndroid Build Coastguard Worker     ppd_attr_t	*ppdattr;		/* cupsPortMonitor attribute */
2778*5e7646d2SAndroid Build Coastguard Worker 
2779*5e7646d2SAndroid Build Coastguard Worker 
2780*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme,
2781*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
2782*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
2783*5e7646d2SAndroid Build Coastguard Worker 
2784*5e7646d2SAndroid Build Coastguard Worker     snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot,
2785*5e7646d2SAndroid Build Coastguard Worker 	     printer->name);
2786*5e7646d2SAndroid Build Coastguard Worker     if ((ppd = _ppdOpenFile(srcfile, _PPD_LOCALIZATION_NONE)) != NULL)
2787*5e7646d2SAndroid Build Coastguard Worker     {
2788*5e7646d2SAndroid Build Coastguard Worker       for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2789*5e7646d2SAndroid Build Coastguard Worker 	   ppdattr;
2790*5e7646d2SAndroid Build Coastguard Worker 	   ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
2791*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(scheme, ppdattr->spec))
2792*5e7646d2SAndroid Build Coastguard Worker 	{
2793*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_INFO,
2794*5e7646d2SAndroid Build Coastguard Worker 			  "Setting %s port-monitor to \"%s\" (was \"%s\".)",
2795*5e7646d2SAndroid Build Coastguard Worker 			  printer->name, ppdattr->value,
2796*5e7646d2SAndroid Build Coastguard Worker 			  printer->port_monitor ? printer->port_monitor
2797*5e7646d2SAndroid Build Coastguard Worker 			                        : "none");
2798*5e7646d2SAndroid Build Coastguard Worker 
2799*5e7646d2SAndroid Build Coastguard Worker 	  if (strcmp(ppdattr->value, "none"))
2800*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetString(&printer->port_monitor, ppdattr->value);
2801*5e7646d2SAndroid Build Coastguard Worker 	  else
2802*5e7646d2SAndroid Build Coastguard Worker 	    cupsdClearString(&printer->port_monitor);
2803*5e7646d2SAndroid Build Coastguard Worker 
2804*5e7646d2SAndroid Build Coastguard Worker 	  break;
2805*5e7646d2SAndroid Build Coastguard Worker 	}
2806*5e7646d2SAndroid Build Coastguard Worker 
2807*5e7646d2SAndroid Build Coastguard Worker       ppdClose(ppd);
2808*5e7646d2SAndroid Build Coastguard Worker     }
2809*5e7646d2SAndroid Build Coastguard Worker   }
2810*5e7646d2SAndroid Build Coastguard Worker 
2811*5e7646d2SAndroid Build Coastguard Worker   printer->config_time = time(NULL);
2812*5e7646d2SAndroid Build Coastguard Worker 
2813*5e7646d2SAndroid Build Coastguard Worker  /*
2814*5e7646d2SAndroid Build Coastguard Worker   * Update the printer attributes and return...
2815*5e7646d2SAndroid Build Coastguard Worker   */
2816*5e7646d2SAndroid Build Coastguard Worker 
2817*5e7646d2SAndroid Build Coastguard Worker   if (!printer->temporary)
2818*5e7646d2SAndroid Build Coastguard Worker   {
2819*5e7646d2SAndroid Build Coastguard Worker     if (!printer->printer_id)
2820*5e7646d2SAndroid Build Coastguard Worker       printer->printer_id = NextPrinterId ++;
2821*5e7646d2SAndroid Build Coastguard Worker 
2822*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
2823*5e7646d2SAndroid Build Coastguard Worker   }
2824*5e7646d2SAndroid Build Coastguard Worker 
2825*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterAttrs(printer);
2826*5e7646d2SAndroid Build Coastguard Worker 
2827*5e7646d2SAndroid Build Coastguard Worker   if (need_restart_job && printer->job)
2828*5e7646d2SAndroid Build Coastguard Worker   {
2829*5e7646d2SAndroid Build Coastguard Worker    /*
2830*5e7646d2SAndroid Build Coastguard Worker     * Restart the current job...
2831*5e7646d2SAndroid Build Coastguard Worker     */
2832*5e7646d2SAndroid Build Coastguard Worker 
2833*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
2834*5e7646d2SAndroid Build Coastguard Worker                      "Job restarted because the printer was modified.");
2835*5e7646d2SAndroid Build Coastguard Worker   }
2836*5e7646d2SAndroid Build Coastguard Worker 
2837*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
2838*5e7646d2SAndroid Build Coastguard Worker 
2839*5e7646d2SAndroid Build Coastguard Worker   if (modify)
2840*5e7646d2SAndroid Build Coastguard Worker   {
2841*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
2842*5e7646d2SAndroid Build Coastguard Worker                   printer, NULL, "Printer \"%s\" modified by \"%s\".",
2843*5e7646d2SAndroid Build Coastguard Worker 		  printer->name, get_username(con));
2844*5e7646d2SAndroid Build Coastguard Worker 
2845*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".",
2846*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
2847*5e7646d2SAndroid Build Coastguard Worker   }
2848*5e7646d2SAndroid Build Coastguard Worker   else
2849*5e7646d2SAndroid Build Coastguard Worker   {
2850*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
2851*5e7646d2SAndroid Build Coastguard Worker                   printer, NULL, "New printer \"%s\" added by \"%s\".",
2852*5e7646d2SAndroid Build Coastguard Worker 		  printer->name, get_username(con));
2853*5e7646d2SAndroid Build Coastguard Worker 
2854*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".",
2855*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
2856*5e7646d2SAndroid Build Coastguard Worker   }
2857*5e7646d2SAndroid Build Coastguard Worker 
2858*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
2859*5e7646d2SAndroid Build Coastguard Worker }
2860*5e7646d2SAndroid Build Coastguard Worker 
2861*5e7646d2SAndroid Build Coastguard Worker 
2862*5e7646d2SAndroid Build Coastguard Worker /*
2863*5e7646d2SAndroid Build Coastguard Worker  * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
2864*5e7646d2SAndroid Build Coastguard Worker  *                                 based upon the printer state...
2865*5e7646d2SAndroid Build Coastguard Worker  */
2866*5e7646d2SAndroid Build Coastguard Worker 
2867*5e7646d2SAndroid Build Coastguard Worker static void
add_printer_state_reasons(cupsd_client_t * con,cupsd_printer_t * p)2868*5e7646d2SAndroid Build Coastguard Worker add_printer_state_reasons(
2869*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
2870*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *p)			/* I - Printer info */
2871*5e7646d2SAndroid Build Coastguard Worker {
2872*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
2873*5e7646d2SAndroid Build Coastguard Worker                   "add_printer_state_reasons(%p[%d], %p[%s])",
2874*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, p, p->name);
2875*5e7646d2SAndroid Build Coastguard Worker 
2876*5e7646d2SAndroid Build Coastguard Worker   if (p->num_reasons == 0)
2877*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2878*5e7646d2SAndroid Build Coastguard Worker                  "printer-state-reasons", NULL, "none");
2879*5e7646d2SAndroid Build Coastguard Worker   else
2880*5e7646d2SAndroid Build Coastguard Worker     ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2881*5e7646d2SAndroid Build Coastguard Worker                   "printer-state-reasons", p->num_reasons, NULL,
2882*5e7646d2SAndroid Build Coastguard Worker 		  (const char * const *)p->reasons);
2883*5e7646d2SAndroid Build Coastguard Worker }
2884*5e7646d2SAndroid Build Coastguard Worker 
2885*5e7646d2SAndroid Build Coastguard Worker 
2886*5e7646d2SAndroid Build Coastguard Worker /*
2887*5e7646d2SAndroid Build Coastguard Worker  * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
2888*5e7646d2SAndroid Build Coastguard Worker  *                            the specified printer or class.
2889*5e7646d2SAndroid Build Coastguard Worker  */
2890*5e7646d2SAndroid Build Coastguard Worker 
2891*5e7646d2SAndroid Build Coastguard Worker static void
add_queued_job_count(cupsd_client_t * con,cupsd_printer_t * p)2892*5e7646d2SAndroid Build Coastguard Worker add_queued_job_count(
2893*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
2894*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *p)			/* I - Printer or class */
2895*5e7646d2SAndroid Build Coastguard Worker {
2896*5e7646d2SAndroid Build Coastguard Worker   int		count;			/* Number of jobs on destination */
2897*5e7646d2SAndroid Build Coastguard Worker 
2898*5e7646d2SAndroid Build Coastguard Worker 
2899*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])",
2900*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, p, p->name);
2901*5e7646d2SAndroid Build Coastguard Worker 
2902*5e7646d2SAndroid Build Coastguard Worker   count = cupsdGetPrinterJobCount(p->name);
2903*5e7646d2SAndroid Build Coastguard Worker 
2904*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2905*5e7646d2SAndroid Build Coastguard Worker                 "queued-job-count", count);
2906*5e7646d2SAndroid Build Coastguard Worker }
2907*5e7646d2SAndroid Build Coastguard Worker 
2908*5e7646d2SAndroid Build Coastguard Worker 
2909*5e7646d2SAndroid Build Coastguard Worker /*
2910*5e7646d2SAndroid Build Coastguard Worker  * 'apply_printer_defaults()' - Apply printer default options to a job.
2911*5e7646d2SAndroid Build Coastguard Worker  */
2912*5e7646d2SAndroid Build Coastguard Worker 
2913*5e7646d2SAndroid Build Coastguard Worker static void
apply_printer_defaults(cupsd_printer_t * printer,cupsd_job_t * job)2914*5e7646d2SAndroid Build Coastguard Worker apply_printer_defaults(
2915*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *printer,		/* I - Printer */
2916*5e7646d2SAndroid Build Coastguard Worker     cupsd_job_t     *job)		/* I - Job */
2917*5e7646d2SAndroid Build Coastguard Worker {
2918*5e7646d2SAndroid Build Coastguard Worker   int		i,			/* Looping var */
2919*5e7646d2SAndroid Build Coastguard Worker 		num_options;		/* Number of default options */
2920*5e7646d2SAndroid Build Coastguard Worker   cups_option_t	*options,		/* Default options */
2921*5e7646d2SAndroid Build Coastguard Worker 		*option;		/* Current option */
2922*5e7646d2SAndroid Build Coastguard Worker 
2923*5e7646d2SAndroid Build Coastguard Worker 
2924*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_DEBUG, "Applying default options...");
2925*5e7646d2SAndroid Build Coastguard Worker 
2926*5e7646d2SAndroid Build Coastguard Worker  /*
2927*5e7646d2SAndroid Build Coastguard Worker   * Collect all of the default options and add the missing ones to the
2928*5e7646d2SAndroid Build Coastguard Worker   * job object...
2929*5e7646d2SAndroid Build Coastguard Worker   */
2930*5e7646d2SAndroid Build Coastguard Worker 
2931*5e7646d2SAndroid Build Coastguard Worker   for (i = printer->num_options, num_options = 0, options = NULL,
2932*5e7646d2SAndroid Build Coastguard Worker            option = printer->options;
2933*5e7646d2SAndroid Build Coastguard Worker        i > 0;
2934*5e7646d2SAndroid Build Coastguard Worker        i --, option ++)
2935*5e7646d2SAndroid Build Coastguard Worker     if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO))
2936*5e7646d2SAndroid Build Coastguard Worker     {
2937*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(option->name, "print-quality") && ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME))
2938*5e7646d2SAndroid Build Coastguard Worker         continue;                     /* Don't override cupsPrintQuality */
2939*5e7646d2SAndroid Build Coastguard Worker 
2940*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding default %s=%s", option->name, option->value);
2941*5e7646d2SAndroid Build Coastguard Worker 
2942*5e7646d2SAndroid Build Coastguard Worker       num_options = cupsAddOption(option->name, option->value, num_options, &options);
2943*5e7646d2SAndroid Build Coastguard Worker     }
2944*5e7646d2SAndroid Build Coastguard Worker 
2945*5e7646d2SAndroid Build Coastguard Worker  /*
2946*5e7646d2SAndroid Build Coastguard Worker   * Encode these options as attributes in the job object...
2947*5e7646d2SAndroid Build Coastguard Worker   */
2948*5e7646d2SAndroid Build Coastguard Worker 
2949*5e7646d2SAndroid Build Coastguard Worker   cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB);
2950*5e7646d2SAndroid Build Coastguard Worker   cupsFreeOptions(num_options, options);
2951*5e7646d2SAndroid Build Coastguard Worker }
2952*5e7646d2SAndroid Build Coastguard Worker 
2953*5e7646d2SAndroid Build Coastguard Worker 
2954*5e7646d2SAndroid Build Coastguard Worker /*
2955*5e7646d2SAndroid Build Coastguard Worker  * 'authenticate_job()' - Set job authentication info.
2956*5e7646d2SAndroid Build Coastguard Worker  */
2957*5e7646d2SAndroid Build Coastguard Worker 
2958*5e7646d2SAndroid Build Coastguard Worker static void
authenticate_job(cupsd_client_t * con,ipp_attribute_t * uri)2959*5e7646d2SAndroid Build Coastguard Worker authenticate_job(cupsd_client_t  *con,	/* I - Client connection */
2960*5e7646d2SAndroid Build Coastguard Worker 	         ipp_attribute_t *uri)	/* I - Job URI */
2961*5e7646d2SAndroid Build Coastguard Worker {
2962*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr,		/* job-id attribute */
2963*5e7646d2SAndroid Build Coastguard Worker 			*auth_info;	/* auth-info attribute */
2964*5e7646d2SAndroid Build Coastguard Worker   int			jobid;		/* Job ID */
2965*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Current job */
2966*5e7646d2SAndroid Build Coastguard Worker   char			scheme[HTTP_MAX_URI],
2967*5e7646d2SAndroid Build Coastguard Worker 					/* Method portion of URI */
2968*5e7646d2SAndroid Build Coastguard Worker 			username[HTTP_MAX_URI],
2969*5e7646d2SAndroid Build Coastguard Worker 					/* Username portion of URI */
2970*5e7646d2SAndroid Build Coastguard Worker 			host[HTTP_MAX_URI],
2971*5e7646d2SAndroid Build Coastguard Worker 					/* Host portion of URI */
2972*5e7646d2SAndroid Build Coastguard Worker 			resource[HTTP_MAX_URI];
2973*5e7646d2SAndroid Build Coastguard Worker 					/* Resource portion of URI */
2974*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port portion of URI */
2975*5e7646d2SAndroid Build Coastguard Worker 
2976*5e7646d2SAndroid Build Coastguard Worker 
2977*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)",
2978*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, uri->values[0].string.text);
2979*5e7646d2SAndroid Build Coastguard Worker 
2980*5e7646d2SAndroid Build Coastguard Worker  /*
2981*5e7646d2SAndroid Build Coastguard Worker   * Start with "everything is OK" status...
2982*5e7646d2SAndroid Build Coastguard Worker   */
2983*5e7646d2SAndroid Build Coastguard Worker 
2984*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
2985*5e7646d2SAndroid Build Coastguard Worker 
2986*5e7646d2SAndroid Build Coastguard Worker  /*
2987*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
2988*5e7646d2SAndroid Build Coastguard Worker   */
2989*5e7646d2SAndroid Build Coastguard Worker 
2990*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
2991*5e7646d2SAndroid Build Coastguard Worker   {
2992*5e7646d2SAndroid Build Coastguard Worker    /*
2993*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
2994*5e7646d2SAndroid Build Coastguard Worker     */
2995*5e7646d2SAndroid Build Coastguard Worker 
2996*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
2997*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
2998*5e7646d2SAndroid Build Coastguard Worker     {
2999*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
3000*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
3001*5e7646d2SAndroid Build Coastguard Worker       return;
3002*5e7646d2SAndroid Build Coastguard Worker     }
3003*5e7646d2SAndroid Build Coastguard Worker 
3004*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
3005*5e7646d2SAndroid Build Coastguard Worker   }
3006*5e7646d2SAndroid Build Coastguard Worker   else
3007*5e7646d2SAndroid Build Coastguard Worker   {
3008*5e7646d2SAndroid Build Coastguard Worker    /*
3009*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
3010*5e7646d2SAndroid Build Coastguard Worker     */
3011*5e7646d2SAndroid Build Coastguard Worker 
3012*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
3013*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
3014*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
3015*5e7646d2SAndroid Build Coastguard Worker 
3016*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
3017*5e7646d2SAndroid Build Coastguard Worker     {
3018*5e7646d2SAndroid Build Coastguard Worker      /*
3019*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
3020*5e7646d2SAndroid Build Coastguard Worker       */
3021*5e7646d2SAndroid Build Coastguard Worker 
3022*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
3023*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
3024*5e7646d2SAndroid Build Coastguard Worker       return;
3025*5e7646d2SAndroid Build Coastguard Worker     }
3026*5e7646d2SAndroid Build Coastguard Worker 
3027*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
3028*5e7646d2SAndroid Build Coastguard Worker   }
3029*5e7646d2SAndroid Build Coastguard Worker 
3030*5e7646d2SAndroid Build Coastguard Worker  /*
3031*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
3032*5e7646d2SAndroid Build Coastguard Worker   */
3033*5e7646d2SAndroid Build Coastguard Worker 
3034*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
3035*5e7646d2SAndroid Build Coastguard Worker   {
3036*5e7646d2SAndroid Build Coastguard Worker    /*
3037*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
3038*5e7646d2SAndroid Build Coastguard Worker     */
3039*5e7646d2SAndroid Build Coastguard Worker 
3040*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
3041*5e7646d2SAndroid Build Coastguard Worker     return;
3042*5e7646d2SAndroid Build Coastguard Worker   }
3043*5e7646d2SAndroid Build Coastguard Worker 
3044*5e7646d2SAndroid Build Coastguard Worker  /*
3045*5e7646d2SAndroid Build Coastguard Worker   * See if the job has been completed...
3046*5e7646d2SAndroid Build Coastguard Worker   */
3047*5e7646d2SAndroid Build Coastguard Worker 
3048*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value != IPP_JOB_HELD)
3049*5e7646d2SAndroid Build Coastguard Worker   {
3050*5e7646d2SAndroid Build Coastguard Worker    /*
3051*5e7646d2SAndroid Build Coastguard Worker     * Return a "not-possible" error...
3052*5e7646d2SAndroid Build Coastguard Worker     */
3053*5e7646d2SAndroid Build Coastguard Worker 
3054*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE,
3055*5e7646d2SAndroid Build Coastguard Worker                     _("Job #%d is not held for authentication."),
3056*5e7646d2SAndroid Build Coastguard Worker 		    jobid);
3057*5e7646d2SAndroid Build Coastguard Worker     return;
3058*5e7646d2SAndroid Build Coastguard Worker   }
3059*5e7646d2SAndroid Build Coastguard Worker 
3060*5e7646d2SAndroid Build Coastguard Worker  /*
3061*5e7646d2SAndroid Build Coastguard Worker   * See if we have already authenticated...
3062*5e7646d2SAndroid Build Coastguard Worker   */
3063*5e7646d2SAndroid Build Coastguard Worker 
3064*5e7646d2SAndroid Build Coastguard Worker   auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
3065*5e7646d2SAndroid Build Coastguard Worker 
3066*5e7646d2SAndroid Build Coastguard Worker   if (!con->username[0] && !auth_info)
3067*5e7646d2SAndroid Build Coastguard Worker   {
3068*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t	*printer;	/* Job destination */
3069*5e7646d2SAndroid Build Coastguard Worker 
3070*5e7646d2SAndroid Build Coastguard Worker    /*
3071*5e7646d2SAndroid Build Coastguard Worker     * No auth data.  If we need to authenticate via Kerberos, send a
3072*5e7646d2SAndroid Build Coastguard Worker     * HTTP auth challenge, otherwise just return an IPP error...
3073*5e7646d2SAndroid Build Coastguard Worker     */
3074*5e7646d2SAndroid Build Coastguard Worker 
3075*5e7646d2SAndroid Build Coastguard Worker     printer = cupsdFindDest(job->dest);
3076*5e7646d2SAndroid Build Coastguard Worker 
3077*5e7646d2SAndroid Build Coastguard Worker     if (printer && printer->num_auth_info_required > 0 &&
3078*5e7646d2SAndroid Build Coastguard Worker         !strcmp(printer->auth_info_required[0], "negotiate"))
3079*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, HTTP_UNAUTHORIZED, printer);
3080*5e7646d2SAndroid Build Coastguard Worker     else
3081*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_AUTHORIZED,
3082*5e7646d2SAndroid Build Coastguard Worker 		      _("No authentication information provided."));
3083*5e7646d2SAndroid Build Coastguard Worker     return;
3084*5e7646d2SAndroid Build Coastguard Worker   }
3085*5e7646d2SAndroid Build Coastguard Worker 
3086*5e7646d2SAndroid Build Coastguard Worker  /*
3087*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
3088*5e7646d2SAndroid Build Coastguard Worker   */
3089*5e7646d2SAndroid Build Coastguard Worker 
3090*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
3091*5e7646d2SAndroid Build Coastguard Worker   {
3092*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3093*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
3094*5e7646d2SAndroid Build Coastguard Worker     return;
3095*5e7646d2SAndroid Build Coastguard Worker   }
3096*5e7646d2SAndroid Build Coastguard Worker 
3097*5e7646d2SAndroid Build Coastguard Worker  /*
3098*5e7646d2SAndroid Build Coastguard Worker   * Save the authentication information for this job...
3099*5e7646d2SAndroid Build Coastguard Worker   */
3100*5e7646d2SAndroid Build Coastguard Worker 
3101*5e7646d2SAndroid Build Coastguard Worker   save_auth_info(con, job, auth_info);
3102*5e7646d2SAndroid Build Coastguard Worker 
3103*5e7646d2SAndroid Build Coastguard Worker  /*
3104*5e7646d2SAndroid Build Coastguard Worker   * Reset the job-hold-until value to "no-hold"...
3105*5e7646d2SAndroid Build Coastguard Worker   */
3106*5e7646d2SAndroid Build Coastguard Worker 
3107*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
3108*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) == NULL)
3109*5e7646d2SAndroid Build Coastguard Worker     attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
3110*5e7646d2SAndroid Build Coastguard Worker 
3111*5e7646d2SAndroid Build Coastguard Worker   if (attr)
3112*5e7646d2SAndroid Build Coastguard Worker   {
3113*5e7646d2SAndroid Build Coastguard Worker     ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
3114*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &attr, 0, "no-hold");
3115*5e7646d2SAndroid Build Coastguard Worker   }
3116*5e7646d2SAndroid Build Coastguard Worker 
3117*5e7646d2SAndroid Build Coastguard Worker  /*
3118*5e7646d2SAndroid Build Coastguard Worker   * Release the job and return...
3119*5e7646d2SAndroid Build Coastguard Worker   */
3120*5e7646d2SAndroid Build Coastguard Worker 
3121*5e7646d2SAndroid Build Coastguard Worker   cupsdReleaseJob(job);
3122*5e7646d2SAndroid Build Coastguard Worker 
3123*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_STATE, NULL, job, "Job authenticated by user");
3124*5e7646d2SAndroid Build Coastguard Worker 
3125*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "Authenticated by \"%s\".", con->username);
3126*5e7646d2SAndroid Build Coastguard Worker 
3127*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
3128*5e7646d2SAndroid Build Coastguard Worker }
3129*5e7646d2SAndroid Build Coastguard Worker 
3130*5e7646d2SAndroid Build Coastguard Worker 
3131*5e7646d2SAndroid Build Coastguard Worker /*
3132*5e7646d2SAndroid Build Coastguard Worker  * 'cancel_all_jobs()' - Cancel all or selected print jobs.
3133*5e7646d2SAndroid Build Coastguard Worker  */
3134*5e7646d2SAndroid Build Coastguard Worker 
3135*5e7646d2SAndroid Build Coastguard Worker static void
cancel_all_jobs(cupsd_client_t * con,ipp_attribute_t * uri)3136*5e7646d2SAndroid Build Coastguard Worker cancel_all_jobs(cupsd_client_t  *con,	/* I - Client connection */
3137*5e7646d2SAndroid Build Coastguard Worker 	        ipp_attribute_t *uri)	/* I - Job or Printer URI */
3138*5e7646d2SAndroid Build Coastguard Worker {
3139*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
3140*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
3141*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type */
3142*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
3143*5e7646d2SAndroid Build Coastguard Worker 		userpass[HTTP_MAX_URI],	/* Username portion of URI */
3144*5e7646d2SAndroid Build Coastguard Worker 		hostname[HTTP_MAX_URI],	/* Host portion of URI */
3145*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
3146*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
3147*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Attribute in request */
3148*5e7646d2SAndroid Build Coastguard Worker   const char	*username = NULL;	/* Username */
3149*5e7646d2SAndroid Build Coastguard Worker   cupsd_jobaction_t purge = CUPSD_JOB_DEFAULT;
3150*5e7646d2SAndroid Build Coastguard Worker 					/* Purge? */
3151*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer */
3152*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *job_ids;		/* job-ids attribute */
3153*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Job */
3154*5e7646d2SAndroid Build Coastguard Worker 
3155*5e7646d2SAndroid Build Coastguard Worker 
3156*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con,
3157*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
3158*5e7646d2SAndroid Build Coastguard Worker 
3159*5e7646d2SAndroid Build Coastguard Worker  /*
3160*5e7646d2SAndroid Build Coastguard Worker   * Get the jobs to cancel/purge...
3161*5e7646d2SAndroid Build Coastguard Worker   */
3162*5e7646d2SAndroid Build Coastguard Worker 
3163*5e7646d2SAndroid Build Coastguard Worker   switch (con->request->request.op.operation_id)
3164*5e7646d2SAndroid Build Coastguard Worker   {
3165*5e7646d2SAndroid Build Coastguard Worker     case IPP_PURGE_JOBS :
3166*5e7646d2SAndroid Build Coastguard Worker        /*
3167*5e7646d2SAndroid Build Coastguard Worker 	* Get the username (if any) for the jobs we want to cancel (only if
3168*5e7646d2SAndroid Build Coastguard Worker 	* "my-jobs" is specified...
3169*5e7646d2SAndroid Build Coastguard Worker 	*/
3170*5e7646d2SAndroid Build Coastguard Worker 
3171*5e7646d2SAndroid Build Coastguard Worker         if ((attr = ippFindAttribute(con->request, "my-jobs",
3172*5e7646d2SAndroid Build Coastguard Worker                                      IPP_TAG_BOOLEAN)) != NULL &&
3173*5e7646d2SAndroid Build Coastguard Worker             attr->values[0].boolean)
3174*5e7646d2SAndroid Build Coastguard Worker 	{
3175*5e7646d2SAndroid Build Coastguard Worker 	  if ((attr = ippFindAttribute(con->request, "requesting-user-name",
3176*5e7646d2SAndroid Build Coastguard Worker 				       IPP_TAG_NAME)) != NULL)
3177*5e7646d2SAndroid Build Coastguard Worker 	    username = attr->values[0].string.text;
3178*5e7646d2SAndroid Build Coastguard Worker 	  else
3179*5e7646d2SAndroid Build Coastguard Worker 	  {
3180*5e7646d2SAndroid Build Coastguard Worker 	    send_ipp_status(con, IPP_BAD_REQUEST,
3181*5e7646d2SAndroid Build Coastguard Worker 			    _("Missing requesting-user-name attribute."));
3182*5e7646d2SAndroid Build Coastguard Worker 	    return;
3183*5e7646d2SAndroid Build Coastguard Worker 	  }
3184*5e7646d2SAndroid Build Coastguard Worker 	}
3185*5e7646d2SAndroid Build Coastguard Worker 
3186*5e7646d2SAndroid Build Coastguard Worker        /*
3187*5e7646d2SAndroid Build Coastguard Worker 	* Look for the "purge-jobs" attribute...
3188*5e7646d2SAndroid Build Coastguard Worker 	*/
3189*5e7646d2SAndroid Build Coastguard Worker 
3190*5e7646d2SAndroid Build Coastguard Worker 	if ((attr = ippFindAttribute(con->request, "purge-jobs",
3191*5e7646d2SAndroid Build Coastguard Worker 				     IPP_TAG_BOOLEAN)) != NULL)
3192*5e7646d2SAndroid Build Coastguard Worker 	  purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
3193*5e7646d2SAndroid Build Coastguard Worker 	else
3194*5e7646d2SAndroid Build Coastguard Worker 	  purge = CUPSD_JOB_PURGE;
3195*5e7646d2SAndroid Build Coastguard Worker 	break;
3196*5e7646d2SAndroid Build Coastguard Worker 
3197*5e7646d2SAndroid Build Coastguard Worker     case IPP_CANCEL_MY_JOBS :
3198*5e7646d2SAndroid Build Coastguard Worker         if (con->username[0])
3199*5e7646d2SAndroid Build Coastguard Worker           username = con->username;
3200*5e7646d2SAndroid Build Coastguard Worker         else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
3201*5e7646d2SAndroid Build Coastguard Worker 					  IPP_TAG_NAME)) != NULL)
3202*5e7646d2SAndroid Build Coastguard Worker           username = attr->values[0].string.text;
3203*5e7646d2SAndroid Build Coastguard Worker         else
3204*5e7646d2SAndroid Build Coastguard Worker         {
3205*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_BAD_REQUEST,
3206*5e7646d2SAndroid Build Coastguard Worker 			  _("Missing requesting-user-name attribute."));
3207*5e7646d2SAndroid Build Coastguard Worker 	  return;
3208*5e7646d2SAndroid Build Coastguard Worker         }
3209*5e7646d2SAndroid Build Coastguard Worker 
3210*5e7646d2SAndroid Build Coastguard Worker     default :
3211*5e7646d2SAndroid Build Coastguard Worker         break;
3212*5e7646d2SAndroid Build Coastguard Worker   }
3213*5e7646d2SAndroid Build Coastguard Worker 
3214*5e7646d2SAndroid Build Coastguard Worker   job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
3215*5e7646d2SAndroid Build Coastguard Worker 
3216*5e7646d2SAndroid Build Coastguard Worker  /*
3217*5e7646d2SAndroid Build Coastguard Worker   * See if we have a printer URI...
3218*5e7646d2SAndroid Build Coastguard Worker   */
3219*5e7646d2SAndroid Build Coastguard Worker 
3220*5e7646d2SAndroid Build Coastguard Worker   if (strcmp(uri->name, "printer-uri"))
3221*5e7646d2SAndroid Build Coastguard Worker   {
3222*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
3223*5e7646d2SAndroid Build Coastguard Worker                     _("The printer-uri attribute is required."));
3224*5e7646d2SAndroid Build Coastguard Worker     return;
3225*5e7646d2SAndroid Build Coastguard Worker   }
3226*5e7646d2SAndroid Build Coastguard Worker 
3227*5e7646d2SAndroid Build Coastguard Worker  /*
3228*5e7646d2SAndroid Build Coastguard Worker   * And if the destination is valid...
3229*5e7646d2SAndroid Build Coastguard Worker   */
3230*5e7646d2SAndroid Build Coastguard Worker 
3231*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
3232*5e7646d2SAndroid Build Coastguard Worker   {
3233*5e7646d2SAndroid Build Coastguard Worker    /*
3234*5e7646d2SAndroid Build Coastguard Worker     * Bad URI?
3235*5e7646d2SAndroid Build Coastguard Worker     */
3236*5e7646d2SAndroid Build Coastguard Worker 
3237*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
3238*5e7646d2SAndroid Build Coastguard Worker                     scheme, sizeof(scheme), userpass, sizeof(userpass),
3239*5e7646d2SAndroid Build Coastguard Worker 		    hostname, sizeof(hostname), &port,
3240*5e7646d2SAndroid Build Coastguard Worker 		    resource, sizeof(resource));
3241*5e7646d2SAndroid Build Coastguard Worker 
3242*5e7646d2SAndroid Build Coastguard Worker     if ((!strncmp(resource, "/printers/", 10) && resource[10]) ||
3243*5e7646d2SAndroid Build Coastguard Worker         (!strncmp(resource, "/classes/", 9) && resource[9]))
3244*5e7646d2SAndroid Build Coastguard Worker     {
3245*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND,
3246*5e7646d2SAndroid Build Coastguard Worker                       _("The printer or class does not exist."));
3247*5e7646d2SAndroid Build Coastguard Worker       return;
3248*5e7646d2SAndroid Build Coastguard Worker     }
3249*5e7646d2SAndroid Build Coastguard Worker 
3250*5e7646d2SAndroid Build Coastguard Worker    /*
3251*5e7646d2SAndroid Build Coastguard Worker     * Check policy...
3252*5e7646d2SAndroid Build Coastguard Worker     */
3253*5e7646d2SAndroid Build Coastguard Worker 
3254*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
3255*5e7646d2SAndroid Build Coastguard Worker     {
3256*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, NULL);
3257*5e7646d2SAndroid Build Coastguard Worker       return;
3258*5e7646d2SAndroid Build Coastguard Worker     }
3259*5e7646d2SAndroid Build Coastguard Worker 
3260*5e7646d2SAndroid Build Coastguard Worker     if (job_ids)
3261*5e7646d2SAndroid Build Coastguard Worker     {
3262*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < job_ids->num_values; i ++)
3263*5e7646d2SAndroid Build Coastguard Worker       {
3264*5e7646d2SAndroid Build Coastguard Worker 	if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL)
3265*5e7646d2SAndroid Build Coastguard Worker 	  break;
3266*5e7646d2SAndroid Build Coastguard Worker 
3267*5e7646d2SAndroid Build Coastguard Worker         if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS &&
3268*5e7646d2SAndroid Build Coastguard Worker             _cups_strcasecmp(job->username, username))
3269*5e7646d2SAndroid Build Coastguard Worker           break;
3270*5e7646d2SAndroid Build Coastguard Worker       }
3271*5e7646d2SAndroid Build Coastguard Worker 
3272*5e7646d2SAndroid Build Coastguard Worker       if (i < job_ids->num_values)
3273*5e7646d2SAndroid Build Coastguard Worker       {
3274*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3275*5e7646d2SAndroid Build Coastguard Worker 			job_ids->values[i].integer);
3276*5e7646d2SAndroid Build Coastguard Worker 	return;
3277*5e7646d2SAndroid Build Coastguard Worker       }
3278*5e7646d2SAndroid Build Coastguard Worker 
3279*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < job_ids->num_values; i ++)
3280*5e7646d2SAndroid Build Coastguard Worker       {
3281*5e7646d2SAndroid Build Coastguard Worker 	job = cupsdFindJob(job_ids->values[i].integer);
3282*5e7646d2SAndroid Build Coastguard Worker 
3283*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3284*5e7646d2SAndroid Build Coastguard Worker 	                 purge == CUPSD_JOB_PURGE ? "Job purged by user." :
3285*5e7646d2SAndroid Build Coastguard Worker 	                                            "Job canceled by user.");
3286*5e7646d2SAndroid Build Coastguard Worker       }
3287*5e7646d2SAndroid Build Coastguard Worker 
3288*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
3289*5e7646d2SAndroid Build Coastguard Worker 		      purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3290*5e7646d2SAndroid Build Coastguard Worker 		      get_username(con));
3291*5e7646d2SAndroid Build Coastguard Worker     }
3292*5e7646d2SAndroid Build Coastguard Worker     else
3293*5e7646d2SAndroid Build Coastguard Worker     {
3294*5e7646d2SAndroid Build Coastguard Worker      /*
3295*5e7646d2SAndroid Build Coastguard Worker       * Cancel all jobs on all printers...
3296*5e7646d2SAndroid Build Coastguard Worker       */
3297*5e7646d2SAndroid Build Coastguard Worker 
3298*5e7646d2SAndroid Build Coastguard Worker       cupsdCancelJobs(NULL, username, purge != CUPSD_JOB_DEFAULT);
3299*5e7646d2SAndroid Build Coastguard Worker 
3300*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
3301*5e7646d2SAndroid Build Coastguard Worker 		      purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3302*5e7646d2SAndroid Build Coastguard Worker 		      get_username(con));
3303*5e7646d2SAndroid Build Coastguard Worker     }
3304*5e7646d2SAndroid Build Coastguard Worker   }
3305*5e7646d2SAndroid Build Coastguard Worker   else
3306*5e7646d2SAndroid Build Coastguard Worker   {
3307*5e7646d2SAndroid Build Coastguard Worker    /*
3308*5e7646d2SAndroid Build Coastguard Worker     * Check policy...
3309*5e7646d2SAndroid Build Coastguard Worker     */
3310*5e7646d2SAndroid Build Coastguard Worker 
3311*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
3312*5e7646d2SAndroid Build Coastguard Worker                                    NULL)) != HTTP_OK)
3313*5e7646d2SAndroid Build Coastguard Worker     {
3314*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, printer);
3315*5e7646d2SAndroid Build Coastguard Worker       return;
3316*5e7646d2SAndroid Build Coastguard Worker     }
3317*5e7646d2SAndroid Build Coastguard Worker 
3318*5e7646d2SAndroid Build Coastguard Worker     if (job_ids)
3319*5e7646d2SAndroid Build Coastguard Worker     {
3320*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < job_ids->num_values; i ++)
3321*5e7646d2SAndroid Build Coastguard Worker       {
3322*5e7646d2SAndroid Build Coastguard Worker 	if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL ||
3323*5e7646d2SAndroid Build Coastguard Worker 	    _cups_strcasecmp(job->dest, printer->name))
3324*5e7646d2SAndroid Build Coastguard Worker 	  break;
3325*5e7646d2SAndroid Build Coastguard Worker 
3326*5e7646d2SAndroid Build Coastguard Worker         if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS &&
3327*5e7646d2SAndroid Build Coastguard Worker             _cups_strcasecmp(job->username, username))
3328*5e7646d2SAndroid Build Coastguard Worker           break;
3329*5e7646d2SAndroid Build Coastguard Worker       }
3330*5e7646d2SAndroid Build Coastguard Worker 
3331*5e7646d2SAndroid Build Coastguard Worker       if (i < job_ids->num_values)
3332*5e7646d2SAndroid Build Coastguard Worker       {
3333*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3334*5e7646d2SAndroid Build Coastguard Worker 			job_ids->values[i].integer);
3335*5e7646d2SAndroid Build Coastguard Worker 	return;
3336*5e7646d2SAndroid Build Coastguard Worker       }
3337*5e7646d2SAndroid Build Coastguard Worker 
3338*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < job_ids->num_values; i ++)
3339*5e7646d2SAndroid Build Coastguard Worker       {
3340*5e7646d2SAndroid Build Coastguard Worker 	job = cupsdFindJob(job_ids->values[i].integer);
3341*5e7646d2SAndroid Build Coastguard Worker 
3342*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3343*5e7646d2SAndroid Build Coastguard Worker 	                 purge == CUPSD_JOB_PURGE ? "Job purged by user." :
3344*5e7646d2SAndroid Build Coastguard Worker 	                                            "Job canceled by user.");
3345*5e7646d2SAndroid Build Coastguard Worker       }
3346*5e7646d2SAndroid Build Coastguard Worker 
3347*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
3348*5e7646d2SAndroid Build Coastguard Worker 		      purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3349*5e7646d2SAndroid Build Coastguard Worker 		      get_username(con));
3350*5e7646d2SAndroid Build Coastguard Worker     }
3351*5e7646d2SAndroid Build Coastguard Worker     else
3352*5e7646d2SAndroid Build Coastguard Worker     {
3353*5e7646d2SAndroid Build Coastguard Worker      /*
3354*5e7646d2SAndroid Build Coastguard Worker       * Cancel all of the jobs on the named printer...
3355*5e7646d2SAndroid Build Coastguard Worker       */
3356*5e7646d2SAndroid Build Coastguard Worker 
3357*5e7646d2SAndroid Build Coastguard Worker       cupsdCancelJobs(printer->name, username, purge != CUPSD_JOB_DEFAULT);
3358*5e7646d2SAndroid Build Coastguard Worker 
3359*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
3360*5e7646d2SAndroid Build Coastguard Worker 		      printer->name,
3361*5e7646d2SAndroid Build Coastguard Worker 		      purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
3362*5e7646d2SAndroid Build Coastguard Worker 		      get_username(con));
3363*5e7646d2SAndroid Build Coastguard Worker     }
3364*5e7646d2SAndroid Build Coastguard Worker   }
3365*5e7646d2SAndroid Build Coastguard Worker 
3366*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
3367*5e7646d2SAndroid Build Coastguard Worker 
3368*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
3369*5e7646d2SAndroid Build Coastguard Worker }
3370*5e7646d2SAndroid Build Coastguard Worker 
3371*5e7646d2SAndroid Build Coastguard Worker 
3372*5e7646d2SAndroid Build Coastguard Worker /*
3373*5e7646d2SAndroid Build Coastguard Worker  * 'cancel_job()' - Cancel a print job.
3374*5e7646d2SAndroid Build Coastguard Worker  */
3375*5e7646d2SAndroid Build Coastguard Worker 
3376*5e7646d2SAndroid Build Coastguard Worker static void
cancel_job(cupsd_client_t * con,ipp_attribute_t * uri)3377*5e7646d2SAndroid Build Coastguard Worker cancel_job(cupsd_client_t  *con,	/* I - Client connection */
3378*5e7646d2SAndroid Build Coastguard Worker 	   ipp_attribute_t *uri)	/* I - Job or Printer URI */
3379*5e7646d2SAndroid Build Coastguard Worker {
3380*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
3381*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
3382*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
3383*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
3384*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
3385*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
3386*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
3387*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Job information */
3388*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type (printer/class) */
3389*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer data */
3390*5e7646d2SAndroid Build Coastguard Worker   cupsd_jobaction_t purge;		/* Purge the job? */
3391*5e7646d2SAndroid Build Coastguard Worker 
3392*5e7646d2SAndroid Build Coastguard Worker 
3393*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con,
3394*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
3395*5e7646d2SAndroid Build Coastguard Worker 
3396*5e7646d2SAndroid Build Coastguard Worker  /*
3397*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
3398*5e7646d2SAndroid Build Coastguard Worker   */
3399*5e7646d2SAndroid Build Coastguard Worker 
3400*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
3401*5e7646d2SAndroid Build Coastguard Worker   {
3402*5e7646d2SAndroid Build Coastguard Worker    /*
3403*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
3404*5e7646d2SAndroid Build Coastguard Worker     */
3405*5e7646d2SAndroid Build Coastguard Worker 
3406*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
3407*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
3408*5e7646d2SAndroid Build Coastguard Worker     {
3409*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
3410*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
3411*5e7646d2SAndroid Build Coastguard Worker       return;
3412*5e7646d2SAndroid Build Coastguard Worker     }
3413*5e7646d2SAndroid Build Coastguard Worker 
3414*5e7646d2SAndroid Build Coastguard Worker     if ((jobid = attr->values[0].integer) == 0)
3415*5e7646d2SAndroid Build Coastguard Worker     {
3416*5e7646d2SAndroid Build Coastguard Worker      /*
3417*5e7646d2SAndroid Build Coastguard Worker       * Find the current job on the specified printer...
3418*5e7646d2SAndroid Build Coastguard Worker       */
3419*5e7646d2SAndroid Build Coastguard Worker 
3420*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
3421*5e7646d2SAndroid Build Coastguard Worker       {
3422*5e7646d2SAndroid Build Coastguard Worker        /*
3423*5e7646d2SAndroid Build Coastguard Worker 	* Bad URI...
3424*5e7646d2SAndroid Build Coastguard Worker 	*/
3425*5e7646d2SAndroid Build Coastguard Worker 
3426*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND,
3427*5e7646d2SAndroid Build Coastguard Worker                 	_("The printer or class does not exist."));
3428*5e7646d2SAndroid Build Coastguard Worker 	return;
3429*5e7646d2SAndroid Build Coastguard Worker       }
3430*5e7646d2SAndroid Build Coastguard Worker 
3431*5e7646d2SAndroid Build Coastguard Worker      /*
3432*5e7646d2SAndroid Build Coastguard Worker       * See if there are any pending jobs...
3433*5e7646d2SAndroid Build Coastguard Worker       */
3434*5e7646d2SAndroid Build Coastguard Worker 
3435*5e7646d2SAndroid Build Coastguard Worker       for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
3436*5e7646d2SAndroid Build Coastguard Worker 	   job;
3437*5e7646d2SAndroid Build Coastguard Worker 	   job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
3438*5e7646d2SAndroid Build Coastguard Worker 	if (job->state_value <= IPP_JOB_PROCESSING &&
3439*5e7646d2SAndroid Build Coastguard Worker 	    !_cups_strcasecmp(job->dest, printer->name))
3440*5e7646d2SAndroid Build Coastguard Worker 	  break;
3441*5e7646d2SAndroid Build Coastguard Worker 
3442*5e7646d2SAndroid Build Coastguard Worker       if (job)
3443*5e7646d2SAndroid Build Coastguard Worker 	jobid = job->id;
3444*5e7646d2SAndroid Build Coastguard Worker       else
3445*5e7646d2SAndroid Build Coastguard Worker       {
3446*5e7646d2SAndroid Build Coastguard Worker        /*
3447*5e7646d2SAndroid Build Coastguard Worker         * No, try stopped jobs...
3448*5e7646d2SAndroid Build Coastguard Worker 	*/
3449*5e7646d2SAndroid Build Coastguard Worker 
3450*5e7646d2SAndroid Build Coastguard Worker 	for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
3451*5e7646d2SAndroid Build Coastguard Worker 	     job;
3452*5e7646d2SAndroid Build Coastguard Worker 	     job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
3453*5e7646d2SAndroid Build Coastguard Worker 	  if (job->state_value == IPP_JOB_STOPPED &&
3454*5e7646d2SAndroid Build Coastguard Worker 	      !_cups_strcasecmp(job->dest, printer->name))
3455*5e7646d2SAndroid Build Coastguard Worker 	    break;
3456*5e7646d2SAndroid Build Coastguard Worker 
3457*5e7646d2SAndroid Build Coastguard Worker 	if (job)
3458*5e7646d2SAndroid Build Coastguard Worker 	  jobid = job->id;
3459*5e7646d2SAndroid Build Coastguard Worker 	else
3460*5e7646d2SAndroid Build Coastguard Worker 	{
3461*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s."),
3462*5e7646d2SAndroid Build Coastguard Worker 			  printer->name);
3463*5e7646d2SAndroid Build Coastguard Worker 	  return;
3464*5e7646d2SAndroid Build Coastguard Worker 	}
3465*5e7646d2SAndroid Build Coastguard Worker       }
3466*5e7646d2SAndroid Build Coastguard Worker     }
3467*5e7646d2SAndroid Build Coastguard Worker   }
3468*5e7646d2SAndroid Build Coastguard Worker   else
3469*5e7646d2SAndroid Build Coastguard Worker   {
3470*5e7646d2SAndroid Build Coastguard Worker    /*
3471*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
3472*5e7646d2SAndroid Build Coastguard Worker     */
3473*5e7646d2SAndroid Build Coastguard Worker 
3474*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
3475*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
3476*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
3477*5e7646d2SAndroid Build Coastguard Worker 
3478*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
3479*5e7646d2SAndroid Build Coastguard Worker     {
3480*5e7646d2SAndroid Build Coastguard Worker      /*
3481*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
3482*5e7646d2SAndroid Build Coastguard Worker       */
3483*5e7646d2SAndroid Build Coastguard Worker 
3484*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
3485*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
3486*5e7646d2SAndroid Build Coastguard Worker       return;
3487*5e7646d2SAndroid Build Coastguard Worker     }
3488*5e7646d2SAndroid Build Coastguard Worker 
3489*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
3490*5e7646d2SAndroid Build Coastguard Worker   }
3491*5e7646d2SAndroid Build Coastguard Worker 
3492*5e7646d2SAndroid Build Coastguard Worker  /*
3493*5e7646d2SAndroid Build Coastguard Worker   * Look for the "purge-job" attribute...
3494*5e7646d2SAndroid Build Coastguard Worker   */
3495*5e7646d2SAndroid Build Coastguard Worker 
3496*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "purge-job",
3497*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_BOOLEAN)) != NULL)
3498*5e7646d2SAndroid Build Coastguard Worker     purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
3499*5e7646d2SAndroid Build Coastguard Worker   else
3500*5e7646d2SAndroid Build Coastguard Worker     purge = CUPSD_JOB_DEFAULT;
3501*5e7646d2SAndroid Build Coastguard Worker 
3502*5e7646d2SAndroid Build Coastguard Worker  /*
3503*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
3504*5e7646d2SAndroid Build Coastguard Worker   */
3505*5e7646d2SAndroid Build Coastguard Worker 
3506*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
3507*5e7646d2SAndroid Build Coastguard Worker   {
3508*5e7646d2SAndroid Build Coastguard Worker    /*
3509*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
3510*5e7646d2SAndroid Build Coastguard Worker     */
3511*5e7646d2SAndroid Build Coastguard Worker 
3512*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
3513*5e7646d2SAndroid Build Coastguard Worker     return;
3514*5e7646d2SAndroid Build Coastguard Worker   }
3515*5e7646d2SAndroid Build Coastguard Worker 
3516*5e7646d2SAndroid Build Coastguard Worker  /*
3517*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
3518*5e7646d2SAndroid Build Coastguard Worker   */
3519*5e7646d2SAndroid Build Coastguard Worker 
3520*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
3521*5e7646d2SAndroid Build Coastguard Worker   {
3522*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3523*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
3524*5e7646d2SAndroid Build Coastguard Worker     return;
3525*5e7646d2SAndroid Build Coastguard Worker   }
3526*5e7646d2SAndroid Build Coastguard Worker 
3527*5e7646d2SAndroid Build Coastguard Worker  /*
3528*5e7646d2SAndroid Build Coastguard Worker   * See if the job is already completed, canceled, or aborted; if so,
3529*5e7646d2SAndroid Build Coastguard Worker   * we can't cancel...
3530*5e7646d2SAndroid Build Coastguard Worker   */
3531*5e7646d2SAndroid Build Coastguard Worker 
3532*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value >= IPP_JOB_CANCELED && purge != CUPSD_JOB_PURGE)
3533*5e7646d2SAndroid Build Coastguard Worker   {
3534*5e7646d2SAndroid Build Coastguard Worker     switch (job->state_value)
3535*5e7646d2SAndroid Build Coastguard Worker     {
3536*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_CANCELED :
3537*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_NOT_POSSIBLE,
3538*5e7646d2SAndroid Build Coastguard Worker                 	  _("Job #%d is already canceled - can\'t cancel."),
3539*5e7646d2SAndroid Build Coastguard Worker 			  jobid);
3540*5e7646d2SAndroid Build Coastguard Worker           break;
3541*5e7646d2SAndroid Build Coastguard Worker 
3542*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_ABORTED :
3543*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_NOT_POSSIBLE,
3544*5e7646d2SAndroid Build Coastguard Worker                 	  _("Job #%d is already aborted - can\'t cancel."),
3545*5e7646d2SAndroid Build Coastguard Worker 			  jobid);
3546*5e7646d2SAndroid Build Coastguard Worker           break;
3547*5e7646d2SAndroid Build Coastguard Worker 
3548*5e7646d2SAndroid Build Coastguard Worker       default :
3549*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_NOT_POSSIBLE,
3550*5e7646d2SAndroid Build Coastguard Worker                 	  _("Job #%d is already completed - can\'t cancel."),
3551*5e7646d2SAndroid Build Coastguard Worker 			  jobid);
3552*5e7646d2SAndroid Build Coastguard Worker           break;
3553*5e7646d2SAndroid Build Coastguard Worker     }
3554*5e7646d2SAndroid Build Coastguard Worker 
3555*5e7646d2SAndroid Build Coastguard Worker     return;
3556*5e7646d2SAndroid Build Coastguard Worker   }
3557*5e7646d2SAndroid Build Coastguard Worker 
3558*5e7646d2SAndroid Build Coastguard Worker  /*
3559*5e7646d2SAndroid Build Coastguard Worker   * Cancel the job and return...
3560*5e7646d2SAndroid Build Coastguard Worker   */
3561*5e7646d2SAndroid Build Coastguard Worker 
3562*5e7646d2SAndroid Build Coastguard Worker   cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
3563*5e7646d2SAndroid Build Coastguard Worker                    purge == CUPSD_JOB_PURGE ? "Job purged by \"%s\"" :
3564*5e7646d2SAndroid Build Coastguard Worker 		                              "Job canceled by \"%s\"",
3565*5e7646d2SAndroid Build Coastguard Worker 		   username);
3566*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
3567*5e7646d2SAndroid Build Coastguard Worker 
3568*5e7646d2SAndroid Build Coastguard Worker   if (purge == CUPSD_JOB_PURGE)
3569*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Purged by \"%s\".", jobid,
3570*5e7646d2SAndroid Build Coastguard Worker 		    username);
3571*5e7646d2SAndroid Build Coastguard Worker   else
3572*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Canceled by \"%s\".", jobid,
3573*5e7646d2SAndroid Build Coastguard Worker 		    username);
3574*5e7646d2SAndroid Build Coastguard Worker 
3575*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
3576*5e7646d2SAndroid Build Coastguard Worker }
3577*5e7646d2SAndroid Build Coastguard Worker 
3578*5e7646d2SAndroid Build Coastguard Worker 
3579*5e7646d2SAndroid Build Coastguard Worker /*
3580*5e7646d2SAndroid Build Coastguard Worker  * 'cancel_subscription()' - Cancel a subscription.
3581*5e7646d2SAndroid Build Coastguard Worker  */
3582*5e7646d2SAndroid Build Coastguard Worker 
3583*5e7646d2SAndroid Build Coastguard Worker static void
cancel_subscription(cupsd_client_t * con,int sub_id)3584*5e7646d2SAndroid Build Coastguard Worker cancel_subscription(
3585*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
3586*5e7646d2SAndroid Build Coastguard Worker     int            sub_id)		/* I - Subscription ID */
3587*5e7646d2SAndroid Build Coastguard Worker {
3588*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
3589*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription */
3590*5e7646d2SAndroid Build Coastguard Worker 
3591*5e7646d2SAndroid Build Coastguard Worker 
3592*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
3593*5e7646d2SAndroid Build Coastguard Worker                   "cancel_subscription(con=%p[%d], sub_id=%d)",
3594*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, sub_id);
3595*5e7646d2SAndroid Build Coastguard Worker 
3596*5e7646d2SAndroid Build Coastguard Worker  /*
3597*5e7646d2SAndroid Build Coastguard Worker   * Is the subscription ID valid?
3598*5e7646d2SAndroid Build Coastguard Worker   */
3599*5e7646d2SAndroid Build Coastguard Worker 
3600*5e7646d2SAndroid Build Coastguard Worker   if ((sub = cupsdFindSubscription(sub_id)) == NULL)
3601*5e7646d2SAndroid Build Coastguard Worker   {
3602*5e7646d2SAndroid Build Coastguard Worker    /*
3603*5e7646d2SAndroid Build Coastguard Worker     * Bad subscription ID...
3604*5e7646d2SAndroid Build Coastguard Worker     */
3605*5e7646d2SAndroid Build Coastguard Worker 
3606*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
3607*5e7646d2SAndroid Build Coastguard Worker                     _("Subscription #%d does not exist."), sub_id);
3608*5e7646d2SAndroid Build Coastguard Worker     return;
3609*5e7646d2SAndroid Build Coastguard Worker   }
3610*5e7646d2SAndroid Build Coastguard Worker 
3611*5e7646d2SAndroid Build Coastguard Worker  /*
3612*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
3613*5e7646d2SAndroid Build Coastguard Worker   */
3614*5e7646d2SAndroid Build Coastguard Worker 
3615*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
3616*5e7646d2SAndroid Build Coastguard Worker                                              DefaultPolicyPtr,
3617*5e7646d2SAndroid Build Coastguard Worker                                  con, sub->owner)) != HTTP_OK)
3618*5e7646d2SAndroid Build Coastguard Worker   {
3619*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, sub->dest);
3620*5e7646d2SAndroid Build Coastguard Worker     return;
3621*5e7646d2SAndroid Build Coastguard Worker   }
3622*5e7646d2SAndroid Build Coastguard Worker 
3623*5e7646d2SAndroid Build Coastguard Worker  /*
3624*5e7646d2SAndroid Build Coastguard Worker   * Cancel the subscription...
3625*5e7646d2SAndroid Build Coastguard Worker   */
3626*5e7646d2SAndroid Build Coastguard Worker 
3627*5e7646d2SAndroid Build Coastguard Worker   cupsdDeleteSubscription(sub, 1);
3628*5e7646d2SAndroid Build Coastguard Worker 
3629*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
3630*5e7646d2SAndroid Build Coastguard Worker }
3631*5e7646d2SAndroid Build Coastguard Worker 
3632*5e7646d2SAndroid Build Coastguard Worker 
3633*5e7646d2SAndroid Build Coastguard Worker /*
3634*5e7646d2SAndroid Build Coastguard Worker  * 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI.
3635*5e7646d2SAndroid Build Coastguard Worker  */
3636*5e7646d2SAndroid Build Coastguard Worker 
3637*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 if OK, 0 if not */
check_rss_recipient(const char * recipient)3638*5e7646d2SAndroid Build Coastguard Worker check_rss_recipient(
3639*5e7646d2SAndroid Build Coastguard Worker     const char *recipient)		/* I - Recipient URI */
3640*5e7646d2SAndroid Build Coastguard Worker {
3641*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Current subscription */
3642*5e7646d2SAndroid Build Coastguard Worker 
3643*5e7646d2SAndroid Build Coastguard Worker 
3644*5e7646d2SAndroid Build Coastguard Worker   for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
3645*5e7646d2SAndroid Build Coastguard Worker        sub;
3646*5e7646d2SAndroid Build Coastguard Worker        sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
3647*5e7646d2SAndroid Build Coastguard Worker     if (sub->recipient)
3648*5e7646d2SAndroid Build Coastguard Worker     {
3649*5e7646d2SAndroid Build Coastguard Worker      /*
3650*5e7646d2SAndroid Build Coastguard Worker       * Compare the URIs up to the first ?...
3651*5e7646d2SAndroid Build Coastguard Worker       */
3652*5e7646d2SAndroid Build Coastguard Worker 
3653*5e7646d2SAndroid Build Coastguard Worker       const char *r1, *r2;
3654*5e7646d2SAndroid Build Coastguard Worker 
3655*5e7646d2SAndroid Build Coastguard Worker       for (r1 = recipient, r2 = sub->recipient;
3656*5e7646d2SAndroid Build Coastguard Worker            *r1 == *r2 && *r1 && *r1 != '?' && *r2 && *r2 != '?';
3657*5e7646d2SAndroid Build Coastguard Worker 	   r1 ++, r2 ++);
3658*5e7646d2SAndroid Build Coastguard Worker 
3659*5e7646d2SAndroid Build Coastguard Worker       if (*r1 == *r2)
3660*5e7646d2SAndroid Build Coastguard Worker         return (0);
3661*5e7646d2SAndroid Build Coastguard Worker     }
3662*5e7646d2SAndroid Build Coastguard Worker 
3663*5e7646d2SAndroid Build Coastguard Worker   return (1);
3664*5e7646d2SAndroid Build Coastguard Worker }
3665*5e7646d2SAndroid Build Coastguard Worker 
3666*5e7646d2SAndroid Build Coastguard Worker 
3667*5e7646d2SAndroid Build Coastguard Worker /*
3668*5e7646d2SAndroid Build Coastguard Worker  * 'check_quotas()' - Check quotas for a printer and user.
3669*5e7646d2SAndroid Build Coastguard Worker  */
3670*5e7646d2SAndroid Build Coastguard Worker 
3671*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 if OK, 0 if forbidden,
3672*5e7646d2SAndroid Build Coastguard Worker 					       -1 if limit reached */
check_quotas(cupsd_client_t * con,cupsd_printer_t * p)3673*5e7646d2SAndroid Build Coastguard Worker check_quotas(cupsd_client_t  *con,	/* I - Client connection */
3674*5e7646d2SAndroid Build Coastguard Worker              cupsd_printer_t *p)	/* I - Printer or class */
3675*5e7646d2SAndroid Build Coastguard Worker {
3676*5e7646d2SAndroid Build Coastguard Worker   char		username[33],		/* Username */
3677*5e7646d2SAndroid Build Coastguard Worker 		*name;			/* Current user name */
3678*5e7646d2SAndroid Build Coastguard Worker   cupsd_quota_t	*q;			/* Quota data */
3679*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_MBR_UID_TO_UUID
3680*5e7646d2SAndroid Build Coastguard Worker  /*
3681*5e7646d2SAndroid Build Coastguard Worker   * Use Apple membership APIs which require that all names represent
3682*5e7646d2SAndroid Build Coastguard Worker   * valid user account or group records accessible by the server.
3683*5e7646d2SAndroid Build Coastguard Worker   */
3684*5e7646d2SAndroid Build Coastguard Worker 
3685*5e7646d2SAndroid Build Coastguard Worker   uuid_t	usr_uuid;		/* UUID for job requesting user  */
3686*5e7646d2SAndroid Build Coastguard Worker   uuid_t	usr2_uuid;		/* UUID for ACL user name entry  */
3687*5e7646d2SAndroid Build Coastguard Worker   uuid_t	grp_uuid;		/* UUID for ACL group name entry */
3688*5e7646d2SAndroid Build Coastguard Worker   int		mbr_err;		/* Error from membership function */
3689*5e7646d2SAndroid Build Coastguard Worker   int		is_member;		/* Is this user a member? */
3690*5e7646d2SAndroid Build Coastguard Worker #else
3691*5e7646d2SAndroid Build Coastguard Worker  /*
3692*5e7646d2SAndroid Build Coastguard Worker   * Use standard POSIX APIs for checking users and groups...
3693*5e7646d2SAndroid Build Coastguard Worker   */
3694*5e7646d2SAndroid Build Coastguard Worker 
3695*5e7646d2SAndroid Build Coastguard Worker   struct passwd	*pw;			/* User password data */
3696*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_MBR_UID_TO_UUID */
3697*5e7646d2SAndroid Build Coastguard Worker 
3698*5e7646d2SAndroid Build Coastguard Worker 
3699*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])",
3700*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, p, p->name);
3701*5e7646d2SAndroid Build Coastguard Worker 
3702*5e7646d2SAndroid Build Coastguard Worker  /*
3703*5e7646d2SAndroid Build Coastguard Worker   * Figure out who is printing...
3704*5e7646d2SAndroid Build Coastguard Worker   */
3705*5e7646d2SAndroid Build Coastguard Worker 
3706*5e7646d2SAndroid Build Coastguard Worker   strlcpy(username, get_username(con), sizeof(username));
3707*5e7646d2SAndroid Build Coastguard Worker 
3708*5e7646d2SAndroid Build Coastguard Worker   if ((name = strchr(username, '@')) != NULL)
3709*5e7646d2SAndroid Build Coastguard Worker     *name = '\0';			/* Strip @REALM */
3710*5e7646d2SAndroid Build Coastguard Worker 
3711*5e7646d2SAndroid Build Coastguard Worker  /*
3712*5e7646d2SAndroid Build Coastguard Worker   * Check global active job limits for printers and users...
3713*5e7646d2SAndroid Build Coastguard Worker   */
3714*5e7646d2SAndroid Build Coastguard Worker 
3715*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobsPerPrinter)
3716*5e7646d2SAndroid Build Coastguard Worker   {
3717*5e7646d2SAndroid Build Coastguard Worker    /*
3718*5e7646d2SAndroid Build Coastguard Worker     * Check if there are too many pending jobs on this printer...
3719*5e7646d2SAndroid Build Coastguard Worker     */
3720*5e7646d2SAndroid Build Coastguard Worker 
3721*5e7646d2SAndroid Build Coastguard Worker     if (cupsdGetPrinterJobCount(p->name) >= MaxJobsPerPrinter)
3722*5e7646d2SAndroid Build Coastguard Worker     {
3723*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for printer \"%s\"...",
3724*5e7646d2SAndroid Build Coastguard Worker                       p->name);
3725*5e7646d2SAndroid Build Coastguard Worker       return (-1);
3726*5e7646d2SAndroid Build Coastguard Worker     }
3727*5e7646d2SAndroid Build Coastguard Worker   }
3728*5e7646d2SAndroid Build Coastguard Worker 
3729*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobsPerUser)
3730*5e7646d2SAndroid Build Coastguard Worker   {
3731*5e7646d2SAndroid Build Coastguard Worker    /*
3732*5e7646d2SAndroid Build Coastguard Worker     * Check if there are too many pending jobs for this user...
3733*5e7646d2SAndroid Build Coastguard Worker     */
3734*5e7646d2SAndroid Build Coastguard Worker 
3735*5e7646d2SAndroid Build Coastguard Worker     if (cupsdGetUserJobCount(username) >= MaxJobsPerUser)
3736*5e7646d2SAndroid Build Coastguard Worker     {
3737*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for user \"%s\"...",
3738*5e7646d2SAndroid Build Coastguard Worker                       username);
3739*5e7646d2SAndroid Build Coastguard Worker       return (-1);
3740*5e7646d2SAndroid Build Coastguard Worker     }
3741*5e7646d2SAndroid Build Coastguard Worker   }
3742*5e7646d2SAndroid Build Coastguard Worker 
3743*5e7646d2SAndroid Build Coastguard Worker  /*
3744*5e7646d2SAndroid Build Coastguard Worker   * Check against users...
3745*5e7646d2SAndroid Build Coastguard Worker   */
3746*5e7646d2SAndroid Build Coastguard Worker 
3747*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0)
3748*5e7646d2SAndroid Build Coastguard Worker     return (1);
3749*5e7646d2SAndroid Build Coastguard Worker 
3750*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(p->users))
3751*5e7646d2SAndroid Build Coastguard Worker   {
3752*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_MBR_UID_TO_UUID
3753*5e7646d2SAndroid Build Coastguard Worker    /*
3754*5e7646d2SAndroid Build Coastguard Worker     * Get UUID for job requesting user...
3755*5e7646d2SAndroid Build Coastguard Worker     */
3756*5e7646d2SAndroid Build Coastguard Worker 
3757*5e7646d2SAndroid Build Coastguard Worker     if (mbr_user_name_to_uuid((char *)username, usr_uuid))
3758*5e7646d2SAndroid Build Coastguard Worker     {
3759*5e7646d2SAndroid Build Coastguard Worker      /*
3760*5e7646d2SAndroid Build Coastguard Worker       * Unknown user...
3761*5e7646d2SAndroid Build Coastguard Worker       */
3762*5e7646d2SAndroid Build Coastguard Worker 
3763*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
3764*5e7646d2SAndroid Build Coastguard Worker 		      "check_quotas: UUID lookup failed for user \"%s\"",
3765*5e7646d2SAndroid Build Coastguard Worker 		      username);
3766*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO,
3767*5e7646d2SAndroid Build Coastguard Worker 		      "Denying user \"%s\" access to printer \"%s\" "
3768*5e7646d2SAndroid Build Coastguard Worker 		      "(unknown user)...",
3769*5e7646d2SAndroid Build Coastguard Worker 		      username, p->name);
3770*5e7646d2SAndroid Build Coastguard Worker       return (0);
3771*5e7646d2SAndroid Build Coastguard Worker     }
3772*5e7646d2SAndroid Build Coastguard Worker #else
3773*5e7646d2SAndroid Build Coastguard Worker    /*
3774*5e7646d2SAndroid Build Coastguard Worker     * Get UID and GID of requesting user...
3775*5e7646d2SAndroid Build Coastguard Worker     */
3776*5e7646d2SAndroid Build Coastguard Worker 
3777*5e7646d2SAndroid Build Coastguard Worker     pw = getpwnam(username);
3778*5e7646d2SAndroid Build Coastguard Worker     endpwent();
3779*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_MBR_UID_TO_UUID */
3780*5e7646d2SAndroid Build Coastguard Worker 
3781*5e7646d2SAndroid Build Coastguard Worker     for (name = (char *)cupsArrayFirst(p->users);
3782*5e7646d2SAndroid Build Coastguard Worker          name;
3783*5e7646d2SAndroid Build Coastguard Worker 	 name = (char *)cupsArrayNext(p->users))
3784*5e7646d2SAndroid Build Coastguard Worker       if (name[0] == '@')
3785*5e7646d2SAndroid Build Coastguard Worker       {
3786*5e7646d2SAndroid Build Coastguard Worker        /*
3787*5e7646d2SAndroid Build Coastguard Worker         * Check group membership...
3788*5e7646d2SAndroid Build Coastguard Worker 	*/
3789*5e7646d2SAndroid Build Coastguard Worker 
3790*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_MBR_UID_TO_UUID
3791*5e7646d2SAndroid Build Coastguard Worker         if (name[1] == '#')
3792*5e7646d2SAndroid Build Coastguard Worker 	{
3793*5e7646d2SAndroid Build Coastguard Worker 	  if (uuid_parse(name + 2, grp_uuid))
3794*5e7646d2SAndroid Build Coastguard Worker 	    uuid_clear(grp_uuid);
3795*5e7646d2SAndroid Build Coastguard Worker 	}
3796*5e7646d2SAndroid Build Coastguard Worker 	else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0)
3797*5e7646d2SAndroid Build Coastguard Worker 	{
3798*5e7646d2SAndroid Build Coastguard Worker 	 /*
3799*5e7646d2SAndroid Build Coastguard Worker 	  * Invalid ACL entries are ignored for matching; just record a
3800*5e7646d2SAndroid Build Coastguard Worker 	  * warning in the log...
3801*5e7646d2SAndroid Build Coastguard Worker 	  */
3802*5e7646d2SAndroid Build Coastguard Worker 
3803*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_DEBUG,
3804*5e7646d2SAndroid Build Coastguard Worker 	                  "check_quotas: UUID lookup failed for ACL entry "
3805*5e7646d2SAndroid Build Coastguard Worker 			  "\"%s\" (err=%d)", name, mbr_err);
3806*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_WARN,
3807*5e7646d2SAndroid Build Coastguard Worker 	                  "Access control entry \"%s\" not a valid group name; "
3808*5e7646d2SAndroid Build Coastguard Worker 			  "entry ignored", name);
3809*5e7646d2SAndroid Build Coastguard Worker 	}
3810*5e7646d2SAndroid Build Coastguard Worker 
3811*5e7646d2SAndroid Build Coastguard Worker 	if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid,
3812*5e7646d2SAndroid Build Coastguard Worker 					    &is_member)) != 0)
3813*5e7646d2SAndroid Build Coastguard Worker 	{
3814*5e7646d2SAndroid Build Coastguard Worker 	 /*
3815*5e7646d2SAndroid Build Coastguard Worker 	  * At this point, there should be no errors, but check anyways...
3816*5e7646d2SAndroid Build Coastguard Worker 	  */
3817*5e7646d2SAndroid Build Coastguard Worker 
3818*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_DEBUG,
3819*5e7646d2SAndroid Build Coastguard Worker 			  "check_quotas: group \"%s\" membership check "
3820*5e7646d2SAndroid Build Coastguard Worker 			  "failed (err=%d)", name + 1, mbr_err);
3821*5e7646d2SAndroid Build Coastguard Worker 	  is_member = 0;
3822*5e7646d2SAndroid Build Coastguard Worker 	}
3823*5e7646d2SAndroid Build Coastguard Worker 
3824*5e7646d2SAndroid Build Coastguard Worker        /*
3825*5e7646d2SAndroid Build Coastguard Worker 	* Stop if we found a match...
3826*5e7646d2SAndroid Build Coastguard Worker 	*/
3827*5e7646d2SAndroid Build Coastguard Worker 
3828*5e7646d2SAndroid Build Coastguard Worker 	if (is_member)
3829*5e7646d2SAndroid Build Coastguard Worker 	  break;
3830*5e7646d2SAndroid Build Coastguard Worker 
3831*5e7646d2SAndroid Build Coastguard Worker #else
3832*5e7646d2SAndroid Build Coastguard Worker         if (cupsdCheckGroup(username, pw, name + 1))
3833*5e7646d2SAndroid Build Coastguard Worker 	  break;
3834*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_MBR_UID_TO_UUID */
3835*5e7646d2SAndroid Build Coastguard Worker       }
3836*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_MBR_UID_TO_UUID
3837*5e7646d2SAndroid Build Coastguard Worker       else
3838*5e7646d2SAndroid Build Coastguard Worker       {
3839*5e7646d2SAndroid Build Coastguard Worker         if (name[0] == '#')
3840*5e7646d2SAndroid Build Coastguard Worker 	{
3841*5e7646d2SAndroid Build Coastguard Worker 	  if (uuid_parse(name + 1, usr2_uuid))
3842*5e7646d2SAndroid Build Coastguard Worker 	    uuid_clear(usr2_uuid);
3843*5e7646d2SAndroid Build Coastguard Worker         }
3844*5e7646d2SAndroid Build Coastguard Worker         else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0)
3845*5e7646d2SAndroid Build Coastguard Worker     	{
3846*5e7646d2SAndroid Build Coastguard Worker 	 /*
3847*5e7646d2SAndroid Build Coastguard Worker 	  * Invalid ACL entries are ignored for matching; just record a
3848*5e7646d2SAndroid Build Coastguard Worker 	  * warning in the log...
3849*5e7646d2SAndroid Build Coastguard Worker 	  */
3850*5e7646d2SAndroid Build Coastguard Worker 
3851*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
3852*5e7646d2SAndroid Build Coastguard Worker 	                  "check_quotas: UUID lookup failed for ACL entry "
3853*5e7646d2SAndroid Build Coastguard Worker 			  "\"%s\" (err=%d)", name, mbr_err);
3854*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_WARN,
3855*5e7646d2SAndroid Build Coastguard Worker 	                  "Access control entry \"%s\" not a valid user name; "
3856*5e7646d2SAndroid Build Coastguard Worker 			  "entry ignored", name);
3857*5e7646d2SAndroid Build Coastguard Worker 	}
3858*5e7646d2SAndroid Build Coastguard Worker 
3859*5e7646d2SAndroid Build Coastguard Worker 	if (!uuid_compare(usr_uuid, usr2_uuid))
3860*5e7646d2SAndroid Build Coastguard Worker 	  break;
3861*5e7646d2SAndroid Build Coastguard Worker       }
3862*5e7646d2SAndroid Build Coastguard Worker #else
3863*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(username, name))
3864*5e7646d2SAndroid Build Coastguard Worker 	break;
3865*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_MBR_UID_TO_UUID */
3866*5e7646d2SAndroid Build Coastguard Worker 
3867*5e7646d2SAndroid Build Coastguard Worker     if ((name != NULL) == p->deny_users)
3868*5e7646d2SAndroid Build Coastguard Worker     {
3869*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO,
3870*5e7646d2SAndroid Build Coastguard Worker                       "Denying user \"%s\" access to printer \"%s\"...",
3871*5e7646d2SAndroid Build Coastguard Worker         	      username, p->name);
3872*5e7646d2SAndroid Build Coastguard Worker       return (0);
3873*5e7646d2SAndroid Build Coastguard Worker     }
3874*5e7646d2SAndroid Build Coastguard Worker   }
3875*5e7646d2SAndroid Build Coastguard Worker 
3876*5e7646d2SAndroid Build Coastguard Worker  /*
3877*5e7646d2SAndroid Build Coastguard Worker   * Check quotas...
3878*5e7646d2SAndroid Build Coastguard Worker   */
3879*5e7646d2SAndroid Build Coastguard Worker 
3880*5e7646d2SAndroid Build Coastguard Worker   if (p->k_limit || p->page_limit)
3881*5e7646d2SAndroid Build Coastguard Worker   {
3882*5e7646d2SAndroid Build Coastguard Worker     if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL)
3883*5e7646d2SAndroid Build Coastguard Worker     {
3884*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR,
3885*5e7646d2SAndroid Build Coastguard Worker                       "Unable to allocate quota data for user \"%s\"",
3886*5e7646d2SAndroid Build Coastguard Worker                       username);
3887*5e7646d2SAndroid Build Coastguard Worker       return (-1);
3888*5e7646d2SAndroid Build Coastguard Worker     }
3889*5e7646d2SAndroid Build Coastguard Worker 
3890*5e7646d2SAndroid Build Coastguard Worker     if ((q->k_count >= p->k_limit && p->k_limit) ||
3891*5e7646d2SAndroid Build Coastguard Worker         (q->page_count >= p->page_limit && p->page_limit))
3892*5e7646d2SAndroid Build Coastguard Worker     {
3893*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "User \"%s\" is over the quota limit...",
3894*5e7646d2SAndroid Build Coastguard Worker                       username);
3895*5e7646d2SAndroid Build Coastguard Worker       return (-1);
3896*5e7646d2SAndroid Build Coastguard Worker     }
3897*5e7646d2SAndroid Build Coastguard Worker   }
3898*5e7646d2SAndroid Build Coastguard Worker 
3899*5e7646d2SAndroid Build Coastguard Worker  /*
3900*5e7646d2SAndroid Build Coastguard Worker   * If we have gotten this far, we're done!
3901*5e7646d2SAndroid Build Coastguard Worker   */
3902*5e7646d2SAndroid Build Coastguard Worker 
3903*5e7646d2SAndroid Build Coastguard Worker   return (1);
3904*5e7646d2SAndroid Build Coastguard Worker }
3905*5e7646d2SAndroid Build Coastguard Worker 
3906*5e7646d2SAndroid Build Coastguard Worker 
3907*5e7646d2SAndroid Build Coastguard Worker /*
3908*5e7646d2SAndroid Build Coastguard Worker  * 'close_job()' - Close a multi-file job.
3909*5e7646d2SAndroid Build Coastguard Worker  */
3910*5e7646d2SAndroid Build Coastguard Worker 
3911*5e7646d2SAndroid Build Coastguard Worker static void
close_job(cupsd_client_t * con,ipp_attribute_t * uri)3912*5e7646d2SAndroid Build Coastguard Worker close_job(cupsd_client_t  *con,		/* I - Client connection */
3913*5e7646d2SAndroid Build Coastguard Worker           ipp_attribute_t *uri)		/* I - Printer URI */
3914*5e7646d2SAndroid Build Coastguard Worker {
3915*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Job */
3916*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Attribute */
3917*5e7646d2SAndroid Build Coastguard Worker   char			job_uri[HTTP_MAX_URI],
3918*5e7646d2SAndroid Build Coastguard Worker 					/* Job URI */
3919*5e7646d2SAndroid Build Coastguard Worker 			username[256];	/* User name */
3920*5e7646d2SAndroid Build Coastguard Worker 
3921*5e7646d2SAndroid Build Coastguard Worker 
3922*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con,
3923*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
3924*5e7646d2SAndroid Build Coastguard Worker 
3925*5e7646d2SAndroid Build Coastguard Worker  /*
3926*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
3927*5e7646d2SAndroid Build Coastguard Worker   */
3928*5e7646d2SAndroid Build Coastguard Worker 
3929*5e7646d2SAndroid Build Coastguard Worker   if (strcmp(uri->name, "printer-uri"))
3930*5e7646d2SAndroid Build Coastguard Worker   {
3931*5e7646d2SAndroid Build Coastguard Worker    /*
3932*5e7646d2SAndroid Build Coastguard Worker     * job-uri is not supported by Close-Job!
3933*5e7646d2SAndroid Build Coastguard Worker     */
3934*5e7646d2SAndroid Build Coastguard Worker 
3935*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
3936*5e7646d2SAndroid Build Coastguard Worker 		    _("Close-Job doesn't support the job-uri attribute."));
3937*5e7646d2SAndroid Build Coastguard Worker     return;
3938*5e7646d2SAndroid Build Coastguard Worker   }
3939*5e7646d2SAndroid Build Coastguard Worker 
3940*5e7646d2SAndroid Build Coastguard Worker  /*
3941*5e7646d2SAndroid Build Coastguard Worker   * Got a printer URI; see if we also have a job-id attribute...
3942*5e7646d2SAndroid Build Coastguard Worker   */
3943*5e7646d2SAndroid Build Coastguard Worker 
3944*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-id",
3945*5e7646d2SAndroid Build Coastguard Worker 			       IPP_TAG_INTEGER)) == NULL)
3946*5e7646d2SAndroid Build Coastguard Worker   {
3947*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
3948*5e7646d2SAndroid Build Coastguard Worker 		    _("Got a printer-uri attribute but no job-id."));
3949*5e7646d2SAndroid Build Coastguard Worker     return;
3950*5e7646d2SAndroid Build Coastguard Worker   }
3951*5e7646d2SAndroid Build Coastguard Worker 
3952*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
3953*5e7646d2SAndroid Build Coastguard Worker   {
3954*5e7646d2SAndroid Build Coastguard Worker    /*
3955*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
3956*5e7646d2SAndroid Build Coastguard Worker     */
3957*5e7646d2SAndroid Build Coastguard Worker 
3958*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
3959*5e7646d2SAndroid Build Coastguard Worker                     attr->values[0].integer);
3960*5e7646d2SAndroid Build Coastguard Worker     return;
3961*5e7646d2SAndroid Build Coastguard Worker   }
3962*5e7646d2SAndroid Build Coastguard Worker 
3963*5e7646d2SAndroid Build Coastguard Worker  /*
3964*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
3965*5e7646d2SAndroid Build Coastguard Worker   */
3966*5e7646d2SAndroid Build Coastguard Worker 
3967*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
3968*5e7646d2SAndroid Build Coastguard Worker   {
3969*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
3970*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
3971*5e7646d2SAndroid Build Coastguard Worker     return;
3972*5e7646d2SAndroid Build Coastguard Worker   }
3973*5e7646d2SAndroid Build Coastguard Worker 
3974*5e7646d2SAndroid Build Coastguard Worker  /*
3975*5e7646d2SAndroid Build Coastguard Worker   * Add any ending sheet...
3976*5e7646d2SAndroid Build Coastguard Worker   */
3977*5e7646d2SAndroid Build Coastguard Worker 
3978*5e7646d2SAndroid Build Coastguard Worker   if (cupsdTimeoutJob(job))
3979*5e7646d2SAndroid Build Coastguard Worker     return;
3980*5e7646d2SAndroid Build Coastguard Worker 
3981*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value == IPP_JOB_STOPPED)
3982*5e7646d2SAndroid Build Coastguard Worker   {
3983*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_PENDING;
3984*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_PENDING;
3985*5e7646d2SAndroid Build Coastguard Worker   }
3986*5e7646d2SAndroid Build Coastguard Worker   else if (job->state_value == IPP_JOB_HELD)
3987*5e7646d2SAndroid Build Coastguard Worker   {
3988*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
3989*5e7646d2SAndroid Build Coastguard Worker 				 IPP_TAG_KEYWORD)) == NULL)
3990*5e7646d2SAndroid Build Coastguard Worker       attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
3991*5e7646d2SAndroid Build Coastguard Worker 
3992*5e7646d2SAndroid Build Coastguard Worker     if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
3993*5e7646d2SAndroid Build Coastguard Worker     {
3994*5e7646d2SAndroid Build Coastguard Worker       job->state->values[0].integer = IPP_JOB_PENDING;
3995*5e7646d2SAndroid Build Coastguard Worker       job->state_value              = IPP_JOB_PENDING;
3996*5e7646d2SAndroid Build Coastguard Worker     }
3997*5e7646d2SAndroid Build Coastguard Worker   }
3998*5e7646d2SAndroid Build Coastguard Worker 
3999*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
4000*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
4001*5e7646d2SAndroid Build Coastguard Worker 
4002*5e7646d2SAndroid Build Coastguard Worker  /*
4003*5e7646d2SAndroid Build Coastguard Worker   * Fill in the response info...
4004*5e7646d2SAndroid Build Coastguard Worker   */
4005*5e7646d2SAndroid Build Coastguard Worker 
4006*5e7646d2SAndroid Build Coastguard Worker   httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4007*5e7646d2SAndroid Build Coastguard Worker                    con->clientname, con->clientport, "/jobs/%d", job->id);
4008*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
4009*5e7646d2SAndroid Build Coastguard Worker                job_uri);
4010*5e7646d2SAndroid Build Coastguard Worker 
4011*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
4012*5e7646d2SAndroid Build Coastguard Worker 
4013*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
4014*5e7646d2SAndroid Build Coastguard Worker 
4015*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
4016*5e7646d2SAndroid Build Coastguard Worker 
4017*5e7646d2SAndroid Build Coastguard Worker  /*
4018*5e7646d2SAndroid Build Coastguard Worker   * Start the job if necessary...
4019*5e7646d2SAndroid Build Coastguard Worker   */
4020*5e7646d2SAndroid Build Coastguard Worker 
4021*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
4022*5e7646d2SAndroid Build Coastguard Worker }
4023*5e7646d2SAndroid Build Coastguard Worker 
4024*5e7646d2SAndroid Build Coastguard Worker 
4025*5e7646d2SAndroid Build Coastguard Worker /*
4026*5e7646d2SAndroid Build Coastguard Worker  * 'copy_attrs()' - Copy attributes from one request to another.
4027*5e7646d2SAndroid Build Coastguard Worker  */
4028*5e7646d2SAndroid Build Coastguard Worker 
4029*5e7646d2SAndroid Build Coastguard Worker static void
copy_attrs(ipp_t * to,ipp_t * from,cups_array_t * ra,ipp_tag_t group,int quickcopy,cups_array_t * exclude)4030*5e7646d2SAndroid Build Coastguard Worker copy_attrs(ipp_t        *to,		/* I - Destination request */
4031*5e7646d2SAndroid Build Coastguard Worker            ipp_t        *from,		/* I - Source request */
4032*5e7646d2SAndroid Build Coastguard Worker            cups_array_t *ra,		/* I - Requested attributes */
4033*5e7646d2SAndroid Build Coastguard Worker 	   ipp_tag_t    group,		/* I - Group to copy */
4034*5e7646d2SAndroid Build Coastguard Worker 	   int          quickcopy,	/* I - Do a quick copy? */
4035*5e7646d2SAndroid Build Coastguard Worker 	   cups_array_t *exclude)	/* I - Attributes to exclude? */
4036*5e7646d2SAndroid Build Coastguard Worker {
4037*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*fromattr;	/* Source attribute */
4038*5e7646d2SAndroid Build Coastguard Worker 
4039*5e7646d2SAndroid Build Coastguard Worker 
4040*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
4041*5e7646d2SAndroid Build Coastguard Worker                   "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
4042*5e7646d2SAndroid Build Coastguard Worker 		  to, from, ra, group, quickcopy);
4043*5e7646d2SAndroid Build Coastguard Worker 
4044*5e7646d2SAndroid Build Coastguard Worker   if (!to || !from)
4045*5e7646d2SAndroid Build Coastguard Worker     return;
4046*5e7646d2SAndroid Build Coastguard Worker 
4047*5e7646d2SAndroid Build Coastguard Worker   for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
4048*5e7646d2SAndroid Build Coastguard Worker   {
4049*5e7646d2SAndroid Build Coastguard Worker    /*
4050*5e7646d2SAndroid Build Coastguard Worker     * Filter attributes as needed...
4051*5e7646d2SAndroid Build Coastguard Worker     */
4052*5e7646d2SAndroid Build Coastguard Worker 
4053*5e7646d2SAndroid Build Coastguard Worker     if ((group != IPP_TAG_ZERO && fromattr->group_tag != group &&
4054*5e7646d2SAndroid Build Coastguard Worker          fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
4055*5e7646d2SAndroid Build Coastguard Worker       continue;
4056*5e7646d2SAndroid Build Coastguard Worker 
4057*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(fromattr->name, "document-password") ||
4058*5e7646d2SAndroid Build Coastguard Worker         !strcmp(fromattr->name, "job-authorization-uri") ||
4059*5e7646d2SAndroid Build Coastguard Worker         !strcmp(fromattr->name, "job-password") ||
4060*5e7646d2SAndroid Build Coastguard Worker         !strcmp(fromattr->name, "job-password-encryption") ||
4061*5e7646d2SAndroid Build Coastguard Worker         !strcmp(fromattr->name, "job-printer-uri"))
4062*5e7646d2SAndroid Build Coastguard Worker       continue;
4063*5e7646d2SAndroid Build Coastguard Worker 
4064*5e7646d2SAndroid Build Coastguard Worker     if (exclude &&
4065*5e7646d2SAndroid Build Coastguard Worker         (cupsArrayFind(exclude, fromattr->name) ||
4066*5e7646d2SAndroid Build Coastguard Worker 	 cupsArrayFind(exclude, "all")))
4067*5e7646d2SAndroid Build Coastguard Worker     {
4068*5e7646d2SAndroid Build Coastguard Worker      /*
4069*5e7646d2SAndroid Build Coastguard Worker       * We need to exclude this attribute for security reasons; we require the
4070*5e7646d2SAndroid Build Coastguard Worker       * job-id attribute regardless of the security settings for IPP
4071*5e7646d2SAndroid Build Coastguard Worker       * conformance.
4072*5e7646d2SAndroid Build Coastguard Worker       *
4073*5e7646d2SAndroid Build Coastguard Worker       * The job-printer-uri attribute is handled by copy_job_attrs().
4074*5e7646d2SAndroid Build Coastguard Worker       *
4075*5e7646d2SAndroid Build Coastguard Worker       * Subscription attribute security is handled by copy_subscription_attrs().
4076*5e7646d2SAndroid Build Coastguard Worker       */
4077*5e7646d2SAndroid Build Coastguard Worker 
4078*5e7646d2SAndroid Build Coastguard Worker       if (strcmp(fromattr->name, "job-id"))
4079*5e7646d2SAndroid Build Coastguard Worker         continue;
4080*5e7646d2SAndroid Build Coastguard Worker     }
4081*5e7646d2SAndroid Build Coastguard Worker 
4082*5e7646d2SAndroid Build Coastguard Worker     if (!ra || cupsArrayFind(ra, fromattr->name))
4083*5e7646d2SAndroid Build Coastguard Worker     {
4084*5e7646d2SAndroid Build Coastguard Worker      /*
4085*5e7646d2SAndroid Build Coastguard Worker       * Don't send collection attributes by default to IPP/1.x clients
4086*5e7646d2SAndroid Build Coastguard Worker       * since many do not support collections.  Also don't send
4087*5e7646d2SAndroid Build Coastguard Worker       * media-col-database unless specifically requested by the client.
4088*5e7646d2SAndroid Build Coastguard Worker       */
4089*5e7646d2SAndroid Build Coastguard Worker 
4090*5e7646d2SAndroid Build Coastguard Worker       if (fromattr->value_tag == IPP_TAG_BEGIN_COLLECTION &&
4091*5e7646d2SAndroid Build Coastguard Worker           !ra &&
4092*5e7646d2SAndroid Build Coastguard Worker 	  (to->request.status.version[0] == 1 ||
4093*5e7646d2SAndroid Build Coastguard Worker 	   !strcmp(fromattr->name, "media-col-database")))
4094*5e7646d2SAndroid Build Coastguard Worker 	continue;
4095*5e7646d2SAndroid Build Coastguard Worker 
4096*5e7646d2SAndroid Build Coastguard Worker       ippCopyAttribute(to, fromattr, quickcopy);
4097*5e7646d2SAndroid Build Coastguard Worker     }
4098*5e7646d2SAndroid Build Coastguard Worker   }
4099*5e7646d2SAndroid Build Coastguard Worker }
4100*5e7646d2SAndroid Build Coastguard Worker 
4101*5e7646d2SAndroid Build Coastguard Worker 
4102*5e7646d2SAndroid Build Coastguard Worker /*
4103*5e7646d2SAndroid Build Coastguard Worker  * 'copy_banner()' - Copy a banner file to the requests directory for the
4104*5e7646d2SAndroid Build Coastguard Worker  *                   specified job.
4105*5e7646d2SAndroid Build Coastguard Worker  */
4106*5e7646d2SAndroid Build Coastguard Worker 
4107*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Size of banner file in kbytes */
copy_banner(cupsd_client_t * con,cupsd_job_t * job,const char * name)4108*5e7646d2SAndroid Build Coastguard Worker copy_banner(cupsd_client_t *con,	/* I - Client connection */
4109*5e7646d2SAndroid Build Coastguard Worker             cupsd_job_t    *job,	/* I - Job information */
4110*5e7646d2SAndroid Build Coastguard Worker             const char     *name)	/* I - Name of banner */
4111*5e7646d2SAndroid Build Coastguard Worker {
4112*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
4113*5e7646d2SAndroid Build Coastguard Worker   int		kbytes;			/* Size of banner file in kbytes */
4114*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Job filename */
4115*5e7646d2SAndroid Build Coastguard Worker   cupsd_banner_t *banner;		/* Pointer to banner */
4116*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*in;			/* Input file */
4117*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*out;			/* Output file */
4118*5e7646d2SAndroid Build Coastguard Worker   int		ch;			/* Character from file */
4119*5e7646d2SAndroid Build Coastguard Worker   char		attrname[255],		/* Name of attribute */
4120*5e7646d2SAndroid Build Coastguard Worker 		*s;			/* Pointer into name */
4121*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Attribute */
4122*5e7646d2SAndroid Build Coastguard Worker 
4123*5e7646d2SAndroid Build Coastguard Worker 
4124*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
4125*5e7646d2SAndroid Build Coastguard Worker                   "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")",
4126*5e7646d2SAndroid Build Coastguard Worker                   con, con ? con->number : -1, job, job->id,
4127*5e7646d2SAndroid Build Coastguard Worker 		  name ? name : "(null)");
4128*5e7646d2SAndroid Build Coastguard Worker 
4129*5e7646d2SAndroid Build Coastguard Worker  /*
4130*5e7646d2SAndroid Build Coastguard Worker   * Find the banner; return if not found or "none"...
4131*5e7646d2SAndroid Build Coastguard Worker   */
4132*5e7646d2SAndroid Build Coastguard Worker 
4133*5e7646d2SAndroid Build Coastguard Worker   if (!name || !strcmp(name, "none") ||
4134*5e7646d2SAndroid Build Coastguard Worker       (banner = cupsdFindBanner(name)) == NULL)
4135*5e7646d2SAndroid Build Coastguard Worker     return (0);
4136*5e7646d2SAndroid Build Coastguard Worker 
4137*5e7646d2SAndroid Build Coastguard Worker  /*
4138*5e7646d2SAndroid Build Coastguard Worker   * Open the banner and job files...
4139*5e7646d2SAndroid Build Coastguard Worker   */
4140*5e7646d2SAndroid Build Coastguard Worker 
4141*5e7646d2SAndroid Build Coastguard Worker   if (add_file(con, job, banner->filetype, 0))
4142*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4143*5e7646d2SAndroid Build Coastguard Worker 
4144*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
4145*5e7646d2SAndroid Build Coastguard Worker            job->num_files);
4146*5e7646d2SAndroid Build Coastguard Worker   if ((out = cupsFileOpen(filename, "w")) == NULL)
4147*5e7646d2SAndroid Build Coastguard Worker   {
4148*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
4149*5e7646d2SAndroid Build Coastguard Worker                     "Unable to create banner job file %s - %s",
4150*5e7646d2SAndroid Build Coastguard Worker                     filename, strerror(errno));
4151*5e7646d2SAndroid Build Coastguard Worker     job->num_files --;
4152*5e7646d2SAndroid Build Coastguard Worker     return (0);
4153*5e7646d2SAndroid Build Coastguard Worker   }
4154*5e7646d2SAndroid Build Coastguard Worker 
4155*5e7646d2SAndroid Build Coastguard Worker   fchmod(cupsFileNumber(out), 0640);
4156*5e7646d2SAndroid Build Coastguard Worker   fchown(cupsFileNumber(out), RunUser, Group);
4157*5e7646d2SAndroid Build Coastguard Worker 
4158*5e7646d2SAndroid Build Coastguard Worker  /*
4159*5e7646d2SAndroid Build Coastguard Worker   * Try the localized banner file under the subdirectory...
4160*5e7646d2SAndroid Build Coastguard Worker   */
4161*5e7646d2SAndroid Build Coastguard Worker 
4162*5e7646d2SAndroid Build Coastguard Worker   strlcpy(attrname, job->attrs->attrs->next->values[0].string.text,
4163*5e7646d2SAndroid Build Coastguard Worker           sizeof(attrname));
4164*5e7646d2SAndroid Build Coastguard Worker   if (strlen(attrname) > 2 && attrname[2] == '-')
4165*5e7646d2SAndroid Build Coastguard Worker   {
4166*5e7646d2SAndroid Build Coastguard Worker    /*
4167*5e7646d2SAndroid Build Coastguard Worker     * Convert ll-cc to ll_CC...
4168*5e7646d2SAndroid Build Coastguard Worker     */
4169*5e7646d2SAndroid Build Coastguard Worker 
4170*5e7646d2SAndroid Build Coastguard Worker     attrname[2] = '_';
4171*5e7646d2SAndroid Build Coastguard Worker     attrname[3] = (char)toupper(attrname[3] & 255);
4172*5e7646d2SAndroid Build Coastguard Worker     attrname[4] = (char)toupper(attrname[4] & 255);
4173*5e7646d2SAndroid Build Coastguard Worker   }
4174*5e7646d2SAndroid Build Coastguard Worker 
4175*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
4176*5e7646d2SAndroid Build Coastguard Worker            attrname, name);
4177*5e7646d2SAndroid Build Coastguard Worker 
4178*5e7646d2SAndroid Build Coastguard Worker   if (access(filename, 0) && strlen(attrname) > 2)
4179*5e7646d2SAndroid Build Coastguard Worker   {
4180*5e7646d2SAndroid Build Coastguard Worker    /*
4181*5e7646d2SAndroid Build Coastguard Worker     * Wasn't able to find "ll_CC" locale file; try the non-national
4182*5e7646d2SAndroid Build Coastguard Worker     * localization banner directory.
4183*5e7646d2SAndroid Build Coastguard Worker     */
4184*5e7646d2SAndroid Build Coastguard Worker 
4185*5e7646d2SAndroid Build Coastguard Worker     attrname[2] = '\0';
4186*5e7646d2SAndroid Build Coastguard Worker 
4187*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
4188*5e7646d2SAndroid Build Coastguard Worker              attrname, name);
4189*5e7646d2SAndroid Build Coastguard Worker   }
4190*5e7646d2SAndroid Build Coastguard Worker 
4191*5e7646d2SAndroid Build Coastguard Worker   if (access(filename, 0))
4192*5e7646d2SAndroid Build Coastguard Worker   {
4193*5e7646d2SAndroid Build Coastguard Worker    /*
4194*5e7646d2SAndroid Build Coastguard Worker     * Use the non-localized banner file.
4195*5e7646d2SAndroid Build Coastguard Worker     */
4196*5e7646d2SAndroid Build Coastguard Worker 
4197*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
4198*5e7646d2SAndroid Build Coastguard Worker   }
4199*5e7646d2SAndroid Build Coastguard Worker 
4200*5e7646d2SAndroid Build Coastguard Worker   if ((in = cupsFileOpen(filename, "r")) == NULL)
4201*5e7646d2SAndroid Build Coastguard Worker   {
4202*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(out);
4203*5e7646d2SAndroid Build Coastguard Worker     unlink(filename);
4204*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
4205*5e7646d2SAndroid Build Coastguard Worker                     "Unable to open banner template file %s - %s",
4206*5e7646d2SAndroid Build Coastguard Worker                     filename, strerror(errno));
4207*5e7646d2SAndroid Build Coastguard Worker     job->num_files --;
4208*5e7646d2SAndroid Build Coastguard Worker     return (0);
4209*5e7646d2SAndroid Build Coastguard Worker   }
4210*5e7646d2SAndroid Build Coastguard Worker 
4211*5e7646d2SAndroid Build Coastguard Worker  /*
4212*5e7646d2SAndroid Build Coastguard Worker   * Parse the file to the end...
4213*5e7646d2SAndroid Build Coastguard Worker   */
4214*5e7646d2SAndroid Build Coastguard Worker 
4215*5e7646d2SAndroid Build Coastguard Worker   while ((ch = cupsFileGetChar(in)) != EOF)
4216*5e7646d2SAndroid Build Coastguard Worker     if (ch == '{')
4217*5e7646d2SAndroid Build Coastguard Worker     {
4218*5e7646d2SAndroid Build Coastguard Worker      /*
4219*5e7646d2SAndroid Build Coastguard Worker       * Get an attribute name...
4220*5e7646d2SAndroid Build Coastguard Worker       */
4221*5e7646d2SAndroid Build Coastguard Worker 
4222*5e7646d2SAndroid Build Coastguard Worker       for (s = attrname; (ch = cupsFileGetChar(in)) != EOF;)
4223*5e7646d2SAndroid Build Coastguard Worker         if (!isalpha(ch & 255) && ch != '-' && ch != '?')
4224*5e7646d2SAndroid Build Coastguard Worker           break;
4225*5e7646d2SAndroid Build Coastguard Worker 	else if (s < (attrname + sizeof(attrname) - 1))
4226*5e7646d2SAndroid Build Coastguard Worker           *s++ = (char)ch;
4227*5e7646d2SAndroid Build Coastguard Worker 	else
4228*5e7646d2SAndroid Build Coastguard Worker 	  break;
4229*5e7646d2SAndroid Build Coastguard Worker 
4230*5e7646d2SAndroid Build Coastguard Worker       *s = '\0';
4231*5e7646d2SAndroid Build Coastguard Worker 
4232*5e7646d2SAndroid Build Coastguard Worker       if (ch != '}')
4233*5e7646d2SAndroid Build Coastguard Worker       {
4234*5e7646d2SAndroid Build Coastguard Worker        /*
4235*5e7646d2SAndroid Build Coastguard Worker         * Ignore { followed by stuff that is not an attribute name...
4236*5e7646d2SAndroid Build Coastguard Worker 	*/
4237*5e7646d2SAndroid Build Coastguard Worker 
4238*5e7646d2SAndroid Build Coastguard Worker         cupsFilePrintf(out, "{%s%c", attrname, ch);
4239*5e7646d2SAndroid Build Coastguard Worker 	continue;
4240*5e7646d2SAndroid Build Coastguard Worker       }
4241*5e7646d2SAndroid Build Coastguard Worker 
4242*5e7646d2SAndroid Build Coastguard Worker      /*
4243*5e7646d2SAndroid Build Coastguard Worker       * See if it is defined...
4244*5e7646d2SAndroid Build Coastguard Worker       */
4245*5e7646d2SAndroid Build Coastguard Worker 
4246*5e7646d2SAndroid Build Coastguard Worker       if (attrname[0] == '?')
4247*5e7646d2SAndroid Build Coastguard Worker         s = attrname + 1;
4248*5e7646d2SAndroid Build Coastguard Worker       else
4249*5e7646d2SAndroid Build Coastguard Worker         s = attrname;
4250*5e7646d2SAndroid Build Coastguard Worker 
4251*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(s, "printer-name"))
4252*5e7646d2SAndroid Build Coastguard Worker       {
4253*5e7646d2SAndroid Build Coastguard Worker         cupsFilePuts(out, job->dest);
4254*5e7646d2SAndroid Build Coastguard Worker 	continue;
4255*5e7646d2SAndroid Build Coastguard Worker       }
4256*5e7646d2SAndroid Build Coastguard Worker       else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
4257*5e7646d2SAndroid Build Coastguard Worker       {
4258*5e7646d2SAndroid Build Coastguard Worker        /*
4259*5e7646d2SAndroid Build Coastguard Worker         * See if we have a leading question mark...
4260*5e7646d2SAndroid Build Coastguard Worker 	*/
4261*5e7646d2SAndroid Build Coastguard Worker 
4262*5e7646d2SAndroid Build Coastguard Worker 	if (attrname[0] != '?')
4263*5e7646d2SAndroid Build Coastguard Worker 	{
4264*5e7646d2SAndroid Build Coastguard Worker 	 /*
4265*5e7646d2SAndroid Build Coastguard Worker           * Nope, write to file as-is; probably a PostScript procedure...
4266*5e7646d2SAndroid Build Coastguard Worker 	  */
4267*5e7646d2SAndroid Build Coastguard Worker 
4268*5e7646d2SAndroid Build Coastguard Worker 	  cupsFilePrintf(out, "{%s}", attrname);
4269*5e7646d2SAndroid Build Coastguard Worker         }
4270*5e7646d2SAndroid Build Coastguard Worker 
4271*5e7646d2SAndroid Build Coastguard Worker         continue;
4272*5e7646d2SAndroid Build Coastguard Worker       }
4273*5e7646d2SAndroid Build Coastguard Worker 
4274*5e7646d2SAndroid Build Coastguard Worker      /*
4275*5e7646d2SAndroid Build Coastguard Worker       * Output value(s)...
4276*5e7646d2SAndroid Build Coastguard Worker       */
4277*5e7646d2SAndroid Build Coastguard Worker 
4278*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < attr->num_values; i ++)
4279*5e7646d2SAndroid Build Coastguard Worker       {
4280*5e7646d2SAndroid Build Coastguard Worker 	if (i)
4281*5e7646d2SAndroid Build Coastguard Worker 	  cupsFilePutChar(out, ',');
4282*5e7646d2SAndroid Build Coastguard Worker 
4283*5e7646d2SAndroid Build Coastguard Worker 	switch (attr->value_tag)
4284*5e7646d2SAndroid Build Coastguard Worker 	{
4285*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_INTEGER :
4286*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_ENUM :
4287*5e7646d2SAndroid Build Coastguard Worker 	      if (!strncmp(s, "time-at-", 8))
4288*5e7646d2SAndroid Build Coastguard Worker 	      {
4289*5e7646d2SAndroid Build Coastguard Worker 	        struct timeval tv;	/* Time value */
4290*5e7646d2SAndroid Build Coastguard Worker 
4291*5e7646d2SAndroid Build Coastguard Worker 		tv.tv_sec  = attr->values[i].integer;
4292*5e7646d2SAndroid Build Coastguard Worker 		tv.tv_usec = 0;
4293*5e7646d2SAndroid Build Coastguard Worker 
4294*5e7646d2SAndroid Build Coastguard Worker 	        cupsFilePuts(out, cupsdGetDateTime(&tv, CUPSD_TIME_STANDARD));
4295*5e7646d2SAndroid Build Coastguard Worker 	      }
4296*5e7646d2SAndroid Build Coastguard Worker 	      else
4297*5e7646d2SAndroid Build Coastguard Worker 	        cupsFilePrintf(out, "%d", attr->values[i].integer);
4298*5e7646d2SAndroid Build Coastguard Worker 	      break;
4299*5e7646d2SAndroid Build Coastguard Worker 
4300*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_BOOLEAN :
4301*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePrintf(out, "%d", attr->values[i].boolean);
4302*5e7646d2SAndroid Build Coastguard Worker 	      break;
4303*5e7646d2SAndroid Build Coastguard Worker 
4304*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_NOVALUE :
4305*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePuts(out, "novalue");
4306*5e7646d2SAndroid Build Coastguard Worker 	      break;
4307*5e7646d2SAndroid Build Coastguard Worker 
4308*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_RANGE :
4309*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePrintf(out, "%d-%d", attr->values[i].range.lower,
4310*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[i].range.upper);
4311*5e7646d2SAndroid Build Coastguard Worker 	      break;
4312*5e7646d2SAndroid Build Coastguard Worker 
4313*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_RESOLUTION :
4314*5e7646d2SAndroid Build Coastguard Worker 	      cupsFilePrintf(out, "%dx%d%s", attr->values[i].resolution.xres,
4315*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[i].resolution.yres,
4316*5e7646d2SAndroid Build Coastguard Worker 		      attr->values[i].resolution.units == IPP_RES_PER_INCH ?
4317*5e7646d2SAndroid Build Coastguard Worker 			  "dpi" : "dpcm");
4318*5e7646d2SAndroid Build Coastguard Worker 	      break;
4319*5e7646d2SAndroid Build Coastguard Worker 
4320*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_URI :
4321*5e7646d2SAndroid Build Coastguard Worker           case IPP_TAG_STRING :
4322*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_TEXT :
4323*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_NAME :
4324*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_KEYWORD :
4325*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_CHARSET :
4326*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_LANGUAGE :
4327*5e7646d2SAndroid Build Coastguard Worker 	      if (!_cups_strcasecmp(banner->filetype->type, "postscript"))
4328*5e7646d2SAndroid Build Coastguard Worker 	      {
4329*5e7646d2SAndroid Build Coastguard Worker 	       /*
4330*5e7646d2SAndroid Build Coastguard Worker 	        * Need to quote strings for PS banners...
4331*5e7646d2SAndroid Build Coastguard Worker 		*/
4332*5e7646d2SAndroid Build Coastguard Worker 
4333*5e7646d2SAndroid Build Coastguard Worker 	        const char *p;
4334*5e7646d2SAndroid Build Coastguard Worker 
4335*5e7646d2SAndroid Build Coastguard Worker 		for (p = attr->values[i].string.text; *p; p ++)
4336*5e7646d2SAndroid Build Coastguard Worker 		{
4337*5e7646d2SAndroid Build Coastguard Worker 		  if (*p == '(' || *p == ')' || *p == '\\')
4338*5e7646d2SAndroid Build Coastguard Worker 		  {
4339*5e7646d2SAndroid Build Coastguard Worker 		    cupsFilePutChar(out, '\\');
4340*5e7646d2SAndroid Build Coastguard Worker 		    cupsFilePutChar(out, *p);
4341*5e7646d2SAndroid Build Coastguard Worker 		  }
4342*5e7646d2SAndroid Build Coastguard Worker 		  else if (*p < 32 || *p > 126)
4343*5e7646d2SAndroid Build Coastguard Worker 		    cupsFilePrintf(out, "\\%03o", *p & 255);
4344*5e7646d2SAndroid Build Coastguard Worker 		  else
4345*5e7646d2SAndroid Build Coastguard Worker 		    cupsFilePutChar(out, *p);
4346*5e7646d2SAndroid Build Coastguard Worker 		}
4347*5e7646d2SAndroid Build Coastguard Worker 	      }
4348*5e7646d2SAndroid Build Coastguard Worker 	      else
4349*5e7646d2SAndroid Build Coastguard Worker 		cupsFilePuts(out, attr->values[i].string.text);
4350*5e7646d2SAndroid Build Coastguard Worker 	      break;
4351*5e7646d2SAndroid Build Coastguard Worker 
4352*5e7646d2SAndroid Build Coastguard Worker           default :
4353*5e7646d2SAndroid Build Coastguard Worker 	      break; /* anti-compiler-warning-code */
4354*5e7646d2SAndroid Build Coastguard Worker 	}
4355*5e7646d2SAndroid Build Coastguard Worker       }
4356*5e7646d2SAndroid Build Coastguard Worker     }
4357*5e7646d2SAndroid Build Coastguard Worker     else if (ch == '\\')	/* Quoted char */
4358*5e7646d2SAndroid Build Coastguard Worker     {
4359*5e7646d2SAndroid Build Coastguard Worker       ch = cupsFileGetChar(in);
4360*5e7646d2SAndroid Build Coastguard Worker 
4361*5e7646d2SAndroid Build Coastguard Worker       if (ch != '{')		/* Only do special handling for \{ */
4362*5e7646d2SAndroid Build Coastguard Worker         cupsFilePutChar(out, '\\');
4363*5e7646d2SAndroid Build Coastguard Worker 
4364*5e7646d2SAndroid Build Coastguard Worker       cupsFilePutChar(out, ch);
4365*5e7646d2SAndroid Build Coastguard Worker     }
4366*5e7646d2SAndroid Build Coastguard Worker     else
4367*5e7646d2SAndroid Build Coastguard Worker       cupsFilePutChar(out, ch);
4368*5e7646d2SAndroid Build Coastguard Worker 
4369*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(in);
4370*5e7646d2SAndroid Build Coastguard Worker 
4371*5e7646d2SAndroid Build Coastguard Worker   kbytes = (cupsFileTell(out) + 1023) / 1024;
4372*5e7646d2SAndroid Build Coastguard Worker 
4373*5e7646d2SAndroid Build Coastguard Worker   job->koctets += kbytes;
4374*5e7646d2SAndroid Build Coastguard Worker 
4375*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
4376*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer += kbytes;
4377*5e7646d2SAndroid Build Coastguard Worker 
4378*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(out);
4379*5e7646d2SAndroid Build Coastguard Worker 
4380*5e7646d2SAndroid Build Coastguard Worker   return (kbytes);
4381*5e7646d2SAndroid Build Coastguard Worker }
4382*5e7646d2SAndroid Build Coastguard Worker 
4383*5e7646d2SAndroid Build Coastguard Worker 
4384*5e7646d2SAndroid Build Coastguard Worker /*
4385*5e7646d2SAndroid Build Coastguard Worker  * 'copy_file()' - Copy a PPD file...
4386*5e7646d2SAndroid Build Coastguard Worker  */
4387*5e7646d2SAndroid Build Coastguard Worker 
4388*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 = success, -1 = error */
copy_file(const char * from,const char * to,mode_t mode)4389*5e7646d2SAndroid Build Coastguard Worker copy_file(const char *from,		/* I - Source file */
4390*5e7646d2SAndroid Build Coastguard Worker           const char *to,		/* I - Destination file */
4391*5e7646d2SAndroid Build Coastguard Worker 	  mode_t     mode)		/* I - Permissions */
4392*5e7646d2SAndroid Build Coastguard Worker {
4393*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*src,			/* Source file */
4394*5e7646d2SAndroid Build Coastguard Worker 		*dst;			/* Destination file */
4395*5e7646d2SAndroid Build Coastguard Worker   int		bytes;			/* Bytes to read/write */
4396*5e7646d2SAndroid Build Coastguard Worker   char		buffer[2048];		/* Copy buffer */
4397*5e7646d2SAndroid Build Coastguard Worker 
4398*5e7646d2SAndroid Build Coastguard Worker 
4399*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_file(\"%s\", \"%s\")", from, to);
4400*5e7646d2SAndroid Build Coastguard Worker 
4401*5e7646d2SAndroid Build Coastguard Worker  /*
4402*5e7646d2SAndroid Build Coastguard Worker   * Open the source and destination file for a copy...
4403*5e7646d2SAndroid Build Coastguard Worker   */
4404*5e7646d2SAndroid Build Coastguard Worker 
4405*5e7646d2SAndroid Build Coastguard Worker   if ((src = cupsFileOpen(from, "rb")) == NULL)
4406*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4407*5e7646d2SAndroid Build Coastguard Worker 
4408*5e7646d2SAndroid Build Coastguard Worker   if ((dst = cupsdCreateConfFile(to, mode)) == NULL)
4409*5e7646d2SAndroid Build Coastguard Worker   {
4410*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(src);
4411*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4412*5e7646d2SAndroid Build Coastguard Worker   }
4413*5e7646d2SAndroid Build Coastguard Worker 
4414*5e7646d2SAndroid Build Coastguard Worker  /*
4415*5e7646d2SAndroid Build Coastguard Worker   * Copy the source file to the destination...
4416*5e7646d2SAndroid Build Coastguard Worker   */
4417*5e7646d2SAndroid Build Coastguard Worker 
4418*5e7646d2SAndroid Build Coastguard Worker   while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0)
4419*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileWrite(dst, buffer, (size_t)bytes) < bytes)
4420*5e7646d2SAndroid Build Coastguard Worker     {
4421*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(src);
4422*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(dst);
4423*5e7646d2SAndroid Build Coastguard Worker       return (-1);
4424*5e7646d2SAndroid Build Coastguard Worker     }
4425*5e7646d2SAndroid Build Coastguard Worker 
4426*5e7646d2SAndroid Build Coastguard Worker  /*
4427*5e7646d2SAndroid Build Coastguard Worker   * Close both files and return...
4428*5e7646d2SAndroid Build Coastguard Worker   */
4429*5e7646d2SAndroid Build Coastguard Worker 
4430*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(src);
4431*5e7646d2SAndroid Build Coastguard Worker 
4432*5e7646d2SAndroid Build Coastguard Worker   return (cupsdCloseCreatedConfFile(dst, to));
4433*5e7646d2SAndroid Build Coastguard Worker }
4434*5e7646d2SAndroid Build Coastguard Worker 
4435*5e7646d2SAndroid Build Coastguard Worker 
4436*5e7646d2SAndroid Build Coastguard Worker /*
4437*5e7646d2SAndroid Build Coastguard Worker  * 'copy_model()' - Copy a PPD model file, substituting default values
4438*5e7646d2SAndroid Build Coastguard Worker  *                  as needed...
4439*5e7646d2SAndroid Build Coastguard Worker  */
4440*5e7646d2SAndroid Build Coastguard Worker 
4441*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 = success, -1 = error */
copy_model(cupsd_client_t * con,const char * from,const char * to)4442*5e7646d2SAndroid Build Coastguard Worker copy_model(cupsd_client_t *con,		/* I - Client connection */
4443*5e7646d2SAndroid Build Coastguard Worker            const char     *from,	/* I - Source file */
4444*5e7646d2SAndroid Build Coastguard Worker            const char     *to)		/* I - Destination file */
4445*5e7646d2SAndroid Build Coastguard Worker {
4446*5e7646d2SAndroid Build Coastguard Worker   fd_set	input;			/* select() input set */
4447*5e7646d2SAndroid Build Coastguard Worker   struct timeval timeout;		/* select() timeout */
4448*5e7646d2SAndroid Build Coastguard Worker   int		maxfd;			/* Max file descriptor for select() */
4449*5e7646d2SAndroid Build Coastguard Worker   char		tempfile[1024];		/* Temporary PPD file */
4450*5e7646d2SAndroid Build Coastguard Worker   int		tempfd;			/* Temporary PPD file descriptor */
4451*5e7646d2SAndroid Build Coastguard Worker   int		temppid;		/* Process ID of cups-driverd */
4452*5e7646d2SAndroid Build Coastguard Worker   int		temppipe[2];		/* Temporary pipes */
4453*5e7646d2SAndroid Build Coastguard Worker   char		*argv[4],		/* Command-line arguments */
4454*5e7646d2SAndroid Build Coastguard Worker 		*envp[MAX_ENV];		/* Environment */
4455*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*src,			/* Source file */
4456*5e7646d2SAndroid Build Coastguard Worker 		*dst;			/* Destination file */
4457*5e7646d2SAndroid Build Coastguard Worker   ppd_file_t	*ppd;			/* PPD file */
4458*5e7646d2SAndroid Build Coastguard Worker   int		bytes,			/* Bytes from pipe */
4459*5e7646d2SAndroid Build Coastguard Worker 		total;			/* Total bytes from pipe */
4460*5e7646d2SAndroid Build Coastguard Worker   char		buffer[2048];		/* Copy buffer */
4461*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
4462*5e7646d2SAndroid Build Coastguard Worker   char		option[PPD_MAX_NAME],	/* Option name */
4463*5e7646d2SAndroid Build Coastguard Worker 		choice[PPD_MAX_NAME];	/* Choice name */
4464*5e7646d2SAndroid Build Coastguard Worker   ppd_size_t	*size;			/* Default size */
4465*5e7646d2SAndroid Build Coastguard Worker   int		num_defaults;		/* Number of default options */
4466*5e7646d2SAndroid Build Coastguard Worker   cups_option_t	*defaults;		/* Default options */
4467*5e7646d2SAndroid Build Coastguard Worker   char		cups_protocol[PPD_MAX_LINE];
4468*5e7646d2SAndroid Build Coastguard Worker 					/* cupsProtocol attribute */
4469*5e7646d2SAndroid Build Coastguard Worker 
4470*5e7646d2SAndroid Build Coastguard Worker 
4471*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", con, from, to);
4472*5e7646d2SAndroid Build Coastguard Worker 
4473*5e7646d2SAndroid Build Coastguard Worker  /*
4474*5e7646d2SAndroid Build Coastguard Worker   * Run cups-driverd to get the PPD file...
4475*5e7646d2SAndroid Build Coastguard Worker   */
4476*5e7646d2SAndroid Build Coastguard Worker 
4477*5e7646d2SAndroid Build Coastguard Worker   argv[0] = "cups-driverd";
4478*5e7646d2SAndroid Build Coastguard Worker   argv[1] = "cat";
4479*5e7646d2SAndroid Build Coastguard Worker   argv[2] = (char *)from;
4480*5e7646d2SAndroid Build Coastguard Worker   argv[3] = NULL;
4481*5e7646d2SAndroid Build Coastguard Worker 
4482*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
4483*5e7646d2SAndroid Build Coastguard Worker 
4484*5e7646d2SAndroid Build Coastguard Worker   snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin);
4485*5e7646d2SAndroid Build Coastguard Worker   snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->number);
4486*5e7646d2SAndroid Build Coastguard Worker   tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
4487*5e7646d2SAndroid Build Coastguard Worker   if (tempfd < 0 || cupsdOpenPipe(temppipe))
4488*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4489*5e7646d2SAndroid Build Coastguard Worker 
4490*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG,
4491*5e7646d2SAndroid Build Coastguard Worker                   "copy_model: Running \"cups-driverd cat %s\"...", from);
4492*5e7646d2SAndroid Build Coastguard Worker 
4493*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
4494*5e7646d2SAndroid Build Coastguard Worker                          -1, -1, 0, DefaultProfile, NULL, &temppid))
4495*5e7646d2SAndroid Build Coastguard Worker   {
4496*5e7646d2SAndroid Build Coastguard Worker     close(tempfd);
4497*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
4498*5e7646d2SAndroid Build Coastguard Worker 
4499*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4500*5e7646d2SAndroid Build Coastguard Worker   }
4501*5e7646d2SAndroid Build Coastguard Worker 
4502*5e7646d2SAndroid Build Coastguard Worker   close(temppipe[1]);
4503*5e7646d2SAndroid Build Coastguard Worker 
4504*5e7646d2SAndroid Build Coastguard Worker  /*
4505*5e7646d2SAndroid Build Coastguard Worker   * Wait up to 30 seconds for the PPD file to be copied...
4506*5e7646d2SAndroid Build Coastguard Worker   */
4507*5e7646d2SAndroid Build Coastguard Worker 
4508*5e7646d2SAndroid Build Coastguard Worker   total = 0;
4509*5e7646d2SAndroid Build Coastguard Worker 
4510*5e7646d2SAndroid Build Coastguard Worker   if (temppipe[0] > CGIPipes[0])
4511*5e7646d2SAndroid Build Coastguard Worker     maxfd = temppipe[0] + 1;
4512*5e7646d2SAndroid Build Coastguard Worker   else
4513*5e7646d2SAndroid Build Coastguard Worker     maxfd = CGIPipes[0] + 1;
4514*5e7646d2SAndroid Build Coastguard Worker 
4515*5e7646d2SAndroid Build Coastguard Worker   for (;;)
4516*5e7646d2SAndroid Build Coastguard Worker   {
4517*5e7646d2SAndroid Build Coastguard Worker    /*
4518*5e7646d2SAndroid Build Coastguard Worker     * See if we have data ready...
4519*5e7646d2SAndroid Build Coastguard Worker     */
4520*5e7646d2SAndroid Build Coastguard Worker 
4521*5e7646d2SAndroid Build Coastguard Worker     FD_ZERO(&input);
4522*5e7646d2SAndroid Build Coastguard Worker     FD_SET(temppipe[0], &input);
4523*5e7646d2SAndroid Build Coastguard Worker     FD_SET(CGIPipes[0], &input);
4524*5e7646d2SAndroid Build Coastguard Worker 
4525*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_sec  = 30;
4526*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_usec = 0;
4527*5e7646d2SAndroid Build Coastguard Worker 
4528*5e7646d2SAndroid Build Coastguard Worker     if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
4529*5e7646d2SAndroid Build Coastguard Worker     {
4530*5e7646d2SAndroid Build Coastguard Worker       if (errno == EINTR)
4531*5e7646d2SAndroid Build Coastguard Worker         continue;
4532*5e7646d2SAndroid Build Coastguard Worker       else
4533*5e7646d2SAndroid Build Coastguard Worker         break;
4534*5e7646d2SAndroid Build Coastguard Worker     }
4535*5e7646d2SAndroid Build Coastguard Worker     else if (i == 0)
4536*5e7646d2SAndroid Build Coastguard Worker     {
4537*5e7646d2SAndroid Build Coastguard Worker      /*
4538*5e7646d2SAndroid Build Coastguard Worker       * We have timed out...
4539*5e7646d2SAndroid Build Coastguard Worker       */
4540*5e7646d2SAndroid Build Coastguard Worker 
4541*5e7646d2SAndroid Build Coastguard Worker       break;
4542*5e7646d2SAndroid Build Coastguard Worker     }
4543*5e7646d2SAndroid Build Coastguard Worker 
4544*5e7646d2SAndroid Build Coastguard Worker     if (FD_ISSET(temppipe[0], &input))
4545*5e7646d2SAndroid Build Coastguard Worker     {
4546*5e7646d2SAndroid Build Coastguard Worker      /*
4547*5e7646d2SAndroid Build Coastguard Worker       * Read the PPD file from the pipe, and write it to the PPD file.
4548*5e7646d2SAndroid Build Coastguard Worker       */
4549*5e7646d2SAndroid Build Coastguard Worker 
4550*5e7646d2SAndroid Build Coastguard Worker       if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0)
4551*5e7646d2SAndroid Build Coastguard Worker       {
4552*5e7646d2SAndroid Build Coastguard Worker 	if (write(tempfd, buffer, (size_t)bytes) < bytes)
4553*5e7646d2SAndroid Build Coastguard Worker           break;
4554*5e7646d2SAndroid Build Coastguard Worker 
4555*5e7646d2SAndroid Build Coastguard Worker 	total += bytes;
4556*5e7646d2SAndroid Build Coastguard Worker       }
4557*5e7646d2SAndroid Build Coastguard Worker       else
4558*5e7646d2SAndroid Build Coastguard Worker 	break;
4559*5e7646d2SAndroid Build Coastguard Worker     }
4560*5e7646d2SAndroid Build Coastguard Worker 
4561*5e7646d2SAndroid Build Coastguard Worker     if (FD_ISSET(CGIPipes[0], &input))
4562*5e7646d2SAndroid Build Coastguard Worker       cupsdUpdateCGI();
4563*5e7646d2SAndroid Build Coastguard Worker   }
4564*5e7646d2SAndroid Build Coastguard Worker 
4565*5e7646d2SAndroid Build Coastguard Worker   close(temppipe[0]);
4566*5e7646d2SAndroid Build Coastguard Worker   close(tempfd);
4567*5e7646d2SAndroid Build Coastguard Worker 
4568*5e7646d2SAndroid Build Coastguard Worker   if (!total)
4569*5e7646d2SAndroid Build Coastguard Worker   {
4570*5e7646d2SAndroid Build Coastguard Worker    /*
4571*5e7646d2SAndroid Build Coastguard Worker     * No data from cups-deviced...
4572*5e7646d2SAndroid Build Coastguard Worker     */
4573*5e7646d2SAndroid Build Coastguard Worker 
4574*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file");
4575*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
4576*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4577*5e7646d2SAndroid Build Coastguard Worker   }
4578*5e7646d2SAndroid Build Coastguard Worker 
4579*5e7646d2SAndroid Build Coastguard Worker  /*
4580*5e7646d2SAndroid Build Coastguard Worker   * Open the source file for a copy...
4581*5e7646d2SAndroid Build Coastguard Worker   */
4582*5e7646d2SAndroid Build Coastguard Worker 
4583*5e7646d2SAndroid Build Coastguard Worker   if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
4584*5e7646d2SAndroid Build Coastguard Worker   {
4585*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
4586*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4587*5e7646d2SAndroid Build Coastguard Worker   }
4588*5e7646d2SAndroid Build Coastguard Worker 
4589*5e7646d2SAndroid Build Coastguard Worker  /*
4590*5e7646d2SAndroid Build Coastguard Worker   * Read the source file and see what page sizes are supported...
4591*5e7646d2SAndroid Build Coastguard Worker   */
4592*5e7646d2SAndroid Build Coastguard Worker 
4593*5e7646d2SAndroid Build Coastguard Worker   if ((ppd = _ppdOpen(src, _PPD_LOCALIZATION_NONE)) == NULL)
4594*5e7646d2SAndroid Build Coastguard Worker   {
4595*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(src);
4596*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
4597*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4598*5e7646d2SAndroid Build Coastguard Worker   }
4599*5e7646d2SAndroid Build Coastguard Worker 
4600*5e7646d2SAndroid Build Coastguard Worker  /*
4601*5e7646d2SAndroid Build Coastguard Worker   * Open the destination (if possible) and set the default options...
4602*5e7646d2SAndroid Build Coastguard Worker   */
4603*5e7646d2SAndroid Build Coastguard Worker 
4604*5e7646d2SAndroid Build Coastguard Worker   num_defaults     = 0;
4605*5e7646d2SAndroid Build Coastguard Worker   defaults         = NULL;
4606*5e7646d2SAndroid Build Coastguard Worker   cups_protocol[0] = '\0';
4607*5e7646d2SAndroid Build Coastguard Worker 
4608*5e7646d2SAndroid Build Coastguard Worker   if ((dst = cupsFileOpen(to, "rb")) != NULL)
4609*5e7646d2SAndroid Build Coastguard Worker   {
4610*5e7646d2SAndroid Build Coastguard Worker    /*
4611*5e7646d2SAndroid Build Coastguard Worker     * Read all of the default lines from the old PPD...
4612*5e7646d2SAndroid Build Coastguard Worker     */
4613*5e7646d2SAndroid Build Coastguard Worker 
4614*5e7646d2SAndroid Build Coastguard Worker     while (cupsFileGets(dst, buffer, sizeof(buffer)))
4615*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(buffer, "*Default", 8))
4616*5e7646d2SAndroid Build Coastguard Worker       {
4617*5e7646d2SAndroid Build Coastguard Worker        /*
4618*5e7646d2SAndroid Build Coastguard Worker 	* Add the default option...
4619*5e7646d2SAndroid Build Coastguard Worker 	*/
4620*5e7646d2SAndroid Build Coastguard Worker 
4621*5e7646d2SAndroid Build Coastguard Worker         if (!ppd_parse_line(buffer, option, sizeof(option),
4622*5e7646d2SAndroid Build Coastguard Worker 	                    choice, sizeof(choice)))
4623*5e7646d2SAndroid Build Coastguard Worker         {
4624*5e7646d2SAndroid Build Coastguard Worker 	  ppd_option_t	*ppdo;		/* PPD option */
4625*5e7646d2SAndroid Build Coastguard Worker 
4626*5e7646d2SAndroid Build Coastguard Worker 
4627*5e7646d2SAndroid Build Coastguard Worker          /*
4628*5e7646d2SAndroid Build Coastguard Worker 	  * Only add the default if the default hasn't already been
4629*5e7646d2SAndroid Build Coastguard Worker 	  * set and the choice exists in the new PPD...
4630*5e7646d2SAndroid Build Coastguard Worker 	  */
4631*5e7646d2SAndroid Build Coastguard Worker 
4632*5e7646d2SAndroid Build Coastguard Worker 	  if (!cupsGetOption(option, num_defaults, defaults) &&
4633*5e7646d2SAndroid Build Coastguard Worker 	      (ppdo = ppdFindOption(ppd, option)) != NULL &&
4634*5e7646d2SAndroid Build Coastguard Worker 	      ppdFindChoice(ppdo, choice))
4635*5e7646d2SAndroid Build Coastguard Worker             num_defaults = cupsAddOption(option, choice, num_defaults,
4636*5e7646d2SAndroid Build Coastguard Worker 	                                 &defaults);
4637*5e7646d2SAndroid Build Coastguard Worker         }
4638*5e7646d2SAndroid Build Coastguard Worker       }
4639*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(buffer, "*cupsProtocol:", 14))
4640*5e7646d2SAndroid Build Coastguard Worker         strlcpy(cups_protocol, buffer, sizeof(cups_protocol));
4641*5e7646d2SAndroid Build Coastguard Worker 
4642*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(dst);
4643*5e7646d2SAndroid Build Coastguard Worker   }
4644*5e7646d2SAndroid Build Coastguard Worker   else if ((size = ppdPageSize(ppd, DefaultPaperSize)) != NULL)
4645*5e7646d2SAndroid Build Coastguard Worker   {
4646*5e7646d2SAndroid Build Coastguard Worker    /*
4647*5e7646d2SAndroid Build Coastguard Worker     * Add the default media sizes...
4648*5e7646d2SAndroid Build Coastguard Worker     */
4649*5e7646d2SAndroid Build Coastguard Worker 
4650*5e7646d2SAndroid Build Coastguard Worker     num_defaults = cupsAddOption("PageSize", size->name,
4651*5e7646d2SAndroid Build Coastguard Worker                                  num_defaults, &defaults);
4652*5e7646d2SAndroid Build Coastguard Worker     num_defaults = cupsAddOption("PageRegion", size->name,
4653*5e7646d2SAndroid Build Coastguard Worker                                  num_defaults, &defaults);
4654*5e7646d2SAndroid Build Coastguard Worker     num_defaults = cupsAddOption("PaperDimension", size->name,
4655*5e7646d2SAndroid Build Coastguard Worker                                  num_defaults, &defaults);
4656*5e7646d2SAndroid Build Coastguard Worker     num_defaults = cupsAddOption("ImageableArea", size->name,
4657*5e7646d2SAndroid Build Coastguard Worker                                  num_defaults, &defaults);
4658*5e7646d2SAndroid Build Coastguard Worker   }
4659*5e7646d2SAndroid Build Coastguard Worker 
4660*5e7646d2SAndroid Build Coastguard Worker   ppdClose(ppd);
4661*5e7646d2SAndroid Build Coastguard Worker 
4662*5e7646d2SAndroid Build Coastguard Worker  /*
4663*5e7646d2SAndroid Build Coastguard Worker   * Open the destination file for a copy...
4664*5e7646d2SAndroid Build Coastguard Worker   */
4665*5e7646d2SAndroid Build Coastguard Worker 
4666*5e7646d2SAndroid Build Coastguard Worker   if ((dst = cupsdCreateConfFile(to, ConfigFilePerm)) == NULL)
4667*5e7646d2SAndroid Build Coastguard Worker   {
4668*5e7646d2SAndroid Build Coastguard Worker     cupsFreeOptions(num_defaults, defaults);
4669*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(src);
4670*5e7646d2SAndroid Build Coastguard Worker     unlink(tempfile);
4671*5e7646d2SAndroid Build Coastguard Worker     return (-1);
4672*5e7646d2SAndroid Build Coastguard Worker   }
4673*5e7646d2SAndroid Build Coastguard Worker 
4674*5e7646d2SAndroid Build Coastguard Worker  /*
4675*5e7646d2SAndroid Build Coastguard Worker   * Copy the source file to the destination...
4676*5e7646d2SAndroid Build Coastguard Worker   */
4677*5e7646d2SAndroid Build Coastguard Worker 
4678*5e7646d2SAndroid Build Coastguard Worker   cupsFileRewind(src);
4679*5e7646d2SAndroid Build Coastguard Worker 
4680*5e7646d2SAndroid Build Coastguard Worker   while (cupsFileGets(src, buffer, sizeof(buffer)))
4681*5e7646d2SAndroid Build Coastguard Worker   {
4682*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(buffer, "*Default", 8))
4683*5e7646d2SAndroid Build Coastguard Worker     {
4684*5e7646d2SAndroid Build Coastguard Worker      /*
4685*5e7646d2SAndroid Build Coastguard Worker       * Check for an previous default option choice...
4686*5e7646d2SAndroid Build Coastguard Worker       */
4687*5e7646d2SAndroid Build Coastguard Worker 
4688*5e7646d2SAndroid Build Coastguard Worker       if (!ppd_parse_line(buffer, option, sizeof(option),
4689*5e7646d2SAndroid Build Coastguard Worker 	                  choice, sizeof(choice)))
4690*5e7646d2SAndroid Build Coastguard Worker       {
4691*5e7646d2SAndroid Build Coastguard Worker         const char	*val;		/* Default option value */
4692*5e7646d2SAndroid Build Coastguard Worker 
4693*5e7646d2SAndroid Build Coastguard Worker 
4694*5e7646d2SAndroid Build Coastguard Worker         if ((val = cupsGetOption(option, num_defaults, defaults)) != NULL)
4695*5e7646d2SAndroid Build Coastguard Worker 	{
4696*5e7646d2SAndroid Build Coastguard Worker 	 /*
4697*5e7646d2SAndroid Build Coastguard Worker 	  * Substitute the previous choice...
4698*5e7646d2SAndroid Build Coastguard Worker 	  */
4699*5e7646d2SAndroid Build Coastguard Worker 
4700*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, val);
4701*5e7646d2SAndroid Build Coastguard Worker 	}
4702*5e7646d2SAndroid Build Coastguard Worker       }
4703*5e7646d2SAndroid Build Coastguard Worker     }
4704*5e7646d2SAndroid Build Coastguard Worker 
4705*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(dst, "%s\n", buffer);
4706*5e7646d2SAndroid Build Coastguard Worker   }
4707*5e7646d2SAndroid Build Coastguard Worker 
4708*5e7646d2SAndroid Build Coastguard Worker   if (cups_protocol[0])
4709*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(dst, "%s\n", cups_protocol);
4710*5e7646d2SAndroid Build Coastguard Worker 
4711*5e7646d2SAndroid Build Coastguard Worker   cupsFreeOptions(num_defaults, defaults);
4712*5e7646d2SAndroid Build Coastguard Worker 
4713*5e7646d2SAndroid Build Coastguard Worker  /*
4714*5e7646d2SAndroid Build Coastguard Worker   * Close both files and return...
4715*5e7646d2SAndroid Build Coastguard Worker   */
4716*5e7646d2SAndroid Build Coastguard Worker 
4717*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(src);
4718*5e7646d2SAndroid Build Coastguard Worker 
4719*5e7646d2SAndroid Build Coastguard Worker   unlink(tempfile);
4720*5e7646d2SAndroid Build Coastguard Worker 
4721*5e7646d2SAndroid Build Coastguard Worker   return (cupsdCloseCreatedConfFile(dst, to));
4722*5e7646d2SAndroid Build Coastguard Worker }
4723*5e7646d2SAndroid Build Coastguard Worker 
4724*5e7646d2SAndroid Build Coastguard Worker 
4725*5e7646d2SAndroid Build Coastguard Worker /*
4726*5e7646d2SAndroid Build Coastguard Worker  * 'copy_job_attrs()' - Copy job attributes.
4727*5e7646d2SAndroid Build Coastguard Worker  */
4728*5e7646d2SAndroid Build Coastguard Worker 
4729*5e7646d2SAndroid Build Coastguard Worker static void
copy_job_attrs(cupsd_client_t * con,cupsd_job_t * job,cups_array_t * ra,cups_array_t * exclude)4730*5e7646d2SAndroid Build Coastguard Worker copy_job_attrs(cupsd_client_t *con,	/* I - Client connection */
4731*5e7646d2SAndroid Build Coastguard Worker 	       cupsd_job_t    *job,	/* I - Job */
4732*5e7646d2SAndroid Build Coastguard Worker 	       cups_array_t   *ra,	/* I - Requested attributes array */
4733*5e7646d2SAndroid Build Coastguard Worker 	       cups_array_t   *exclude)	/* I - Private attributes array */
4734*5e7646d2SAndroid Build Coastguard Worker {
4735*5e7646d2SAndroid Build Coastguard Worker   char	job_uri[HTTP_MAX_URI];		/* Job URI */
4736*5e7646d2SAndroid Build Coastguard Worker 
4737*5e7646d2SAndroid Build Coastguard Worker 
4738*5e7646d2SAndroid Build Coastguard Worker  /*
4739*5e7646d2SAndroid Build Coastguard Worker   * Send the requested attributes for each job...
4740*5e7646d2SAndroid Build Coastguard Worker   */
4741*5e7646d2SAndroid Build Coastguard Worker 
4742*5e7646d2SAndroid Build Coastguard Worker   if (!cupsArrayFind(exclude, "all"))
4743*5e7646d2SAndroid Build Coastguard Worker   {
4744*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "number-of-documents")) &&
4745*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "number-of-documents")))
4746*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4747*5e7646d2SAndroid Build Coastguard Worker 		    "number-of-documents", job->num_files);
4748*5e7646d2SAndroid Build Coastguard Worker 
4749*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) &&
4750*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "job-media-progress")))
4751*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4752*5e7646d2SAndroid Build Coastguard Worker 		    "job-media-progress", job->progress);
4753*5e7646d2SAndroid Build Coastguard Worker 
4754*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) &&
4755*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "job-more-info")))
4756*5e7646d2SAndroid Build Coastguard Worker     {
4757*5e7646d2SAndroid Build Coastguard Worker       httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "http",
4758*5e7646d2SAndroid Build Coastguard Worker                        NULL, con->clientname, con->clientport, "/jobs/%d",
4759*5e7646d2SAndroid Build Coastguard Worker 		       job->id);
4760*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4761*5e7646d2SAndroid Build Coastguard Worker 		   "job-more-info", NULL, job_uri);
4762*5e7646d2SAndroid Build Coastguard Worker     }
4763*5e7646d2SAndroid Build Coastguard Worker 
4764*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value > IPP_JOB_PROCESSING &&
4765*5e7646d2SAndroid Build Coastguard Worker 	(!exclude || !cupsArrayFind(exclude, "job-preserved")) &&
4766*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "job-preserved")))
4767*5e7646d2SAndroid Build Coastguard Worker       ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
4768*5e7646d2SAndroid Build Coastguard Worker 		    job->num_files > 0);
4769*5e7646d2SAndroid Build Coastguard Worker 
4770*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) &&
4771*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "job-printer-up-time")))
4772*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
4773*5e7646d2SAndroid Build Coastguard Worker 		    "job-printer-up-time", time(NULL));
4774*5e7646d2SAndroid Build Coastguard Worker   }
4775*5e7646d2SAndroid Build Coastguard Worker 
4776*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "job-printer-uri"))
4777*5e7646d2SAndroid Build Coastguard Worker   {
4778*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4779*5e7646d2SAndroid Build Coastguard Worker 		     con->clientname, con->clientport,
4780*5e7646d2SAndroid Build Coastguard Worker 		     (job->dtype & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4781*5e7646d2SAndroid Build Coastguard Worker 		                                         "/printers/%s",
4782*5e7646d2SAndroid Build Coastguard Worker 		     job->dest);
4783*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4784*5e7646d2SAndroid Build Coastguard Worker         	 "job-printer-uri", NULL, job_uri);
4785*5e7646d2SAndroid Build Coastguard Worker   }
4786*5e7646d2SAndroid Build Coastguard Worker 
4787*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "job-uri"))
4788*5e7646d2SAndroid Build Coastguard Worker   {
4789*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
4790*5e7646d2SAndroid Build Coastguard Worker 		     con->clientname, con->clientport, "/jobs/%d",
4791*5e7646d2SAndroid Build Coastguard Worker 		     job->id);
4792*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
4793*5e7646d2SAndroid Build Coastguard Worker         	 "job-uri", NULL, job_uri);
4794*5e7646d2SAndroid Build Coastguard Worker   }
4795*5e7646d2SAndroid Build Coastguard Worker 
4796*5e7646d2SAndroid Build Coastguard Worker   if (job->attrs)
4797*5e7646d2SAndroid Build Coastguard Worker   {
4798*5e7646d2SAndroid Build Coastguard Worker     copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
4799*5e7646d2SAndroid Build Coastguard Worker   }
4800*5e7646d2SAndroid Build Coastguard Worker   else
4801*5e7646d2SAndroid Build Coastguard Worker   {
4802*5e7646d2SAndroid Build Coastguard Worker    /*
4803*5e7646d2SAndroid Build Coastguard Worker     * Generate attributes from the job structure...
4804*5e7646d2SAndroid Build Coastguard Worker     */
4805*5e7646d2SAndroid Build Coastguard Worker 
4806*5e7646d2SAndroid Build Coastguard Worker     if (job->completed_time && (!ra || cupsArrayFind(ra, "date-time-at-completed")))
4807*5e7646d2SAndroid Build Coastguard Worker       ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed_time));
4808*5e7646d2SAndroid Build Coastguard Worker 
4809*5e7646d2SAndroid Build Coastguard Worker     if (job->creation_time && (!ra || cupsArrayFind(ra, "date-time-at-creation")))
4810*5e7646d2SAndroid Build Coastguard Worker       ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(job->creation_time));
4811*5e7646d2SAndroid Build Coastguard Worker 
4812*5e7646d2SAndroid Build Coastguard Worker     if (!ra || cupsArrayFind(ra, "job-id"))
4813*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
4814*5e7646d2SAndroid Build Coastguard Worker 
4815*5e7646d2SAndroid Build Coastguard Worker     if (!ra || cupsArrayFind(ra, "job-k-octets"))
4816*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets);
4817*5e7646d2SAndroid Build Coastguard Worker 
4818*5e7646d2SAndroid Build Coastguard Worker     if (job->name && (!ra || cupsArrayFind(ra, "job-name")))
4819*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, job->name);
4820*5e7646d2SAndroid Build Coastguard Worker 
4821*5e7646d2SAndroid Build Coastguard Worker     if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name")))
4822*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username);
4823*5e7646d2SAndroid Build Coastguard Worker 
4824*5e7646d2SAndroid Build Coastguard Worker     if (!ra || cupsArrayFind(ra, "job-state"))
4825*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
4826*5e7646d2SAndroid Build Coastguard Worker 
4827*5e7646d2SAndroid Build Coastguard Worker     if (!ra || cupsArrayFind(ra, "job-state-reasons"))
4828*5e7646d2SAndroid Build Coastguard Worker     {
4829*5e7646d2SAndroid Build Coastguard Worker       switch (job->state_value)
4830*5e7646d2SAndroid Build Coastguard Worker       {
4831*5e7646d2SAndroid Build Coastguard Worker         default : /* Should never get here for processing, pending, held, or stopped jobs since they don't get unloaded... */
4832*5e7646d2SAndroid Build Coastguard Worker 	    break;
4833*5e7646d2SAndroid Build Coastguard Worker         case IPP_JSTATE_ABORTED :
4834*5e7646d2SAndroid Build Coastguard Worker 	    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-aborted-by-system");
4835*5e7646d2SAndroid Build Coastguard Worker 	    break;
4836*5e7646d2SAndroid Build Coastguard Worker         case IPP_JSTATE_CANCELED :
4837*5e7646d2SAndroid Build Coastguard Worker 	    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user");
4838*5e7646d2SAndroid Build Coastguard Worker 	    break;
4839*5e7646d2SAndroid Build Coastguard Worker         case IPP_JSTATE_COMPLETED :
4840*5e7646d2SAndroid Build Coastguard Worker 	    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully");
4841*5e7646d2SAndroid Build Coastguard Worker 	    break;
4842*5e7646d2SAndroid Build Coastguard Worker       }
4843*5e7646d2SAndroid Build Coastguard Worker     }
4844*5e7646d2SAndroid Build Coastguard Worker 
4845*5e7646d2SAndroid Build Coastguard Worker     if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-completed")))
4846*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-completed", (int)job->completed_time);
4847*5e7646d2SAndroid Build Coastguard Worker 
4848*5e7646d2SAndroid Build Coastguard Worker     if (job->creation_time && (!ra || cupsArrayFind(ra, "time-at-creation")))
4849*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)job->creation_time);
4850*5e7646d2SAndroid Build Coastguard Worker   }
4851*5e7646d2SAndroid Build Coastguard Worker }
4852*5e7646d2SAndroid Build Coastguard Worker 
4853*5e7646d2SAndroid Build Coastguard Worker 
4854*5e7646d2SAndroid Build Coastguard Worker /*
4855*5e7646d2SAndroid Build Coastguard Worker  * 'copy_printer_attrs()' - Copy printer attributes.
4856*5e7646d2SAndroid Build Coastguard Worker  */
4857*5e7646d2SAndroid Build Coastguard Worker 
4858*5e7646d2SAndroid Build Coastguard Worker static void
copy_printer_attrs(cupsd_client_t * con,cupsd_printer_t * printer,cups_array_t * ra)4859*5e7646d2SAndroid Build Coastguard Worker copy_printer_attrs(
4860*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
4861*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *printer,		/* I - Printer */
4862*5e7646d2SAndroid Build Coastguard Worker     cups_array_t    *ra)		/* I - Requested attributes array */
4863*5e7646d2SAndroid Build Coastguard Worker {
4864*5e7646d2SAndroid Build Coastguard Worker   char		uri[HTTP_MAX_URI];	/* URI value */
4865*5e7646d2SAndroid Build Coastguard Worker   time_t	curtime;		/* Current time */
4866*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
4867*5e7646d2SAndroid Build Coastguard Worker   int		is_encrypted = httpIsEncrypted(con->http);
4868*5e7646d2SAndroid Build Coastguard Worker 					/* Is the connection encrypted? */
4869*5e7646d2SAndroid Build Coastguard Worker 
4870*5e7646d2SAndroid Build Coastguard Worker 
4871*5e7646d2SAndroid Build Coastguard Worker  /*
4872*5e7646d2SAndroid Build Coastguard Worker   * Copy the printer attributes to the response using requested-attributes
4873*5e7646d2SAndroid Build Coastguard Worker   * and document-format attributes that may be provided by the client.
4874*5e7646d2SAndroid Build Coastguard Worker   */
4875*5e7646d2SAndroid Build Coastguard Worker 
4876*5e7646d2SAndroid Build Coastguard Worker   _cupsRWLockRead(&printer->lock);
4877*5e7646d2SAndroid Build Coastguard Worker 
4878*5e7646d2SAndroid Build Coastguard Worker   curtime = time(NULL);
4879*5e7646d2SAndroid Build Coastguard Worker 
4880*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "marker-change-time"))
4881*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "marker-change-time", printer->marker_time);
4882*5e7646d2SAndroid Build Coastguard Worker 
4883*5e7646d2SAndroid Build Coastguard Worker   if (printer->num_printers > 0 && (!ra || cupsArrayFind(ra, "member-uris")))
4884*5e7646d2SAndroid Build Coastguard Worker   {
4885*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t	*member_uris;	/* member-uris attribute */
4886*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t	*p2;		/* Printer in class */
4887*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t	*p2_uri;	/* printer-uri-supported for class printer */
4888*5e7646d2SAndroid Build Coastguard Worker 
4889*5e7646d2SAndroid Build Coastguard Worker 
4890*5e7646d2SAndroid Build Coastguard Worker     if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", printer->num_printers, NULL, NULL)) != NULL)
4891*5e7646d2SAndroid Build Coastguard Worker     {
4892*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < printer->num_printers; i ++)
4893*5e7646d2SAndroid Build Coastguard Worker       {
4894*5e7646d2SAndroid Build Coastguard Worker         p2 = printer->printers[i];
4895*5e7646d2SAndroid Build Coastguard Worker 
4896*5e7646d2SAndroid Build Coastguard Worker         if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", IPP_TAG_URI)) != NULL)
4897*5e7646d2SAndroid Build Coastguard Worker         {
4898*5e7646d2SAndroid Build Coastguard Worker           member_uris->values[i].string.text = _cupsStrAlloc(p2_uri->values[0].string.text);
4899*5e7646d2SAndroid Build Coastguard Worker         }
4900*5e7646d2SAndroid Build Coastguard Worker         else
4901*5e7646d2SAndroid Build Coastguard Worker 	{
4902*5e7646d2SAndroid Build Coastguard Worker 	  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (p2->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", p2->name);
4903*5e7646d2SAndroid Build Coastguard Worker 	  member_uris->values[i].string.text = _cupsStrAlloc(uri);
4904*5e7646d2SAndroid Build Coastguard Worker         }
4905*5e7646d2SAndroid Build Coastguard Worker       }
4906*5e7646d2SAndroid Build Coastguard Worker     }
4907*5e7646d2SAndroid Build Coastguard Worker   }
4908*5e7646d2SAndroid Build Coastguard Worker 
4909*5e7646d2SAndroid Build Coastguard Worker   if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert")))
4910*5e7646d2SAndroid Build Coastguard Worker     ippAddOctetString(con->response, IPP_TAG_PRINTER, "printer-alert", printer->alert, (int)strlen(printer->alert));
4911*5e7646d2SAndroid Build Coastguard Worker 
4912*5e7646d2SAndroid Build Coastguard Worker   if (printer->alert_description && (!ra || cupsArrayFind(ra, "printer-alert-description")))
4913*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-alert-description", NULL, printer->alert_description);
4914*5e7646d2SAndroid Build Coastguard Worker 
4915*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-config-change-date-time"))
4916*5e7646d2SAndroid Build Coastguard Worker     ippAddDate(con->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time));
4917*5e7646d2SAndroid Build Coastguard Worker 
4918*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-config-change-time"))
4919*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", printer->config_time);
4920*5e7646d2SAndroid Build Coastguard Worker 
4921*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-current-time"))
4922*5e7646d2SAndroid Build Coastguard Worker     ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(curtime));
4923*5e7646d2SAndroid Build Coastguard Worker 
4924*5e7646d2SAndroid Build Coastguard Worker #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
4925*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
4926*5e7646d2SAndroid Build Coastguard Worker   {
4927*5e7646d2SAndroid Build Coastguard Worker     if (printer->reg_name)
4928*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-dns-sd-name", NULL, printer->reg_name);
4929*5e7646d2SAndroid Build Coastguard Worker     else
4930*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "printer-dns-sd-name", 0);
4931*5e7646d2SAndroid Build Coastguard Worker   }
4932*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD || HAVE_AVAHI */
4933*5e7646d2SAndroid Build Coastguard Worker 
4934*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-error-policy"))
4935*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-error-policy", NULL, printer->error_policy);
4936*5e7646d2SAndroid Build Coastguard Worker 
4937*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-error-policy-supported"))
4938*5e7646d2SAndroid Build Coastguard Worker   {
4939*5e7646d2SAndroid Build Coastguard Worker     static const char * const errors[] =/* printer-error-policy-supported values */
4940*5e7646d2SAndroid Build Coastguard Worker     {
4941*5e7646d2SAndroid Build Coastguard Worker       "abort-job",
4942*5e7646d2SAndroid Build Coastguard Worker       "retry-current-job",
4943*5e7646d2SAndroid Build Coastguard Worker       "retry-job",
4944*5e7646d2SAndroid Build Coastguard Worker       "stop-printer"
4945*5e7646d2SAndroid Build Coastguard Worker     };
4946*5e7646d2SAndroid Build Coastguard Worker 
4947*5e7646d2SAndroid Build Coastguard Worker     if (printer->type & CUPS_PRINTER_CLASS)
4948*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", NULL, "retry-current-job");
4949*5e7646d2SAndroid Build Coastguard Worker     else
4950*5e7646d2SAndroid Build Coastguard Worker       ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors);
4951*5e7646d2SAndroid Build Coastguard Worker   }
4952*5e7646d2SAndroid Build Coastguard Worker 
4953*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-icons"))
4954*5e7646d2SAndroid Build Coastguard Worker   {
4955*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/icons/%s.png", printer->name);
4956*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, uri);
4957*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", uri);
4958*5e7646d2SAndroid Build Coastguard Worker   }
4959*5e7646d2SAndroid Build Coastguard Worker 
4960*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs"))
4961*5e7646d2SAndroid Build Coastguard Worker     ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
4962*5e7646d2SAndroid Build Coastguard Worker 
4963*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-is-shared"))
4964*5e7646d2SAndroid Build Coastguard Worker     ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", (char)printer->shared);
4965*5e7646d2SAndroid Build Coastguard Worker 
4966*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-is-temporary"))
4967*5e7646d2SAndroid Build Coastguard Worker     ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary);
4968*5e7646d2SAndroid Build Coastguard Worker 
4969*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-more-info"))
4970*5e7646d2SAndroid Build Coastguard Worker   {
4971*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
4972*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, uri);
4973*5e7646d2SAndroid Build Coastguard Worker   }
4974*5e7646d2SAndroid Build Coastguard Worker 
4975*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-op-policy"))
4976*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-op-policy", NULL, printer->op_policy);
4977*5e7646d2SAndroid Build Coastguard Worker 
4978*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-state"))
4979*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state);
4980*5e7646d2SAndroid Build Coastguard Worker 
4981*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-state-change-date-time"))
4982*5e7646d2SAndroid Build Coastguard Worker     ippAddDate(con->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time));
4983*5e7646d2SAndroid Build Coastguard Worker 
4984*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
4985*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", printer->state_time);
4986*5e7646d2SAndroid Build Coastguard Worker 
4987*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-state-message"))
4988*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", NULL, printer->state_message);
4989*5e7646d2SAndroid Build Coastguard Worker 
4990*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
4991*5e7646d2SAndroid Build Coastguard Worker     add_printer_state_reasons(con, printer);
4992*5e7646d2SAndroid Build Coastguard Worker 
4993*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-strings-uri"))
4994*5e7646d2SAndroid Build Coastguard Worker   {
4995*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", printer->name);
4996*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri);
4997*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-strings-uri=\"%s\"", uri);
4998*5e7646d2SAndroid Build Coastguard Worker   }
4999*5e7646d2SAndroid Build Coastguard Worker 
5000*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-type"))
5001*5e7646d2SAndroid Build Coastguard Worker   {
5002*5e7646d2SAndroid Build Coastguard Worker     cups_ptype_t type;			/* printer-type value */
5003*5e7646d2SAndroid Build Coastguard Worker 
5004*5e7646d2SAndroid Build Coastguard Worker    /*
5005*5e7646d2SAndroid Build Coastguard Worker     * Add the CUPS-specific printer-type attribute...
5006*5e7646d2SAndroid Build Coastguard Worker     */
5007*5e7646d2SAndroid Build Coastguard Worker 
5008*5e7646d2SAndroid Build Coastguard Worker     type = printer->type;
5009*5e7646d2SAndroid Build Coastguard Worker 
5010*5e7646d2SAndroid Build Coastguard Worker     if (printer == DefaultPrinter)
5011*5e7646d2SAndroid Build Coastguard Worker       type |= CUPS_PRINTER_DEFAULT;
5012*5e7646d2SAndroid Build Coastguard Worker 
5013*5e7646d2SAndroid Build Coastguard Worker     if (!printer->accepting)
5014*5e7646d2SAndroid Build Coastguard Worker       type |= CUPS_PRINTER_REJECTING;
5015*5e7646d2SAndroid Build Coastguard Worker 
5016*5e7646d2SAndroid Build Coastguard Worker     if (!printer->shared)
5017*5e7646d2SAndroid Build Coastguard Worker       type |= CUPS_PRINTER_NOT_SHARED;
5018*5e7646d2SAndroid Build Coastguard Worker 
5019*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", (int)type);
5020*5e7646d2SAndroid Build Coastguard Worker   }
5021*5e7646d2SAndroid Build Coastguard Worker 
5022*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-up-time"))
5023*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", curtime);
5024*5e7646d2SAndroid Build Coastguard Worker 
5025*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "printer-uri-supported"))
5026*5e7646d2SAndroid Build Coastguard Worker   {
5027*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
5028*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
5029*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", uri);
5030*5e7646d2SAndroid Build Coastguard Worker   }
5031*5e7646d2SAndroid Build Coastguard Worker 
5032*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "queued-job-count"))
5033*5e7646d2SAndroid Build Coastguard Worker     add_queued_job_count(con, printer);
5034*5e7646d2SAndroid Build Coastguard Worker 
5035*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "uri-security-supported"))
5036*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "uri-security-supported", NULL, is_encrypted ? "tls" : "none");
5037*5e7646d2SAndroid Build Coastguard Worker 
5038*5e7646d2SAndroid Build Coastguard Worker   copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL);
5039*5e7646d2SAndroid Build Coastguard Worker   if (printer->ppd_attrs)
5040*5e7646d2SAndroid Build Coastguard Worker     copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
5041*5e7646d2SAndroid Build Coastguard Worker   copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
5042*5e7646d2SAndroid Build Coastguard Worker 
5043*5e7646d2SAndroid Build Coastguard Worker   _cupsRWUnlock(&printer->lock);
5044*5e7646d2SAndroid Build Coastguard Worker }
5045*5e7646d2SAndroid Build Coastguard Worker 
5046*5e7646d2SAndroid Build Coastguard Worker 
5047*5e7646d2SAndroid Build Coastguard Worker /*
5048*5e7646d2SAndroid Build Coastguard Worker  * 'copy_subscription_attrs()' - Copy subscription attributes.
5049*5e7646d2SAndroid Build Coastguard Worker  */
5050*5e7646d2SAndroid Build Coastguard Worker 
5051*5e7646d2SAndroid Build Coastguard Worker static void
copy_subscription_attrs(cupsd_client_t * con,cupsd_subscription_t * sub,cups_array_t * ra,cups_array_t * exclude)5052*5e7646d2SAndroid Build Coastguard Worker copy_subscription_attrs(
5053*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t       *con,		/* I - Client connection */
5054*5e7646d2SAndroid Build Coastguard Worker     cupsd_subscription_t *sub,		/* I - Subscription */
5055*5e7646d2SAndroid Build Coastguard Worker     cups_array_t         *ra,		/* I - Requested attributes array */
5056*5e7646d2SAndroid Build Coastguard Worker     cups_array_t         *exclude)	/* I - Private attributes array */
5057*5e7646d2SAndroid Build Coastguard Worker {
5058*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
5059*5e7646d2SAndroid Build Coastguard Worker   char			printer_uri[HTTP_MAX_URI];
5060*5e7646d2SAndroid Build Coastguard Worker 					/* Printer URI */
5061*5e7646d2SAndroid Build Coastguard Worker   int			count;		/* Number of events */
5062*5e7646d2SAndroid Build Coastguard Worker   unsigned		mask;		/* Current event mask */
5063*5e7646d2SAndroid Build Coastguard Worker   const char		*name;		/* Current event name */
5064*5e7646d2SAndroid Build Coastguard Worker 
5065*5e7646d2SAndroid Build Coastguard Worker 
5066*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
5067*5e7646d2SAndroid Build Coastguard Worker                   "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)",
5068*5e7646d2SAndroid Build Coastguard Worker 		  con, sub, ra, exclude);
5069*5e7646d2SAndroid Build Coastguard Worker 
5070*5e7646d2SAndroid Build Coastguard Worker  /*
5071*5e7646d2SAndroid Build Coastguard Worker   * Copy the subscription attributes to the response using the
5072*5e7646d2SAndroid Build Coastguard Worker   * requested-attributes attribute that may be provided by the client.
5073*5e7646d2SAndroid Build Coastguard Worker   */
5074*5e7646d2SAndroid Build Coastguard Worker 
5075*5e7646d2SAndroid Build Coastguard Worker   if (!exclude || !cupsArrayFind(exclude, "all"))
5076*5e7646d2SAndroid Build Coastguard Worker   {
5077*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "notify-events")) &&
5078*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "notify-events")))
5079*5e7646d2SAndroid Build Coastguard Worker     {
5080*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events");
5081*5e7646d2SAndroid Build Coastguard Worker 
5082*5e7646d2SAndroid Build Coastguard Worker       if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
5083*5e7646d2SAndroid Build Coastguard Worker       {
5084*5e7646d2SAndroid Build Coastguard Worker        /*
5085*5e7646d2SAndroid Build Coastguard Worker 	* Simple event list...
5086*5e7646d2SAndroid Build Coastguard Worker 	*/
5087*5e7646d2SAndroid Build Coastguard Worker 
5088*5e7646d2SAndroid Build Coastguard Worker 	ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", NULL, name);
5089*5e7646d2SAndroid Build Coastguard Worker       }
5090*5e7646d2SAndroid Build Coastguard Worker       else
5091*5e7646d2SAndroid Build Coastguard Worker       {
5092*5e7646d2SAndroid Build Coastguard Worker        /*
5093*5e7646d2SAndroid Build Coastguard Worker 	* Complex event list...
5094*5e7646d2SAndroid Build Coastguard Worker 	*/
5095*5e7646d2SAndroid Build Coastguard Worker 
5096*5e7646d2SAndroid Build Coastguard Worker 	for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
5097*5e7646d2SAndroid Build Coastguard Worker 	  if (sub->mask & mask)
5098*5e7646d2SAndroid Build Coastguard Worker 	    count ++;
5099*5e7646d2SAndroid Build Coastguard Worker 
5100*5e7646d2SAndroid Build Coastguard Worker 	attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", count, NULL, NULL);
5101*5e7646d2SAndroid Build Coastguard Worker 
5102*5e7646d2SAndroid Build Coastguard Worker 	for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
5103*5e7646d2SAndroid Build Coastguard Worker 	  if (sub->mask & mask)
5104*5e7646d2SAndroid Build Coastguard Worker 	  {
5105*5e7646d2SAndroid Build Coastguard Worker 	    attr->values[count].string.text = (char *)cupsdEventName((cupsd_eventmask_t)mask);
5106*5e7646d2SAndroid Build Coastguard Worker 
5107*5e7646d2SAndroid Build Coastguard Worker 	    count ++;
5108*5e7646d2SAndroid Build Coastguard Worker 	  }
5109*5e7646d2SAndroid Build Coastguard Worker       }
5110*5e7646d2SAndroid Build Coastguard Worker     }
5111*5e7646d2SAndroid Build Coastguard Worker 
5112*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) &&
5113*5e7646d2SAndroid Build Coastguard Worker         (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))))
5114*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5115*5e7646d2SAndroid Build Coastguard Worker 		    "notify-lease-duration", sub->lease);
5116*5e7646d2SAndroid Build Coastguard Worker 
5117*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) &&
5118*5e7646d2SAndroid Build Coastguard Worker         (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))))
5119*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
5120*5e7646d2SAndroid Build Coastguard Worker 		   "notify-recipient-uri", NULL, sub->recipient);
5121*5e7646d2SAndroid Build Coastguard Worker     else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) &&
5122*5e7646d2SAndroid Build Coastguard Worker              (!ra || cupsArrayFind(ra, "notify-pull-method")))
5123*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
5124*5e7646d2SAndroid Build Coastguard Worker 		   "notify-pull-method", NULL, "ippget");
5125*5e7646d2SAndroid Build Coastguard Worker 
5126*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) &&
5127*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")))
5128*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
5129*5e7646d2SAndroid Build Coastguard Worker 		   "notify-subscriber-user-name", NULL, sub->owner);
5130*5e7646d2SAndroid Build Coastguard Worker 
5131*5e7646d2SAndroid Build Coastguard Worker     if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) &&
5132*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "notify-time-interval")))
5133*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5134*5e7646d2SAndroid Build Coastguard Worker 		    "notify-time-interval", sub->interval);
5135*5e7646d2SAndroid Build Coastguard Worker 
5136*5e7646d2SAndroid Build Coastguard Worker     if (sub->user_data_len > 0 &&
5137*5e7646d2SAndroid Build Coastguard Worker 	(!exclude || !cupsArrayFind(exclude, "notify-user-data")) &&
5138*5e7646d2SAndroid Build Coastguard Worker         (!ra || cupsArrayFind(ra, "notify-user-data")))
5139*5e7646d2SAndroid Build Coastguard Worker       ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
5140*5e7646d2SAndroid Build Coastguard Worker 			sub->user_data, sub->user_data_len);
5141*5e7646d2SAndroid Build Coastguard Worker   }
5142*5e7646d2SAndroid Build Coastguard Worker 
5143*5e7646d2SAndroid Build Coastguard Worker   if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id")))
5144*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5145*5e7646d2SAndroid Build Coastguard Worker                   "notify-job-id", sub->job->id);
5146*5e7646d2SAndroid Build Coastguard Worker 
5147*5e7646d2SAndroid Build Coastguard Worker   if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri")))
5148*5e7646d2SAndroid Build Coastguard Worker   {
5149*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
5150*5e7646d2SAndroid Build Coastguard Worker                      "ipp", NULL, con->clientname, con->clientport,
5151*5e7646d2SAndroid Build Coastguard Worker 		     "/printers/%s", sub->dest->name);
5152*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
5153*5e7646d2SAndroid Build Coastguard Worker         	 "notify-printer-uri", NULL, printer_uri);
5154*5e7646d2SAndroid Build Coastguard Worker   }
5155*5e7646d2SAndroid Build Coastguard Worker 
5156*5e7646d2SAndroid Build Coastguard Worker   if (!ra || cupsArrayFind(ra, "notify-subscription-id"))
5157*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5158*5e7646d2SAndroid Build Coastguard Worker                   "notify-subscription-id", sub->id);
5159*5e7646d2SAndroid Build Coastguard Worker }
5160*5e7646d2SAndroid Build Coastguard Worker 
5161*5e7646d2SAndroid Build Coastguard Worker 
5162*5e7646d2SAndroid Build Coastguard Worker /*
5163*5e7646d2SAndroid Build Coastguard Worker  * 'create_job()' - Print a file to a printer or class.
5164*5e7646d2SAndroid Build Coastguard Worker  */
5165*5e7646d2SAndroid Build Coastguard Worker 
5166*5e7646d2SAndroid Build Coastguard Worker static void
create_job(cupsd_client_t * con,ipp_attribute_t * uri)5167*5e7646d2SAndroid Build Coastguard Worker create_job(cupsd_client_t  *con,	/* I - Client connection */
5168*5e7646d2SAndroid Build Coastguard Worker 	   ipp_attribute_t *uri)	/* I - Printer URI */
5169*5e7646d2SAndroid Build Coastguard Worker {
5170*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
5171*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer */
5172*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* New job */
5173*5e7646d2SAndroid Build Coastguard Worker   static const char * const forbidden_attrs[] =
5174*5e7646d2SAndroid Build Coastguard Worker   {					/* List of forbidden attributes */
5175*5e7646d2SAndroid Build Coastguard Worker     "compression",
5176*5e7646d2SAndroid Build Coastguard Worker     "document-format",
5177*5e7646d2SAndroid Build Coastguard Worker     "document-name",
5178*5e7646d2SAndroid Build Coastguard Worker     "document-natural-language"
5179*5e7646d2SAndroid Build Coastguard Worker   };
5180*5e7646d2SAndroid Build Coastguard Worker 
5181*5e7646d2SAndroid Build Coastguard Worker 
5182*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con,
5183*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
5184*5e7646d2SAndroid Build Coastguard Worker 
5185*5e7646d2SAndroid Build Coastguard Worker  /*
5186*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
5187*5e7646d2SAndroid Build Coastguard Worker   */
5188*5e7646d2SAndroid Build Coastguard Worker 
5189*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
5190*5e7646d2SAndroid Build Coastguard Worker   {
5191*5e7646d2SAndroid Build Coastguard Worker    /*
5192*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
5193*5e7646d2SAndroid Build Coastguard Worker     */
5194*5e7646d2SAndroid Build Coastguard Worker 
5195*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
5196*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
5197*5e7646d2SAndroid Build Coastguard Worker     return;
5198*5e7646d2SAndroid Build Coastguard Worker   }
5199*5e7646d2SAndroid Build Coastguard Worker 
5200*5e7646d2SAndroid Build Coastguard Worker  /*
5201*5e7646d2SAndroid Build Coastguard Worker   * Check for invalid Create-Job attributes and log a warning or error depending
5202*5e7646d2SAndroid Build Coastguard Worker   * on whether cupsd is running in "strict conformance" mode...
5203*5e7646d2SAndroid Build Coastguard Worker   */
5204*5e7646d2SAndroid Build Coastguard Worker 
5205*5e7646d2SAndroid Build Coastguard Worker   for (i = 0;
5206*5e7646d2SAndroid Build Coastguard Worker        i < (int)(sizeof(forbidden_attrs) / sizeof(forbidden_attrs[0]));
5207*5e7646d2SAndroid Build Coastguard Worker        i ++)
5208*5e7646d2SAndroid Build Coastguard Worker     if (ippFindAttribute(con->request, forbidden_attrs[i], IPP_TAG_ZERO))
5209*5e7646d2SAndroid Build Coastguard Worker     {
5210*5e7646d2SAndroid Build Coastguard Worker       if (StrictConformance)
5211*5e7646d2SAndroid Build Coastguard Worker       {
5212*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_BAD_REQUEST,
5213*5e7646d2SAndroid Build Coastguard Worker 			_("The '%s' operation attribute cannot be supplied in a "
5214*5e7646d2SAndroid Build Coastguard Worker 			  "Create-Job request."), forbidden_attrs[i]);
5215*5e7646d2SAndroid Build Coastguard Worker 	return;
5216*5e7646d2SAndroid Build Coastguard Worker       }
5217*5e7646d2SAndroid Build Coastguard Worker 
5218*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_WARN,
5219*5e7646d2SAndroid Build Coastguard Worker                       "Unexpected '%s' operation attribute in a Create-Job "
5220*5e7646d2SAndroid Build Coastguard Worker                       "request.", forbidden_attrs[i]);
5221*5e7646d2SAndroid Build Coastguard Worker     }
5222*5e7646d2SAndroid Build Coastguard Worker 
5223*5e7646d2SAndroid Build Coastguard Worker  /*
5224*5e7646d2SAndroid Build Coastguard Worker   * Create the job object...
5225*5e7646d2SAndroid Build Coastguard Worker   */
5226*5e7646d2SAndroid Build Coastguard Worker 
5227*5e7646d2SAndroid Build Coastguard Worker   if ((job = add_job(con, printer, NULL)) == NULL)
5228*5e7646d2SAndroid Build Coastguard Worker     return;
5229*5e7646d2SAndroid Build Coastguard Worker 
5230*5e7646d2SAndroid Build Coastguard Worker   job->pending_timeout = 1;
5231*5e7646d2SAndroid Build Coastguard Worker 
5232*5e7646d2SAndroid Build Coastguard Worker  /*
5233*5e7646d2SAndroid Build Coastguard Worker   * Save and log the job...
5234*5e7646d2SAndroid Build Coastguard Worker   */
5235*5e7646d2SAndroid Build Coastguard Worker 
5236*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
5237*5e7646d2SAndroid Build Coastguard Worker 	      job->dest, job->username);
5238*5e7646d2SAndroid Build Coastguard Worker }
5239*5e7646d2SAndroid Build Coastguard Worker 
5240*5e7646d2SAndroid Build Coastguard Worker 
5241*5e7646d2SAndroid Build Coastguard Worker /*
5242*5e7646d2SAndroid Build Coastguard Worker  * 'create_local_bg_thread()' - Background thread for creating a local print queue.
5243*5e7646d2SAndroid Build Coastguard Worker  */
5244*5e7646d2SAndroid Build Coastguard Worker 
5245*5e7646d2SAndroid Build Coastguard Worker static void *				/* O - Exit status */
create_local_bg_thread(cupsd_printer_t * printer)5246*5e7646d2SAndroid Build Coastguard Worker create_local_bg_thread(
5247*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *printer)		/* I - Printer */
5248*5e7646d2SAndroid Build Coastguard Worker {
5249*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*from,			/* Source file */
5250*5e7646d2SAndroid Build Coastguard Worker 		*to;			/* Destination file */
5251*5e7646d2SAndroid Build Coastguard Worker   char		fromppd[1024],		/* Source PPD */
5252*5e7646d2SAndroid Build Coastguard Worker 		toppd[1024],		/* Destination PPD */
5253*5e7646d2SAndroid Build Coastguard Worker 		scheme[32],		/* URI scheme */
5254*5e7646d2SAndroid Build Coastguard Worker 		userpass[256],		/* User:pass */
5255*5e7646d2SAndroid Build Coastguard Worker 		host[256],		/* Hostname */
5256*5e7646d2SAndroid Build Coastguard Worker 		resource[1024],		/* Resource path */
5257*5e7646d2SAndroid Build Coastguard Worker 		line[1024];		/* Line from PPD */
5258*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port number */
5259*5e7646d2SAndroid Build Coastguard Worker   http_encryption_t encryption;		/* Type of encryption to use */
5260*5e7646d2SAndroid Build Coastguard Worker   http_t	*http;			/* Connection to printer */
5261*5e7646d2SAndroid Build Coastguard Worker   ipp_t		*request,		/* Request to printer */
5262*5e7646d2SAndroid Build Coastguard Worker 		*response;		/* Response from printer */
5263*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Attribute in response */
5264*5e7646d2SAndroid Build Coastguard Worker   ipp_status_t	status;			/* Status code */
5265*5e7646d2SAndroid Build Coastguard Worker   static const char * const pattrs[] =	/* Printer attributes we need */
5266*5e7646d2SAndroid Build Coastguard Worker   {
5267*5e7646d2SAndroid Build Coastguard Worker     "all",
5268*5e7646d2SAndroid Build Coastguard Worker     "media-col-database"
5269*5e7646d2SAndroid Build Coastguard Worker   };
5270*5e7646d2SAndroid Build Coastguard Worker 
5271*5e7646d2SAndroid Build Coastguard Worker 
5272*5e7646d2SAndroid Build Coastguard Worker  /*
5273*5e7646d2SAndroid Build Coastguard Worker   * Try connecting to the printer...
5274*5e7646d2SAndroid Build Coastguard Worker   */
5275*5e7646d2SAndroid Build Coastguard Worker 
5276*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri);
5277*5e7646d2SAndroid Build Coastguard Worker 
5278*5e7646d2SAndroid Build Coastguard Worker   if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
5279*5e7646d2SAndroid Build Coastguard Worker   {
5280*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri);
5281*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
5282*5e7646d2SAndroid Build Coastguard Worker   }
5283*5e7646d2SAndroid Build Coastguard Worker 
5284*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(scheme, "ipps") || port == 443)
5285*5e7646d2SAndroid Build Coastguard Worker     encryption = HTTP_ENCRYPTION_ALWAYS;
5286*5e7646d2SAndroid Build Coastguard Worker   else
5287*5e7646d2SAndroid Build Coastguard Worker     encryption = HTTP_ENCRYPTION_IF_REQUESTED;
5288*5e7646d2SAndroid Build Coastguard Worker 
5289*5e7646d2SAndroid Build Coastguard Worker   if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
5290*5e7646d2SAndroid Build Coastguard Worker   {
5291*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString());
5292*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
5293*5e7646d2SAndroid Build Coastguard Worker   }
5294*5e7646d2SAndroid Build Coastguard Worker 
5295*5e7646d2SAndroid Build Coastguard Worker  /*
5296*5e7646d2SAndroid Build Coastguard Worker   * Query the printer for its capabilities...
5297*5e7646d2SAndroid Build Coastguard Worker   */
5298*5e7646d2SAndroid Build Coastguard Worker 
5299*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port);
5300*5e7646d2SAndroid Build Coastguard Worker 
5301*5e7646d2SAndroid Build Coastguard Worker   request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
5302*5e7646d2SAndroid Build Coastguard Worker   ippSetVersion(request, 2, 0);
5303*5e7646d2SAndroid Build Coastguard Worker   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
5304*5e7646d2SAndroid Build Coastguard Worker   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
5305*5e7646d2SAndroid Build Coastguard Worker 
5306*5e7646d2SAndroid Build Coastguard Worker   response = cupsDoRequest(http, request, resource);
5307*5e7646d2SAndroid Build Coastguard Worker   status   = cupsLastError();
5308*5e7646d2SAndroid Build Coastguard Worker 
5309*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString());
5310*5e7646d2SAndroid Build Coastguard Worker 
5311*5e7646d2SAndroid Build Coastguard Worker   if (status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
5312*5e7646d2SAndroid Build Coastguard Worker   {
5313*5e7646d2SAndroid Build Coastguard Worker    /*
5314*5e7646d2SAndroid Build Coastguard Worker     * Try request using IPP/1.1, in case we are talking to an old CUPS server or
5315*5e7646d2SAndroid Build Coastguard Worker     * printer...
5316*5e7646d2SAndroid Build Coastguard Worker     */
5317*5e7646d2SAndroid Build Coastguard Worker 
5318*5e7646d2SAndroid Build Coastguard Worker     ippDelete(response);
5319*5e7646d2SAndroid Build Coastguard Worker 
5320*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Re-sending Get-Printer-Attributes request using IPP/1.1...", printer->name);
5321*5e7646d2SAndroid Build Coastguard Worker 
5322*5e7646d2SAndroid Build Coastguard Worker     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
5323*5e7646d2SAndroid Build Coastguard Worker     ippSetVersion(request, 1, 1);
5324*5e7646d2SAndroid Build Coastguard Worker     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
5325*5e7646d2SAndroid Build Coastguard Worker     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all");
5326*5e7646d2SAndroid Build Coastguard Worker 
5327*5e7646d2SAndroid Build Coastguard Worker     response = cupsDoRequest(http, request, resource);
5328*5e7646d2SAndroid Build Coastguard Worker 
5329*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: IPP/1.1 Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString());
5330*5e7646d2SAndroid Build Coastguard Worker   }
5331*5e7646d2SAndroid Build Coastguard Worker 
5332*5e7646d2SAndroid Build Coastguard Worker   // TODO: Grab printer icon file...
5333*5e7646d2SAndroid Build Coastguard Worker   httpClose(http);
5334*5e7646d2SAndroid Build Coastguard Worker 
5335*5e7646d2SAndroid Build Coastguard Worker  /*
5336*5e7646d2SAndroid Build Coastguard Worker   * Write the PPD for the queue...
5337*5e7646d2SAndroid Build Coastguard Worker   */
5338*5e7646d2SAndroid Build Coastguard Worker 
5339*5e7646d2SAndroid Build Coastguard Worker   if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response))
5340*5e7646d2SAndroid Build Coastguard Worker   {
5341*5e7646d2SAndroid Build Coastguard Worker     _cupsRWLockWrite(&printer->lock);
5342*5e7646d2SAndroid Build Coastguard Worker 
5343*5e7646d2SAndroid Build Coastguard Worker     if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
5344*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->info, ippGetString(attr, 0, NULL));
5345*5e7646d2SAndroid Build Coastguard Worker 
5346*5e7646d2SAndroid Build Coastguard Worker     if ((!printer->location || !*(printer->location)) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
5347*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->location, ippGetString(attr, 0, NULL));
5348*5e7646d2SAndroid Build Coastguard Worker 
5349*5e7646d2SAndroid Build Coastguard Worker     if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
5350*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL));
5351*5e7646d2SAndroid Build Coastguard Worker 
5352*5e7646d2SAndroid Build Coastguard Worker     _cupsRWUnlock(&printer->lock);
5353*5e7646d2SAndroid Build Coastguard Worker 
5354*5e7646d2SAndroid Build Coastguard Worker     if ((from = cupsFileOpen(fromppd, "r")) == NULL)
5355*5e7646d2SAndroid Build Coastguard Worker     {
5356*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno));
5357*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
5358*5e7646d2SAndroid Build Coastguard Worker     }
5359*5e7646d2SAndroid Build Coastguard Worker 
5360*5e7646d2SAndroid Build Coastguard Worker     snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name);
5361*5e7646d2SAndroid Build Coastguard Worker     if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL)
5362*5e7646d2SAndroid Build Coastguard Worker     {
5363*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno));
5364*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(from);
5365*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
5366*5e7646d2SAndroid Build Coastguard Worker     }
5367*5e7646d2SAndroid Build Coastguard Worker 
5368*5e7646d2SAndroid Build Coastguard Worker     while (cupsFileGets(from, line, sizeof(line)))
5369*5e7646d2SAndroid Build Coastguard Worker       cupsFilePrintf(to, "%s\n", line);
5370*5e7646d2SAndroid Build Coastguard Worker 
5371*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(from);
5372*5e7646d2SAndroid Build Coastguard Worker     if (!cupsdCloseCreatedConfFile(to, toppd))
5373*5e7646d2SAndroid Build Coastguard Worker     {
5374*5e7646d2SAndroid Build Coastguard Worker       printer->config_time = time(NULL);
5375*5e7646d2SAndroid Build Coastguard Worker       printer->state       = IPP_PSTATE_IDLE;
5376*5e7646d2SAndroid Build Coastguard Worker       printer->accepting   = 1;
5377*5e7646d2SAndroid Build Coastguard Worker 
5378*5e7646d2SAndroid Build Coastguard Worker       cupsdSetPrinterAttrs(printer);
5379*5e7646d2SAndroid Build Coastguard Worker 
5380*5e7646d2SAndroid Build Coastguard Worker       cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name);
5381*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name);
5382*5e7646d2SAndroid Build Coastguard Worker     }
5383*5e7646d2SAndroid Build Coastguard Worker   }
5384*5e7646d2SAndroid Build Coastguard Worker   else
5385*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsLastErrorString());
5386*5e7646d2SAndroid Build Coastguard Worker 
5387*5e7646d2SAndroid Build Coastguard Worker   return (NULL);
5388*5e7646d2SAndroid Build Coastguard Worker }
5389*5e7646d2SAndroid Build Coastguard Worker 
5390*5e7646d2SAndroid Build Coastguard Worker 
5391*5e7646d2SAndroid Build Coastguard Worker /*
5392*5e7646d2SAndroid Build Coastguard Worker  * 'create_local_printer()' - Create a local (temporary) print queue.
5393*5e7646d2SAndroid Build Coastguard Worker  */
5394*5e7646d2SAndroid Build Coastguard Worker 
5395*5e7646d2SAndroid Build Coastguard Worker static void
create_local_printer(cupsd_client_t * con)5396*5e7646d2SAndroid Build Coastguard Worker create_local_printer(
5397*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con)		/* I - Client connection */
5398*5e7646d2SAndroid Build Coastguard Worker {
5399*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *device_uri,		/* device-uri attribute */
5400*5e7646d2SAndroid Build Coastguard Worker 		*printer_geo_location,	/* printer-geo-location attribute */
5401*5e7646d2SAndroid Build Coastguard Worker 		*printer_info,		/* printer-info attribute */
5402*5e7646d2SAndroid Build Coastguard Worker 		*printer_location,	/* printer-location attribute */
5403*5e7646d2SAndroid Build Coastguard Worker 		*printer_name;		/* printer-name attribute */
5404*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* New printer */
5405*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
5406*5e7646d2SAndroid Build Coastguard Worker   char		name[128],		/* Sanitized printer name */
5407*5e7646d2SAndroid Build Coastguard Worker 		*nameptr,		/* Pointer into name */
5408*5e7646d2SAndroid Build Coastguard Worker 		uri[1024];		/* printer-uri-supported value */
5409*5e7646d2SAndroid Build Coastguard Worker   const char	*ptr;			/* Pointer into attribute value */
5410*5e7646d2SAndroid Build Coastguard Worker 
5411*5e7646d2SAndroid Build Coastguard Worker 
5412*5e7646d2SAndroid Build Coastguard Worker  /*
5413*5e7646d2SAndroid Build Coastguard Worker   * Require local access to create a local printer...
5414*5e7646d2SAndroid Build Coastguard Worker   */
5415*5e7646d2SAndroid Build Coastguard Worker 
5416*5e7646d2SAndroid Build Coastguard Worker   if (!httpAddrLocalhost(httpGetAddress(con->http)))
5417*5e7646d2SAndroid Build Coastguard Worker   {
5418*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer."));
5419*5e7646d2SAndroid Build Coastguard Worker     return;
5420*5e7646d2SAndroid Build Coastguard Worker   }
5421*5e7646d2SAndroid Build Coastguard Worker 
5422*5e7646d2SAndroid Build Coastguard Worker  /*
5423*5e7646d2SAndroid Build Coastguard Worker   * Check any other policy limits...
5424*5e7646d2SAndroid Build Coastguard Worker   */
5425*5e7646d2SAndroid Build Coastguard Worker 
5426*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
5427*5e7646d2SAndroid Build Coastguard Worker   {
5428*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
5429*5e7646d2SAndroid Build Coastguard Worker     return;
5430*5e7646d2SAndroid Build Coastguard Worker   }
5431*5e7646d2SAndroid Build Coastguard Worker 
5432*5e7646d2SAndroid Build Coastguard Worker  /*
5433*5e7646d2SAndroid Build Coastguard Worker   * Grab needed attributes...
5434*5e7646d2SAndroid Build Coastguard Worker   */
5435*5e7646d2SAndroid Build Coastguard Worker 
5436*5e7646d2SAndroid Build Coastguard Worker   if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME)
5437*5e7646d2SAndroid Build Coastguard Worker   {
5438*5e7646d2SAndroid Build Coastguard Worker     if (!printer_name)
5439*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name");
5440*5e7646d2SAndroid Build Coastguard Worker     else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER)
5441*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name");
5442*5e7646d2SAndroid Build Coastguard Worker     else
5443*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name");
5444*5e7646d2SAndroid Build Coastguard Worker 
5445*5e7646d2SAndroid Build Coastguard Worker     return;
5446*5e7646d2SAndroid Build Coastguard Worker   }
5447*5e7646d2SAndroid Build Coastguard Worker 
5448*5e7646d2SAndroid Build Coastguard Worker   for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++)
5449*5e7646d2SAndroid Build Coastguard Worker   {
5450*5e7646d2SAndroid Build Coastguard Worker    /*
5451*5e7646d2SAndroid Build Coastguard Worker     * Sanitize the printer name...
5452*5e7646d2SAndroid Build Coastguard Worker     */
5453*5e7646d2SAndroid Build Coastguard Worker 
5454*5e7646d2SAndroid Build Coastguard Worker     if (_cups_isalnum(*ptr))
5455*5e7646d2SAndroid Build Coastguard Worker       *nameptr++ = *ptr;
5456*5e7646d2SAndroid Build Coastguard Worker     else if (nameptr == name || nameptr[-1] != '_')
5457*5e7646d2SAndroid Build Coastguard Worker       *nameptr++ = '_';
5458*5e7646d2SAndroid Build Coastguard Worker   }
5459*5e7646d2SAndroid Build Coastguard Worker 
5460*5e7646d2SAndroid Build Coastguard Worker   *nameptr = '\0';
5461*5e7646d2SAndroid Build Coastguard Worker 
5462*5e7646d2SAndroid Build Coastguard Worker   if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI)
5463*5e7646d2SAndroid Build Coastguard Worker   {
5464*5e7646d2SAndroid Build Coastguard Worker     if (!device_uri)
5465*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri");
5466*5e7646d2SAndroid Build Coastguard Worker     else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER)
5467*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri");
5468*5e7646d2SAndroid Build Coastguard Worker     else
5469*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri");
5470*5e7646d2SAndroid Build Coastguard Worker 
5471*5e7646d2SAndroid Build Coastguard Worker     return;
5472*5e7646d2SAndroid Build Coastguard Worker   }
5473*5e7646d2SAndroid Build Coastguard Worker 
5474*5e7646d2SAndroid Build Coastguard Worker   printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI);
5475*5e7646d2SAndroid Build Coastguard Worker   printer_info         = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT);
5476*5e7646d2SAndroid Build Coastguard Worker   printer_location     = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT);
5477*5e7646d2SAndroid Build Coastguard Worker 
5478*5e7646d2SAndroid Build Coastguard Worker  /*
5479*5e7646d2SAndroid Build Coastguard Worker   * See if the printer already exists...
5480*5e7646d2SAndroid Build Coastguard Worker   */
5481*5e7646d2SAndroid Build Coastguard Worker 
5482*5e7646d2SAndroid Build Coastguard Worker   if ((printer = cupsdFindDest(name)) != NULL)
5483*5e7646d2SAndroid Build Coastguard Worker   {
5484*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name);
5485*5e7646d2SAndroid Build Coastguard Worker     goto add_printer_attributes;
5486*5e7646d2SAndroid Build Coastguard Worker   }
5487*5e7646d2SAndroid Build Coastguard Worker 
5488*5e7646d2SAndroid Build Coastguard Worker  /*
5489*5e7646d2SAndroid Build Coastguard Worker   * Create the printer...
5490*5e7646d2SAndroid Build Coastguard Worker   */
5491*5e7646d2SAndroid Build Coastguard Worker 
5492*5e7646d2SAndroid Build Coastguard Worker   if ((printer = cupsdAddPrinter(name)) == NULL)
5493*5e7646d2SAndroid Build Coastguard Worker   {
5494*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer."));
5495*5e7646d2SAndroid Build Coastguard Worker     return;
5496*5e7646d2SAndroid Build Coastguard Worker   }
5497*5e7646d2SAndroid Build Coastguard Worker 
5498*5e7646d2SAndroid Build Coastguard Worker   printer->shared    = 0;
5499*5e7646d2SAndroid Build Coastguard Worker   printer->temporary = 1;
5500*5e7646d2SAndroid Build Coastguard Worker 
5501*5e7646d2SAndroid Build Coastguard Worker   cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL));
5502*5e7646d2SAndroid Build Coastguard Worker 
5503*5e7646d2SAndroid Build Coastguard Worker   if (printer_geo_location)
5504*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL));
5505*5e7646d2SAndroid Build Coastguard Worker   if (printer_info)
5506*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL));
5507*5e7646d2SAndroid Build Coastguard Worker   if (printer_location)
5508*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL));
5509*5e7646d2SAndroid Build Coastguard Worker 
5510*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterAttrs(printer);
5511*5e7646d2SAndroid Build Coastguard Worker 
5512*5e7646d2SAndroid Build Coastguard Worker  /*
5513*5e7646d2SAndroid Build Coastguard Worker   * Run a background thread to create the PPD...
5514*5e7646d2SAndroid Build Coastguard Worker   */
5515*5e7646d2SAndroid Build Coastguard Worker 
5516*5e7646d2SAndroid Build Coastguard Worker   _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
5517*5e7646d2SAndroid Build Coastguard Worker 
5518*5e7646d2SAndroid Build Coastguard Worker  /*
5519*5e7646d2SAndroid Build Coastguard Worker   * Return printer attributes...
5520*5e7646d2SAndroid Build Coastguard Worker   */
5521*5e7646d2SAndroid Build Coastguard Worker 
5522*5e7646d2SAndroid Build Coastguard Worker   send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
5523*5e7646d2SAndroid Build Coastguard Worker 
5524*5e7646d2SAndroid Build Coastguard Worker   add_printer_attributes:
5525*5e7646d2SAndroid Build Coastguard Worker 
5526*5e7646d2SAndroid Build Coastguard Worker   ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
5527*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state);
5528*5e7646d2SAndroid Build Coastguard Worker   add_printer_state_reasons(con, printer);
5529*5e7646d2SAndroid Build Coastguard Worker 
5530*5e7646d2SAndroid Build Coastguard Worker   httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name);
5531*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
5532*5e7646d2SAndroid Build Coastguard Worker }
5533*5e7646d2SAndroid Build Coastguard Worker 
5534*5e7646d2SAndroid Build Coastguard Worker 
5535*5e7646d2SAndroid Build Coastguard Worker /*
5536*5e7646d2SAndroid Build Coastguard Worker  * 'create_requested_array()' - Create an array for the requested-attributes.
5537*5e7646d2SAndroid Build Coastguard Worker  */
5538*5e7646d2SAndroid Build Coastguard Worker 
5539*5e7646d2SAndroid Build Coastguard Worker static cups_array_t *			/* O - Array of attributes or NULL */
create_requested_array(ipp_t * request)5540*5e7646d2SAndroid Build Coastguard Worker create_requested_array(ipp_t *request)	/* I - IPP request */
5541*5e7646d2SAndroid Build Coastguard Worker {
5542*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*ra;		/* Requested attributes array */
5543*5e7646d2SAndroid Build Coastguard Worker 
5544*5e7646d2SAndroid Build Coastguard Worker 
5545*5e7646d2SAndroid Build Coastguard Worker  /*
5546*5e7646d2SAndroid Build Coastguard Worker   * Create the array for standard attributes...
5547*5e7646d2SAndroid Build Coastguard Worker   */
5548*5e7646d2SAndroid Build Coastguard Worker 
5549*5e7646d2SAndroid Build Coastguard Worker   ra = ippCreateRequestedArray(request);
5550*5e7646d2SAndroid Build Coastguard Worker 
5551*5e7646d2SAndroid Build Coastguard Worker  /*
5552*5e7646d2SAndroid Build Coastguard Worker   * Add CUPS defaults as needed...
5553*5e7646d2SAndroid Build Coastguard Worker   */
5554*5e7646d2SAndroid Build Coastguard Worker 
5555*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayFind(ra, "printer-defaults"))
5556*5e7646d2SAndroid Build Coastguard Worker   {
5557*5e7646d2SAndroid Build Coastguard Worker    /*
5558*5e7646d2SAndroid Build Coastguard Worker     * Include user-set defaults...
5559*5e7646d2SAndroid Build Coastguard Worker     */
5560*5e7646d2SAndroid Build Coastguard Worker 
5561*5e7646d2SAndroid Build Coastguard Worker     char	*name;			/* Option name */
5562*5e7646d2SAndroid Build Coastguard Worker 
5563*5e7646d2SAndroid Build Coastguard Worker     cupsArrayRemove(ra, "printer-defaults");
5564*5e7646d2SAndroid Build Coastguard Worker 
5565*5e7646d2SAndroid Build Coastguard Worker     for (name = (char *)cupsArrayFirst(CommonDefaults);
5566*5e7646d2SAndroid Build Coastguard Worker 	 name;
5567*5e7646d2SAndroid Build Coastguard Worker 	 name = (char *)cupsArrayNext(CommonDefaults))
5568*5e7646d2SAndroid Build Coastguard Worker       if (!cupsArrayFind(ra, name))
5569*5e7646d2SAndroid Build Coastguard Worker         cupsArrayAdd(ra, name);
5570*5e7646d2SAndroid Build Coastguard Worker   }
5571*5e7646d2SAndroid Build Coastguard Worker 
5572*5e7646d2SAndroid Build Coastguard Worker   return (ra);
5573*5e7646d2SAndroid Build Coastguard Worker }
5574*5e7646d2SAndroid Build Coastguard Worker 
5575*5e7646d2SAndroid Build Coastguard Worker 
5576*5e7646d2SAndroid Build Coastguard Worker /*
5577*5e7646d2SAndroid Build Coastguard Worker  * 'create_subscriptions()' - Create one or more notification subscriptions.
5578*5e7646d2SAndroid Build Coastguard Worker  */
5579*5e7646d2SAndroid Build Coastguard Worker 
5580*5e7646d2SAndroid Build Coastguard Worker static void
create_subscriptions(cupsd_client_t * con,ipp_attribute_t * uri)5581*5e7646d2SAndroid Build Coastguard Worker create_subscriptions(
5582*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
5583*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t *uri)		/* I - Printer URI */
5584*5e7646d2SAndroid Build Coastguard Worker {
5585*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
5586*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
5587*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
5588*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
5589*5e7646d2SAndroid Build Coastguard Worker   char			scheme[HTTP_MAX_URI],
5590*5e7646d2SAndroid Build Coastguard Worker 					/* Scheme portion of URI */
5591*5e7646d2SAndroid Build Coastguard Worker 			userpass[HTTP_MAX_URI],
5592*5e7646d2SAndroid Build Coastguard Worker 					/* Username portion of URI */
5593*5e7646d2SAndroid Build Coastguard Worker 			host[HTTP_MAX_URI],
5594*5e7646d2SAndroid Build Coastguard Worker 					/* Host portion of URI */
5595*5e7646d2SAndroid Build Coastguard Worker 			resource[HTTP_MAX_URI];
5596*5e7646d2SAndroid Build Coastguard Worker 					/* Resource portion of URI */
5597*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port portion of URI */
5598*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer/class */
5599*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Job */
5600*5e7646d2SAndroid Build Coastguard Worker   int			jobid;		/* Job ID */
5601*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription object */
5602*5e7646d2SAndroid Build Coastguard Worker   const char		*username,	/* requesting-user-name or
5603*5e7646d2SAndroid Build Coastguard Worker 					   authenticated username */
5604*5e7646d2SAndroid Build Coastguard Worker 			*recipient,	/* notify-recipient-uri */
5605*5e7646d2SAndroid Build Coastguard Worker 			*pullmethod;	/* notify-pull-method */
5606*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*user_data;	/* notify-user-data */
5607*5e7646d2SAndroid Build Coastguard Worker   int			interval,	/* notify-time-interval */
5608*5e7646d2SAndroid Build Coastguard Worker 			lease;		/* notify-lease-duration */
5609*5e7646d2SAndroid Build Coastguard Worker   unsigned		mask;		/* notify-events */
5610*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*notify_events,/* notify-events(-default) */
5611*5e7646d2SAndroid Build Coastguard Worker 			*notify_lease;	/* notify-lease-duration(-default) */
5612*5e7646d2SAndroid Build Coastguard Worker 
5613*5e7646d2SAndroid Build Coastguard Worker 
5614*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
5615*5e7646d2SAndroid Build Coastguard Worker   for (attr = con->request->attrs; attr; attr = attr->next)
5616*5e7646d2SAndroid Build Coastguard Worker   {
5617*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag != IPP_TAG_ZERO)
5618*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG2, "g%04x v%04x %s", attr->group_tag,
5619*5e7646d2SAndroid Build Coastguard Worker                       attr->value_tag, attr->name);
5620*5e7646d2SAndroid Build Coastguard Worker     else
5621*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG2, "----SEP----");
5622*5e7646d2SAndroid Build Coastguard Worker   }
5623*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
5624*5e7646d2SAndroid Build Coastguard Worker 
5625*5e7646d2SAndroid Build Coastguard Worker  /*
5626*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
5627*5e7646d2SAndroid Build Coastguard Worker   */
5628*5e7646d2SAndroid Build Coastguard Worker 
5629*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "create_subscriptions(con=%p(%d), uri=\"%s\")", con, con->number, uri->values[0].string.text);
5630*5e7646d2SAndroid Build Coastguard Worker 
5631*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
5632*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), userpass, sizeof(userpass), host,
5633*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
5634*5e7646d2SAndroid Build Coastguard Worker 
5635*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(resource, "/"))
5636*5e7646d2SAndroid Build Coastguard Worker   {
5637*5e7646d2SAndroid Build Coastguard Worker     dtype   = (cups_ptype_t)0;
5638*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
5639*5e7646d2SAndroid Build Coastguard Worker   }
5640*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
5641*5e7646d2SAndroid Build Coastguard Worker   {
5642*5e7646d2SAndroid Build Coastguard Worker     dtype   = (cups_ptype_t)0;
5643*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
5644*5e7646d2SAndroid Build Coastguard Worker   }
5645*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
5646*5e7646d2SAndroid Build Coastguard Worker   {
5647*5e7646d2SAndroid Build Coastguard Worker     dtype   = CUPS_PRINTER_CLASS;
5648*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
5649*5e7646d2SAndroid Build Coastguard Worker   }
5650*5e7646d2SAndroid Build Coastguard Worker   else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
5651*5e7646d2SAndroid Build Coastguard Worker   {
5652*5e7646d2SAndroid Build Coastguard Worker    /*
5653*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
5654*5e7646d2SAndroid Build Coastguard Worker     */
5655*5e7646d2SAndroid Build Coastguard Worker 
5656*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
5657*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
5658*5e7646d2SAndroid Build Coastguard Worker     return;
5659*5e7646d2SAndroid Build Coastguard Worker   }
5660*5e7646d2SAndroid Build Coastguard Worker 
5661*5e7646d2SAndroid Build Coastguard Worker  /*
5662*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
5663*5e7646d2SAndroid Build Coastguard Worker   */
5664*5e7646d2SAndroid Build Coastguard Worker 
5665*5e7646d2SAndroid Build Coastguard Worker   if (printer)
5666*5e7646d2SAndroid Build Coastguard Worker   {
5667*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
5668*5e7646d2SAndroid Build Coastguard Worker                                    NULL)) != HTTP_OK)
5669*5e7646d2SAndroid Build Coastguard Worker     {
5670*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, printer);
5671*5e7646d2SAndroid Build Coastguard Worker       return;
5672*5e7646d2SAndroid Build Coastguard Worker     }
5673*5e7646d2SAndroid Build Coastguard Worker   }
5674*5e7646d2SAndroid Build Coastguard Worker   else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
5675*5e7646d2SAndroid Build Coastguard Worker   {
5676*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
5677*5e7646d2SAndroid Build Coastguard Worker     return;
5678*5e7646d2SAndroid Build Coastguard Worker   }
5679*5e7646d2SAndroid Build Coastguard Worker 
5680*5e7646d2SAndroid Build Coastguard Worker  /*
5681*5e7646d2SAndroid Build Coastguard Worker   * Get the user that is requesting the subscription...
5682*5e7646d2SAndroid Build Coastguard Worker   */
5683*5e7646d2SAndroid Build Coastguard Worker 
5684*5e7646d2SAndroid Build Coastguard Worker   username = get_username(con);
5685*5e7646d2SAndroid Build Coastguard Worker 
5686*5e7646d2SAndroid Build Coastguard Worker  /*
5687*5e7646d2SAndroid Build Coastguard Worker   * Find the first subscription group attribute; return if we have
5688*5e7646d2SAndroid Build Coastguard Worker   * none...
5689*5e7646d2SAndroid Build Coastguard Worker   */
5690*5e7646d2SAndroid Build Coastguard Worker 
5691*5e7646d2SAndroid Build Coastguard Worker   for (attr = con->request->attrs; attr; attr = attr->next)
5692*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
5693*5e7646d2SAndroid Build Coastguard Worker       break;
5694*5e7646d2SAndroid Build Coastguard Worker 
5695*5e7646d2SAndroid Build Coastguard Worker   if (!attr)
5696*5e7646d2SAndroid Build Coastguard Worker   {
5697*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
5698*5e7646d2SAndroid Build Coastguard Worker                     _("No subscription attributes in request."));
5699*5e7646d2SAndroid Build Coastguard Worker     return;
5700*5e7646d2SAndroid Build Coastguard Worker   }
5701*5e7646d2SAndroid Build Coastguard Worker 
5702*5e7646d2SAndroid Build Coastguard Worker  /*
5703*5e7646d2SAndroid Build Coastguard Worker   * Process the subscription attributes in the request...
5704*5e7646d2SAndroid Build Coastguard Worker   */
5705*5e7646d2SAndroid Build Coastguard Worker 
5706*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_BAD_REQUEST;
5707*5e7646d2SAndroid Build Coastguard Worker 
5708*5e7646d2SAndroid Build Coastguard Worker   while (attr)
5709*5e7646d2SAndroid Build Coastguard Worker   {
5710*5e7646d2SAndroid Build Coastguard Worker     recipient = NULL;
5711*5e7646d2SAndroid Build Coastguard Worker     pullmethod = NULL;
5712*5e7646d2SAndroid Build Coastguard Worker     user_data  = NULL;
5713*5e7646d2SAndroid Build Coastguard Worker     interval   = 0;
5714*5e7646d2SAndroid Build Coastguard Worker     lease      = DefaultLeaseDuration;
5715*5e7646d2SAndroid Build Coastguard Worker     jobid      = 0;
5716*5e7646d2SAndroid Build Coastguard Worker     mask       = CUPSD_EVENT_NONE;
5717*5e7646d2SAndroid Build Coastguard Worker 
5718*5e7646d2SAndroid Build Coastguard Worker     if (printer)
5719*5e7646d2SAndroid Build Coastguard Worker     {
5720*5e7646d2SAndroid Build Coastguard Worker       notify_events = ippFindAttribute(printer->attrs, "notify-events-default",
5721*5e7646d2SAndroid Build Coastguard Worker                                        IPP_TAG_KEYWORD);
5722*5e7646d2SAndroid Build Coastguard Worker       notify_lease  = ippFindAttribute(printer->attrs,
5723*5e7646d2SAndroid Build Coastguard Worker                                        "notify-lease-duration-default",
5724*5e7646d2SAndroid Build Coastguard Worker                                        IPP_TAG_INTEGER);
5725*5e7646d2SAndroid Build Coastguard Worker 
5726*5e7646d2SAndroid Build Coastguard Worker       if (notify_lease)
5727*5e7646d2SAndroid Build Coastguard Worker         lease = notify_lease->values[0].integer;
5728*5e7646d2SAndroid Build Coastguard Worker     }
5729*5e7646d2SAndroid Build Coastguard Worker     else
5730*5e7646d2SAndroid Build Coastguard Worker     {
5731*5e7646d2SAndroid Build Coastguard Worker       notify_events = NULL;
5732*5e7646d2SAndroid Build Coastguard Worker       notify_lease  = NULL;
5733*5e7646d2SAndroid Build Coastguard Worker     }
5734*5e7646d2SAndroid Build Coastguard Worker 
5735*5e7646d2SAndroid Build Coastguard Worker     while (attr && attr->group_tag != IPP_TAG_ZERO)
5736*5e7646d2SAndroid Build Coastguard Worker     {
5737*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->name, "notify-recipient-uri") &&
5738*5e7646d2SAndroid Build Coastguard Worker           attr->value_tag == IPP_TAG_URI)
5739*5e7646d2SAndroid Build Coastguard Worker       {
5740*5e7646d2SAndroid Build Coastguard Worker        /*
5741*5e7646d2SAndroid Build Coastguard Worker         * Validate the recipient scheme against the ServerBin/notifier
5742*5e7646d2SAndroid Build Coastguard Worker 	* directory...
5743*5e7646d2SAndroid Build Coastguard Worker 	*/
5744*5e7646d2SAndroid Build Coastguard Worker 
5745*5e7646d2SAndroid Build Coastguard Worker 	char	notifier[1024];		/* Notifier filename */
5746*5e7646d2SAndroid Build Coastguard Worker 
5747*5e7646d2SAndroid Build Coastguard Worker 
5748*5e7646d2SAndroid Build Coastguard Worker         recipient = attr->values[0].string.text;
5749*5e7646d2SAndroid Build Coastguard Worker 
5750*5e7646d2SAndroid Build Coastguard Worker 	if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
5751*5e7646d2SAndroid Build Coastguard Worker 	                    scheme, sizeof(scheme), userpass, sizeof(userpass),
5752*5e7646d2SAndroid Build Coastguard Worker 			    host, sizeof(host), &port,
5753*5e7646d2SAndroid Build Coastguard Worker 			    resource, sizeof(resource)) < HTTP_URI_OK)
5754*5e7646d2SAndroid Build Coastguard Worker         {
5755*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
5756*5e7646d2SAndroid Build Coastguard Worker 	                  _("Bad notify-recipient-uri \"%s\"."), recipient);
5757*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5758*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_URI_SCHEME);
5759*5e7646d2SAndroid Build Coastguard Worker 	  return;
5760*5e7646d2SAndroid Build Coastguard Worker 	}
5761*5e7646d2SAndroid Build Coastguard Worker 
5762*5e7646d2SAndroid Build Coastguard Worker         snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
5763*5e7646d2SAndroid Build Coastguard Worker 	         scheme);
5764*5e7646d2SAndroid Build Coastguard Worker         if (access(notifier, X_OK) || !strcmp(scheme, ".") || !strcmp(scheme, ".."))
5765*5e7646d2SAndroid Build Coastguard Worker 	{
5766*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
5767*5e7646d2SAndroid Build Coastguard Worker 	                  _("notify-recipient-uri URI \"%s\" uses unknown "
5768*5e7646d2SAndroid Build Coastguard Worker 			    "scheme."), recipient);
5769*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5770*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_URI_SCHEME);
5771*5e7646d2SAndroid Build Coastguard Worker 	  return;
5772*5e7646d2SAndroid Build Coastguard Worker 	}
5773*5e7646d2SAndroid Build Coastguard Worker 
5774*5e7646d2SAndroid Build Coastguard Worker         if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
5775*5e7646d2SAndroid Build Coastguard Worker 	{
5776*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
5777*5e7646d2SAndroid Build Coastguard Worker 	                  _("notify-recipient-uri URI \"%s\" is already used."),
5778*5e7646d2SAndroid Build Coastguard Worker 			  recipient);
5779*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5780*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_ATTRIBUTES);
5781*5e7646d2SAndroid Build Coastguard Worker 	  return;
5782*5e7646d2SAndroid Build Coastguard Worker 	}
5783*5e7646d2SAndroid Build Coastguard Worker       }
5784*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-pull-method") &&
5785*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_KEYWORD)
5786*5e7646d2SAndroid Build Coastguard Worker       {
5787*5e7646d2SAndroid Build Coastguard Worker         pullmethod = attr->values[0].string.text;
5788*5e7646d2SAndroid Build Coastguard Worker 
5789*5e7646d2SAndroid Build Coastguard Worker         if (strcmp(pullmethod, "ippget"))
5790*5e7646d2SAndroid Build Coastguard Worker 	{
5791*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_NOT_POSSIBLE,
5792*5e7646d2SAndroid Build Coastguard Worker 	                  _("Bad notify-pull-method \"%s\"."), pullmethod);
5793*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
5794*5e7646d2SAndroid Build Coastguard Worker 	                "notify-status-code", IPP_ATTRIBUTES);
5795*5e7646d2SAndroid Build Coastguard Worker 	  return;
5796*5e7646d2SAndroid Build Coastguard Worker 	}
5797*5e7646d2SAndroid Build Coastguard Worker       }
5798*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-charset") &&
5799*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_CHARSET &&
5800*5e7646d2SAndroid Build Coastguard Worker 	       strcmp(attr->values[0].string.text, "us-ascii") &&
5801*5e7646d2SAndroid Build Coastguard Worker 	       strcmp(attr->values[0].string.text, "utf-8"))
5802*5e7646d2SAndroid Build Coastguard Worker       {
5803*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_CHARSET,
5804*5e7646d2SAndroid Build Coastguard Worker 	                _("Character set \"%s\" not supported."),
5805*5e7646d2SAndroid Build Coastguard Worker 			attr->values[0].string.text);
5806*5e7646d2SAndroid Build Coastguard Worker 	return;
5807*5e7646d2SAndroid Build Coastguard Worker       }
5808*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-natural-language") &&
5809*5e7646d2SAndroid Build Coastguard Worker                (attr->value_tag != IPP_TAG_LANGUAGE ||
5810*5e7646d2SAndroid Build Coastguard Worker 	        strcmp(attr->values[0].string.text, DefaultLanguage)))
5811*5e7646d2SAndroid Build Coastguard Worker       {
5812*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_CHARSET,
5813*5e7646d2SAndroid Build Coastguard Worker 	                _("Language \"%s\" not supported."),
5814*5e7646d2SAndroid Build Coastguard Worker 			attr->values[0].string.text);
5815*5e7646d2SAndroid Build Coastguard Worker 	return;
5816*5e7646d2SAndroid Build Coastguard Worker       }
5817*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-user-data") &&
5818*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_STRING)
5819*5e7646d2SAndroid Build Coastguard Worker       {
5820*5e7646d2SAndroid Build Coastguard Worker         if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
5821*5e7646d2SAndroid Build Coastguard Worker 	{
5822*5e7646d2SAndroid Build Coastguard Worker           send_ipp_status(con, IPP_REQUEST_VALUE,
5823*5e7646d2SAndroid Build Coastguard Worker 	                  _("The notify-user-data value is too large "
5824*5e7646d2SAndroid Build Coastguard Worker 			    "(%d > 63 octets)."),
5825*5e7646d2SAndroid Build Coastguard Worker 			  attr->values[0].unknown.length);
5826*5e7646d2SAndroid Build Coastguard Worker 	  return;
5827*5e7646d2SAndroid Build Coastguard Worker 	}
5828*5e7646d2SAndroid Build Coastguard Worker 
5829*5e7646d2SAndroid Build Coastguard Worker         user_data = attr;
5830*5e7646d2SAndroid Build Coastguard Worker       }
5831*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-events") &&
5832*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_KEYWORD)
5833*5e7646d2SAndroid Build Coastguard Worker         notify_events = attr;
5834*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-lease-duration") &&
5835*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_INTEGER)
5836*5e7646d2SAndroid Build Coastguard Worker         lease = attr->values[0].integer;
5837*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-time-interval") &&
5838*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_INTEGER)
5839*5e7646d2SAndroid Build Coastguard Worker         interval = attr->values[0].integer;
5840*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->name, "notify-job-id") &&
5841*5e7646d2SAndroid Build Coastguard Worker                attr->value_tag == IPP_TAG_INTEGER)
5842*5e7646d2SAndroid Build Coastguard Worker         jobid = attr->values[0].integer;
5843*5e7646d2SAndroid Build Coastguard Worker 
5844*5e7646d2SAndroid Build Coastguard Worker       attr = attr->next;
5845*5e7646d2SAndroid Build Coastguard Worker     }
5846*5e7646d2SAndroid Build Coastguard Worker 
5847*5e7646d2SAndroid Build Coastguard Worker     if (notify_events)
5848*5e7646d2SAndroid Build Coastguard Worker     {
5849*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < notify_events->num_values; i ++)
5850*5e7646d2SAndroid Build Coastguard Worker 	mask |= cupsdEventValue(notify_events->values[i].string.text);
5851*5e7646d2SAndroid Build Coastguard Worker     }
5852*5e7646d2SAndroid Build Coastguard Worker 
5853*5e7646d2SAndroid Build Coastguard Worker     if (recipient)
5854*5e7646d2SAndroid Build Coastguard Worker     {
5855*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient);
5856*5e7646d2SAndroid Build Coastguard Worker 
5857*5e7646d2SAndroid Build Coastguard Worker 
5858*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(recipient, "mailto:", 7) && user_data)
5859*5e7646d2SAndroid Build Coastguard Worker       {
5860*5e7646d2SAndroid Build Coastguard Worker         char	temp[64];		/* Temporary string */
5861*5e7646d2SAndroid Build Coastguard Worker 
5862*5e7646d2SAndroid Build Coastguard Worker 	memcpy(temp, user_data->values[0].unknown.data, (size_t)user_data->values[0].unknown.length);
5863*5e7646d2SAndroid Build Coastguard Worker 	temp[user_data->values[0].unknown.length] = '\0';
5864*5e7646d2SAndroid Build Coastguard Worker 
5865*5e7646d2SAndroid Build Coastguard Worker 	if (httpSeparateURI(HTTP_URI_CODING_ALL, temp, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_OK)
5866*5e7646d2SAndroid Build Coastguard Worker 	{
5867*5e7646d2SAndroid Build Coastguard Worker 	  send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad notify-user-data \"%s\"."), temp);
5868*5e7646d2SAndroid Build Coastguard Worker 	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES);
5869*5e7646d2SAndroid Build Coastguard Worker 	  return;
5870*5e7646d2SAndroid Build Coastguard Worker 	}
5871*5e7646d2SAndroid Build Coastguard Worker       }
5872*5e7646d2SAndroid Build Coastguard Worker     }
5873*5e7646d2SAndroid Build Coastguard Worker 
5874*5e7646d2SAndroid Build Coastguard Worker     if (pullmethod)
5875*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod);
5876*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease);
5877*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-time-interval=%d", interval);
5878*5e7646d2SAndroid Build Coastguard Worker 
5879*5e7646d2SAndroid Build Coastguard Worker     if (!recipient && !pullmethod)
5880*5e7646d2SAndroid Build Coastguard Worker       break;
5881*5e7646d2SAndroid Build Coastguard Worker 
5882*5e7646d2SAndroid Build Coastguard Worker     if (mask == CUPSD_EVENT_NONE)
5883*5e7646d2SAndroid Build Coastguard Worker     {
5884*5e7646d2SAndroid Build Coastguard Worker       if (jobid)
5885*5e7646d2SAndroid Build Coastguard Worker         mask = CUPSD_EVENT_JOB_COMPLETED;
5886*5e7646d2SAndroid Build Coastguard Worker       else if (printer)
5887*5e7646d2SAndroid Build Coastguard Worker         mask = CUPSD_EVENT_PRINTER_STATE_CHANGED;
5888*5e7646d2SAndroid Build Coastguard Worker       else
5889*5e7646d2SAndroid Build Coastguard Worker       {
5890*5e7646d2SAndroid Build Coastguard Worker         send_ipp_status(con, IPP_BAD_REQUEST,
5891*5e7646d2SAndroid Build Coastguard Worker 	                _("notify-events not specified."));
5892*5e7646d2SAndroid Build Coastguard Worker 	return;
5893*5e7646d2SAndroid Build Coastguard Worker       }
5894*5e7646d2SAndroid Build Coastguard Worker     }
5895*5e7646d2SAndroid Build Coastguard Worker 
5896*5e7646d2SAndroid Build Coastguard Worker     if (MaxLeaseDuration && (lease == 0 || lease > MaxLeaseDuration))
5897*5e7646d2SAndroid Build Coastguard Worker     {
5898*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO,
5899*5e7646d2SAndroid Build Coastguard Worker                       "create_subscriptions: Limiting notify-lease-duration to "
5900*5e7646d2SAndroid Build Coastguard Worker 		      "%d seconds.",
5901*5e7646d2SAndroid Build Coastguard Worker 		      MaxLeaseDuration);
5902*5e7646d2SAndroid Build Coastguard Worker       lease = MaxLeaseDuration;
5903*5e7646d2SAndroid Build Coastguard Worker     }
5904*5e7646d2SAndroid Build Coastguard Worker 
5905*5e7646d2SAndroid Build Coastguard Worker     if (jobid)
5906*5e7646d2SAndroid Build Coastguard Worker     {
5907*5e7646d2SAndroid Build Coastguard Worker       if ((job = cupsdFindJob(jobid)) == NULL)
5908*5e7646d2SAndroid Build Coastguard Worker       {
5909*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
5910*5e7646d2SAndroid Build Coastguard Worker 	                jobid);
5911*5e7646d2SAndroid Build Coastguard Worker 	return;
5912*5e7646d2SAndroid Build Coastguard Worker       }
5913*5e7646d2SAndroid Build Coastguard Worker     }
5914*5e7646d2SAndroid Build Coastguard Worker     else
5915*5e7646d2SAndroid Build Coastguard Worker       job = NULL;
5916*5e7646d2SAndroid Build Coastguard Worker 
5917*5e7646d2SAndroid Build Coastguard Worker     if ((sub = cupsdAddSubscription(mask, printer, job, recipient, 0)) == NULL)
5918*5e7646d2SAndroid Build Coastguard Worker     {
5919*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_TOO_MANY_SUBSCRIPTIONS,
5920*5e7646d2SAndroid Build Coastguard Worker 		      _("There are too many subscriptions."));
5921*5e7646d2SAndroid Build Coastguard Worker       return;
5922*5e7646d2SAndroid Build Coastguard Worker     }
5923*5e7646d2SAndroid Build Coastguard Worker 
5924*5e7646d2SAndroid Build Coastguard Worker     if (job)
5925*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for job %d.",
5926*5e7646d2SAndroid Build Coastguard Worker 		      sub->id, job->id);
5927*5e7646d2SAndroid Build Coastguard Worker     else if (printer)
5928*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
5929*5e7646d2SAndroid Build Coastguard Worker                       "Added subscription #%d for printer \"%s\".",
5930*5e7646d2SAndroid Build Coastguard Worker 		      sub->id, printer->name);
5931*5e7646d2SAndroid Build Coastguard Worker     else
5932*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for server.",
5933*5e7646d2SAndroid Build Coastguard Worker 		      sub->id);
5934*5e7646d2SAndroid Build Coastguard Worker 
5935*5e7646d2SAndroid Build Coastguard Worker     sub->interval = interval;
5936*5e7646d2SAndroid Build Coastguard Worker     sub->lease    = lease;
5937*5e7646d2SAndroid Build Coastguard Worker     sub->expire   = lease ? time(NULL) + lease : 0;
5938*5e7646d2SAndroid Build Coastguard Worker 
5939*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&sub->owner, username);
5940*5e7646d2SAndroid Build Coastguard Worker 
5941*5e7646d2SAndroid Build Coastguard Worker     if (user_data)
5942*5e7646d2SAndroid Build Coastguard Worker     {
5943*5e7646d2SAndroid Build Coastguard Worker       sub->user_data_len = user_data->values[0].unknown.length;
5944*5e7646d2SAndroid Build Coastguard Worker       memcpy(sub->user_data, user_data->values[0].unknown.data,
5945*5e7646d2SAndroid Build Coastguard Worker              (size_t)sub->user_data_len);
5946*5e7646d2SAndroid Build Coastguard Worker     }
5947*5e7646d2SAndroid Build Coastguard Worker 
5948*5e7646d2SAndroid Build Coastguard Worker     ippAddSeparator(con->response);
5949*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
5950*5e7646d2SAndroid Build Coastguard Worker                   "notify-subscription-id", sub->id);
5951*5e7646d2SAndroid Build Coastguard Worker 
5952*5e7646d2SAndroid Build Coastguard Worker     con->response->request.status.status_code = IPP_OK;
5953*5e7646d2SAndroid Build Coastguard Worker 
5954*5e7646d2SAndroid Build Coastguard Worker     if (attr)
5955*5e7646d2SAndroid Build Coastguard Worker       attr = attr->next;
5956*5e7646d2SAndroid Build Coastguard Worker   }
5957*5e7646d2SAndroid Build Coastguard Worker 
5958*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
5959*5e7646d2SAndroid Build Coastguard Worker }
5960*5e7646d2SAndroid Build Coastguard Worker 
5961*5e7646d2SAndroid Build Coastguard Worker 
5962*5e7646d2SAndroid Build Coastguard Worker /*
5963*5e7646d2SAndroid Build Coastguard Worker  * 'delete_printer()' - Remove a printer or class from the system.
5964*5e7646d2SAndroid Build Coastguard Worker  */
5965*5e7646d2SAndroid Build Coastguard Worker 
5966*5e7646d2SAndroid Build Coastguard Worker static void
delete_printer(cupsd_client_t * con,ipp_attribute_t * uri)5967*5e7646d2SAndroid Build Coastguard Worker delete_printer(cupsd_client_t  *con,	/* I - Client connection */
5968*5e7646d2SAndroid Build Coastguard Worker                ipp_attribute_t *uri)	/* I - URI of printer or class */
5969*5e7646d2SAndroid Build Coastguard Worker {
5970*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
5971*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type (printer/class) */
5972*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer/class */
5973*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Script/PPD filename */
5974*5e7646d2SAndroid Build Coastguard Worker   int		temporary;		/* Temporary queue? */
5975*5e7646d2SAndroid Build Coastguard Worker 
5976*5e7646d2SAndroid Build Coastguard Worker 
5977*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con,
5978*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
5979*5e7646d2SAndroid Build Coastguard Worker 
5980*5e7646d2SAndroid Build Coastguard Worker  /*
5981*5e7646d2SAndroid Build Coastguard Worker   * Do we have a valid URI?
5982*5e7646d2SAndroid Build Coastguard Worker   */
5983*5e7646d2SAndroid Build Coastguard Worker 
5984*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
5985*5e7646d2SAndroid Build Coastguard Worker   {
5986*5e7646d2SAndroid Build Coastguard Worker    /*
5987*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
5988*5e7646d2SAndroid Build Coastguard Worker     */
5989*5e7646d2SAndroid Build Coastguard Worker 
5990*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
5991*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
5992*5e7646d2SAndroid Build Coastguard Worker     return;
5993*5e7646d2SAndroid Build Coastguard Worker   }
5994*5e7646d2SAndroid Build Coastguard Worker 
5995*5e7646d2SAndroid Build Coastguard Worker  /*
5996*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
5997*5e7646d2SAndroid Build Coastguard Worker   */
5998*5e7646d2SAndroid Build Coastguard Worker 
5999*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6000*5e7646d2SAndroid Build Coastguard Worker   {
6001*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6002*5e7646d2SAndroid Build Coastguard Worker     return;
6003*5e7646d2SAndroid Build Coastguard Worker   }
6004*5e7646d2SAndroid Build Coastguard Worker 
6005*5e7646d2SAndroid Build Coastguard Worker  /*
6006*5e7646d2SAndroid Build Coastguard Worker   * Remove old jobs...
6007*5e7646d2SAndroid Build Coastguard Worker   */
6008*5e7646d2SAndroid Build Coastguard Worker 
6009*5e7646d2SAndroid Build Coastguard Worker   cupsdCancelJobs(printer->name, NULL, 1);
6010*5e7646d2SAndroid Build Coastguard Worker 
6011*5e7646d2SAndroid Build Coastguard Worker  /*
6012*5e7646d2SAndroid Build Coastguard Worker   * Remove old subscriptions and send a "deleted printer" event...
6013*5e7646d2SAndroid Build Coastguard Worker   */
6014*5e7646d2SAndroid Build Coastguard Worker 
6015*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL,
6016*5e7646d2SAndroid Build Coastguard Worker                 "%s \"%s\" deleted by \"%s\".",
6017*5e7646d2SAndroid Build Coastguard Worker 		(dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
6018*5e7646d2SAndroid Build Coastguard Worker 		printer->name, get_username(con));
6019*5e7646d2SAndroid Build Coastguard Worker 
6020*5e7646d2SAndroid Build Coastguard Worker   cupsdExpireSubscriptions(printer, NULL);
6021*5e7646d2SAndroid Build Coastguard Worker 
6022*5e7646d2SAndroid Build Coastguard Worker  /*
6023*5e7646d2SAndroid Build Coastguard Worker   * Remove any old PPD or script files...
6024*5e7646d2SAndroid Build Coastguard Worker   */
6025*5e7646d2SAndroid Build Coastguard Worker 
6026*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
6027*5e7646d2SAndroid Build Coastguard Worker            printer->name);
6028*5e7646d2SAndroid Build Coastguard Worker   unlink(filename);
6029*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot,
6030*5e7646d2SAndroid Build Coastguard Worker            printer->name);
6031*5e7646d2SAndroid Build Coastguard Worker   unlink(filename);
6032*5e7646d2SAndroid Build Coastguard Worker 
6033*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, printer->name);
6034*5e7646d2SAndroid Build Coastguard Worker   unlink(filename);
6035*5e7646d2SAndroid Build Coastguard Worker 
6036*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
6037*5e7646d2SAndroid Build Coastguard Worker   unlink(filename);
6038*5e7646d2SAndroid Build Coastguard Worker 
6039*5e7646d2SAndroid Build Coastguard Worker  /*
6040*5e7646d2SAndroid Build Coastguard Worker   * Unregister color profiles...
6041*5e7646d2SAndroid Build Coastguard Worker   */
6042*5e7646d2SAndroid Build Coastguard Worker 
6043*5e7646d2SAndroid Build Coastguard Worker   cupsdUnregisterColor(printer);
6044*5e7646d2SAndroid Build Coastguard Worker 
6045*5e7646d2SAndroid Build Coastguard Worker   temporary = printer->temporary;
6046*5e7646d2SAndroid Build Coastguard Worker 
6047*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
6048*5e7646d2SAndroid Build Coastguard Worker   {
6049*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".",
6050*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
6051*5e7646d2SAndroid Build Coastguard Worker 
6052*5e7646d2SAndroid Build Coastguard Worker     cupsdDeletePrinter(printer, 0);
6053*5e7646d2SAndroid Build Coastguard Worker     if (!temporary)
6054*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
6055*5e7646d2SAndroid Build Coastguard Worker   }
6056*5e7646d2SAndroid Build Coastguard Worker   else
6057*5e7646d2SAndroid Build Coastguard Worker   {
6058*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".",
6059*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
6060*5e7646d2SAndroid Build Coastguard Worker 
6061*5e7646d2SAndroid Build Coastguard Worker     if (cupsdDeletePrinter(printer, 0) && !temporary)
6062*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
6063*5e7646d2SAndroid Build Coastguard Worker 
6064*5e7646d2SAndroid Build Coastguard Worker     if (!temporary)
6065*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
6066*5e7646d2SAndroid Build Coastguard Worker   }
6067*5e7646d2SAndroid Build Coastguard Worker 
6068*5e7646d2SAndroid Build Coastguard Worker   if (!temporary)
6069*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
6070*5e7646d2SAndroid Build Coastguard Worker 
6071*5e7646d2SAndroid Build Coastguard Worker  /*
6072*5e7646d2SAndroid Build Coastguard Worker   * Return with no errors...
6073*5e7646d2SAndroid Build Coastguard Worker   */
6074*5e7646d2SAndroid Build Coastguard Worker 
6075*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
6076*5e7646d2SAndroid Build Coastguard Worker }
6077*5e7646d2SAndroid Build Coastguard Worker 
6078*5e7646d2SAndroid Build Coastguard Worker 
6079*5e7646d2SAndroid Build Coastguard Worker /*
6080*5e7646d2SAndroid Build Coastguard Worker  * 'get_default()' - Get the default destination.
6081*5e7646d2SAndroid Build Coastguard Worker  */
6082*5e7646d2SAndroid Build Coastguard Worker 
6083*5e7646d2SAndroid Build Coastguard Worker static void
get_default(cupsd_client_t * con)6084*5e7646d2SAndroid Build Coastguard Worker get_default(cupsd_client_t *con)	/* I - Client connection */
6085*5e7646d2SAndroid Build Coastguard Worker {
6086*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
6087*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*ra;			/* Requested attributes array */
6088*5e7646d2SAndroid Build Coastguard Worker 
6089*5e7646d2SAndroid Build Coastguard Worker 
6090*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->number);
6091*5e7646d2SAndroid Build Coastguard Worker 
6092*5e7646d2SAndroid Build Coastguard Worker  /*
6093*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
6094*5e7646d2SAndroid Build Coastguard Worker   */
6095*5e7646d2SAndroid Build Coastguard Worker 
6096*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6097*5e7646d2SAndroid Build Coastguard Worker   {
6098*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6099*5e7646d2SAndroid Build Coastguard Worker     return;
6100*5e7646d2SAndroid Build Coastguard Worker   }
6101*5e7646d2SAndroid Build Coastguard Worker 
6102*5e7646d2SAndroid Build Coastguard Worker   if (DefaultPrinter)
6103*5e7646d2SAndroid Build Coastguard Worker   {
6104*5e7646d2SAndroid Build Coastguard Worker     ra = create_requested_array(con->request);
6105*5e7646d2SAndroid Build Coastguard Worker 
6106*5e7646d2SAndroid Build Coastguard Worker     copy_printer_attrs(con, DefaultPrinter, ra);
6107*5e7646d2SAndroid Build Coastguard Worker 
6108*5e7646d2SAndroid Build Coastguard Worker     cupsArrayDelete(ra);
6109*5e7646d2SAndroid Build Coastguard Worker 
6110*5e7646d2SAndroid Build Coastguard Worker     con->response->request.status.status_code = IPP_OK;
6111*5e7646d2SAndroid Build Coastguard Worker   }
6112*5e7646d2SAndroid Build Coastguard Worker   else
6113*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("No default printer."));
6114*5e7646d2SAndroid Build Coastguard Worker }
6115*5e7646d2SAndroid Build Coastguard Worker 
6116*5e7646d2SAndroid Build Coastguard Worker 
6117*5e7646d2SAndroid Build Coastguard Worker /*
6118*5e7646d2SAndroid Build Coastguard Worker  * 'get_devices()' - Get the list of available devices on the local system.
6119*5e7646d2SAndroid Build Coastguard Worker  */
6120*5e7646d2SAndroid Build Coastguard Worker 
6121*5e7646d2SAndroid Build Coastguard Worker static void
get_devices(cupsd_client_t * con)6122*5e7646d2SAndroid Build Coastguard Worker get_devices(cupsd_client_t *con)	/* I - Client connection */
6123*5e7646d2SAndroid Build Coastguard Worker {
6124*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
6125*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*limit,		/* limit attribute */
6126*5e7646d2SAndroid Build Coastguard Worker 			*timeout,	/* timeout attribute */
6127*5e7646d2SAndroid Build Coastguard Worker 			*requested,	/* requested-attributes attribute */
6128*5e7646d2SAndroid Build Coastguard Worker 			*exclude,	/* exclude-schemes attribute */
6129*5e7646d2SAndroid Build Coastguard Worker 			*include;	/* include-schemes attribute */
6130*5e7646d2SAndroid Build Coastguard Worker   char			command[1024],	/* cups-deviced command */
6131*5e7646d2SAndroid Build Coastguard Worker 			options[2048],	/* Options to pass to command */
6132*5e7646d2SAndroid Build Coastguard Worker 			requested_str[256],
6133*5e7646d2SAndroid Build Coastguard Worker 					/* String for requested attributes */
6134*5e7646d2SAndroid Build Coastguard Worker 			exclude_str[512],
6135*5e7646d2SAndroid Build Coastguard Worker 					/* String for excluded schemes */
6136*5e7646d2SAndroid Build Coastguard Worker 			include_str[512];
6137*5e7646d2SAndroid Build Coastguard Worker 					/* String for included schemes */
6138*5e7646d2SAndroid Build Coastguard Worker 
6139*5e7646d2SAndroid Build Coastguard Worker 
6140*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->number);
6141*5e7646d2SAndroid Build Coastguard Worker 
6142*5e7646d2SAndroid Build Coastguard Worker  /*
6143*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
6144*5e7646d2SAndroid Build Coastguard Worker   */
6145*5e7646d2SAndroid Build Coastguard Worker 
6146*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
6147*5e7646d2SAndroid Build Coastguard Worker   {
6148*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6149*5e7646d2SAndroid Build Coastguard Worker     return;
6150*5e7646d2SAndroid Build Coastguard Worker   }
6151*5e7646d2SAndroid Build Coastguard Worker 
6152*5e7646d2SAndroid Build Coastguard Worker  /*
6153*5e7646d2SAndroid Build Coastguard Worker   * Run cups-deviced command with the given options...
6154*5e7646d2SAndroid Build Coastguard Worker   */
6155*5e7646d2SAndroid Build Coastguard Worker 
6156*5e7646d2SAndroid Build Coastguard Worker   limit     = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
6157*5e7646d2SAndroid Build Coastguard Worker   timeout   = ippFindAttribute(con->request, "timeout", IPP_TAG_INTEGER);
6158*5e7646d2SAndroid Build Coastguard Worker   requested = ippFindAttribute(con->request, "requested-attributes",
6159*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD);
6160*5e7646d2SAndroid Build Coastguard Worker   exclude   = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME);
6161*5e7646d2SAndroid Build Coastguard Worker   include   = ippFindAttribute(con->request, "include-schemes", IPP_TAG_NAME);
6162*5e7646d2SAndroid Build Coastguard Worker 
6163*5e7646d2SAndroid Build Coastguard Worker   if (requested)
6164*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(requested, requested_str, sizeof(requested_str));
6165*5e7646d2SAndroid Build Coastguard Worker   else
6166*5e7646d2SAndroid Build Coastguard Worker     strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
6167*5e7646d2SAndroid Build Coastguard Worker 
6168*5e7646d2SAndroid Build Coastguard Worker   if (exclude)
6169*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
6170*5e7646d2SAndroid Build Coastguard Worker   else
6171*5e7646d2SAndroid Build Coastguard Worker     exclude_str[0] = '\0';
6172*5e7646d2SAndroid Build Coastguard Worker 
6173*5e7646d2SAndroid Build Coastguard Worker   if (include)
6174*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(include, include_str, sizeof(include_str));
6175*5e7646d2SAndroid Build Coastguard Worker   else
6176*5e7646d2SAndroid Build Coastguard Worker     include_str[0] = '\0';
6177*5e7646d2SAndroid Build Coastguard Worker 
6178*5e7646d2SAndroid Build Coastguard Worker   snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
6179*5e7646d2SAndroid Build Coastguard Worker   snprintf(options, sizeof(options),
6180*5e7646d2SAndroid Build Coastguard Worker            "%d+%d+%d+%d+%s%s%s%s%s",
6181*5e7646d2SAndroid Build Coastguard Worker            con->request->request.op.request_id,
6182*5e7646d2SAndroid Build Coastguard Worker            limit ? limit->values[0].integer : 0,
6183*5e7646d2SAndroid Build Coastguard Worker 	   timeout ? timeout->values[0].integer : 15,
6184*5e7646d2SAndroid Build Coastguard Worker 	   (int)User,
6185*5e7646d2SAndroid Build Coastguard Worker 	   requested_str,
6186*5e7646d2SAndroid Build Coastguard Worker 	   exclude_str[0] ? "%20" : "", exclude_str,
6187*5e7646d2SAndroid Build Coastguard Worker 	   include_str[0] ? "%20" : "", include_str);
6188*5e7646d2SAndroid Build Coastguard Worker 
6189*5e7646d2SAndroid Build Coastguard Worker   if (cupsdSendCommand(con, command, options, 1))
6190*5e7646d2SAndroid Build Coastguard Worker   {
6191*5e7646d2SAndroid Build Coastguard Worker    /*
6192*5e7646d2SAndroid Build Coastguard Worker     * Command started successfully, don't send an IPP response here...
6193*5e7646d2SAndroid Build Coastguard Worker     */
6194*5e7646d2SAndroid Build Coastguard Worker 
6195*5e7646d2SAndroid Build Coastguard Worker     ippDelete(con->response);
6196*5e7646d2SAndroid Build Coastguard Worker     con->response = NULL;
6197*5e7646d2SAndroid Build Coastguard Worker   }
6198*5e7646d2SAndroid Build Coastguard Worker   else
6199*5e7646d2SAndroid Build Coastguard Worker   {
6200*5e7646d2SAndroid Build Coastguard Worker    /*
6201*5e7646d2SAndroid Build Coastguard Worker     * Command failed, return "internal error" so the user knows something
6202*5e7646d2SAndroid Build Coastguard Worker     * went wrong...
6203*5e7646d2SAndroid Build Coastguard Worker     */
6204*5e7646d2SAndroid Build Coastguard Worker 
6205*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_INTERNAL_ERROR,
6206*5e7646d2SAndroid Build Coastguard Worker                     _("cups-deviced failed to execute."));
6207*5e7646d2SAndroid Build Coastguard Worker   }
6208*5e7646d2SAndroid Build Coastguard Worker }
6209*5e7646d2SAndroid Build Coastguard Worker 
6210*5e7646d2SAndroid Build Coastguard Worker 
6211*5e7646d2SAndroid Build Coastguard Worker /*
6212*5e7646d2SAndroid Build Coastguard Worker  * 'get_document()' - Get a copy of a job file.
6213*5e7646d2SAndroid Build Coastguard Worker  */
6214*5e7646d2SAndroid Build Coastguard Worker 
6215*5e7646d2SAndroid Build Coastguard Worker static void
get_document(cupsd_client_t * con,ipp_attribute_t * uri)6216*5e7646d2SAndroid Build Coastguard Worker get_document(cupsd_client_t  *con,	/* I - Client connection */
6217*5e7646d2SAndroid Build Coastguard Worker              ipp_attribute_t *uri)	/* I - Job URI */
6218*5e7646d2SAndroid Build Coastguard Worker {
6219*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
6220*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
6221*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
6222*5e7646d2SAndroid Build Coastguard Worker   int		docnum;			/* Document number */
6223*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
6224*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
6225*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
6226*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
6227*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
6228*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
6229*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024],		/* Filename for document */
6230*5e7646d2SAndroid Build Coastguard Worker 		format[1024];		/* Format for document */
6231*5e7646d2SAndroid Build Coastguard Worker 
6232*5e7646d2SAndroid Build Coastguard Worker 
6233*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con,
6234*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
6235*5e7646d2SAndroid Build Coastguard Worker 
6236*5e7646d2SAndroid Build Coastguard Worker  /*
6237*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
6238*5e7646d2SAndroid Build Coastguard Worker   */
6239*5e7646d2SAndroid Build Coastguard Worker 
6240*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
6241*5e7646d2SAndroid Build Coastguard Worker   {
6242*5e7646d2SAndroid Build Coastguard Worker    /*
6243*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
6244*5e7646d2SAndroid Build Coastguard Worker     */
6245*5e7646d2SAndroid Build Coastguard Worker 
6246*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
6247*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
6248*5e7646d2SAndroid Build Coastguard Worker     {
6249*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
6250*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
6251*5e7646d2SAndroid Build Coastguard Worker       return;
6252*5e7646d2SAndroid Build Coastguard Worker     }
6253*5e7646d2SAndroid Build Coastguard Worker 
6254*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
6255*5e7646d2SAndroid Build Coastguard Worker   }
6256*5e7646d2SAndroid Build Coastguard Worker   else
6257*5e7646d2SAndroid Build Coastguard Worker   {
6258*5e7646d2SAndroid Build Coastguard Worker    /*
6259*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
6260*5e7646d2SAndroid Build Coastguard Worker     */
6261*5e7646d2SAndroid Build Coastguard Worker 
6262*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6263*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
6264*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
6265*5e7646d2SAndroid Build Coastguard Worker 
6266*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
6267*5e7646d2SAndroid Build Coastguard Worker     {
6268*5e7646d2SAndroid Build Coastguard Worker      /*
6269*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
6270*5e7646d2SAndroid Build Coastguard Worker       */
6271*5e7646d2SAndroid Build Coastguard Worker 
6272*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
6273*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
6274*5e7646d2SAndroid Build Coastguard Worker       return;
6275*5e7646d2SAndroid Build Coastguard Worker     }
6276*5e7646d2SAndroid Build Coastguard Worker 
6277*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
6278*5e7646d2SAndroid Build Coastguard Worker   }
6279*5e7646d2SAndroid Build Coastguard Worker 
6280*5e7646d2SAndroid Build Coastguard Worker  /*
6281*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
6282*5e7646d2SAndroid Build Coastguard Worker   */
6283*5e7646d2SAndroid Build Coastguard Worker 
6284*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
6285*5e7646d2SAndroid Build Coastguard Worker   {
6286*5e7646d2SAndroid Build Coastguard Worker    /*
6287*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
6288*5e7646d2SAndroid Build Coastguard Worker     */
6289*5e7646d2SAndroid Build Coastguard Worker 
6290*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
6291*5e7646d2SAndroid Build Coastguard Worker     return;
6292*5e7646d2SAndroid Build Coastguard Worker   }
6293*5e7646d2SAndroid Build Coastguard Worker 
6294*5e7646d2SAndroid Build Coastguard Worker  /*
6295*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
6296*5e7646d2SAndroid Build Coastguard Worker   */
6297*5e7646d2SAndroid Build Coastguard Worker 
6298*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con,
6299*5e7646d2SAndroid Build Coastguard Worker                                  job->username)) != HTTP_OK)
6300*5e7646d2SAndroid Build Coastguard Worker   {
6301*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6302*5e7646d2SAndroid Build Coastguard Worker     return;
6303*5e7646d2SAndroid Build Coastguard Worker   }
6304*5e7646d2SAndroid Build Coastguard Worker 
6305*5e7646d2SAndroid Build Coastguard Worker  /*
6306*5e7646d2SAndroid Build Coastguard Worker   * Get the document number...
6307*5e7646d2SAndroid Build Coastguard Worker   */
6308*5e7646d2SAndroid Build Coastguard Worker 
6309*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "document-number",
6310*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) == NULL)
6311*5e7646d2SAndroid Build Coastguard Worker   {
6312*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
6313*5e7646d2SAndroid Build Coastguard Worker                     _("Missing document-number attribute."));
6314*5e7646d2SAndroid Build Coastguard Worker     return;
6315*5e7646d2SAndroid Build Coastguard Worker   }
6316*5e7646d2SAndroid Build Coastguard Worker 
6317*5e7646d2SAndroid Build Coastguard Worker   if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files ||
6318*5e7646d2SAndroid Build Coastguard Worker       attr->num_values > 1)
6319*5e7646d2SAndroid Build Coastguard Worker   {
6320*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
6321*5e7646d2SAndroid Build Coastguard Worker                     _("Document #%d does not exist in job #%d."), docnum,
6322*5e7646d2SAndroid Build Coastguard Worker 		    jobid);
6323*5e7646d2SAndroid Build Coastguard Worker     return;
6324*5e7646d2SAndroid Build Coastguard Worker   }
6325*5e7646d2SAndroid Build Coastguard Worker 
6326*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, jobid,
6327*5e7646d2SAndroid Build Coastguard Worker            docnum);
6328*5e7646d2SAndroid Build Coastguard Worker   if ((con->file = open(filename, O_RDONLY)) == -1)
6329*5e7646d2SAndroid Build Coastguard Worker   {
6330*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
6331*5e7646d2SAndroid Build Coastguard Worker                     "Unable to open document %d in job %d - %s", docnum, jobid,
6332*5e7646d2SAndroid Build Coastguard Worker 		    strerror(errno));
6333*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
6334*5e7646d2SAndroid Build Coastguard Worker                     _("Unable to open document #%d in job #%d."), docnum,
6335*5e7646d2SAndroid Build Coastguard Worker 		    jobid);
6336*5e7646d2SAndroid Build Coastguard Worker     return;
6337*5e7646d2SAndroid Build Coastguard Worker   }
6338*5e7646d2SAndroid Build Coastguard Worker 
6339*5e7646d2SAndroid Build Coastguard Worker   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
6340*5e7646d2SAndroid Build Coastguard Worker 
6341*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadJob(job);
6342*5e7646d2SAndroid Build Coastguard Worker 
6343*5e7646d2SAndroid Build Coastguard Worker   snprintf(format, sizeof(format), "%s/%s", job->filetypes[docnum - 1]->super,
6344*5e7646d2SAndroid Build Coastguard Worker            job->filetypes[docnum - 1]->type);
6345*5e7646d2SAndroid Build Coastguard Worker 
6346*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
6347*5e7646d2SAndroid Build Coastguard Worker                NULL, format);
6348*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-number",
6349*5e7646d2SAndroid Build Coastguard Worker                 docnum);
6350*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "document-name",
6351*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_NAME)) != NULL)
6352*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "document-name",
6353*5e7646d2SAndroid Build Coastguard Worker                  NULL, attr->values[0].string.text);
6354*5e7646d2SAndroid Build Coastguard Worker }
6355*5e7646d2SAndroid Build Coastguard Worker 
6356*5e7646d2SAndroid Build Coastguard Worker 
6357*5e7646d2SAndroid Build Coastguard Worker /*
6358*5e7646d2SAndroid Build Coastguard Worker  * 'get_job_attrs()' - Get job attributes.
6359*5e7646d2SAndroid Build Coastguard Worker  */
6360*5e7646d2SAndroid Build Coastguard Worker 
6361*5e7646d2SAndroid Build Coastguard Worker static void
get_job_attrs(cupsd_client_t * con,ipp_attribute_t * uri)6362*5e7646d2SAndroid Build Coastguard Worker get_job_attrs(cupsd_client_t  *con,	/* I - Client connection */
6363*5e7646d2SAndroid Build Coastguard Worker 	      ipp_attribute_t *uri)	/* I - Job URI */
6364*5e7646d2SAndroid Build Coastguard Worker {
6365*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
6366*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
6367*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
6368*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
6369*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Current printer */
6370*5e7646d2SAndroid Build Coastguard Worker   cupsd_policy_t *policy;		/* Current security policy */
6371*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
6372*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
6373*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
6374*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
6375*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
6376*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*ra,			/* Requested attributes array */
6377*5e7646d2SAndroid Build Coastguard Worker 		*exclude;		/* Private attributes array */
6378*5e7646d2SAndroid Build Coastguard Worker 
6379*5e7646d2SAndroid Build Coastguard Worker 
6380*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
6381*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
6382*5e7646d2SAndroid Build Coastguard Worker 
6383*5e7646d2SAndroid Build Coastguard Worker  /*
6384*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
6385*5e7646d2SAndroid Build Coastguard Worker   */
6386*5e7646d2SAndroid Build Coastguard Worker 
6387*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
6388*5e7646d2SAndroid Build Coastguard Worker   {
6389*5e7646d2SAndroid Build Coastguard Worker    /*
6390*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
6391*5e7646d2SAndroid Build Coastguard Worker     */
6392*5e7646d2SAndroid Build Coastguard Worker 
6393*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
6394*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
6395*5e7646d2SAndroid Build Coastguard Worker     {
6396*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
6397*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
6398*5e7646d2SAndroid Build Coastguard Worker       return;
6399*5e7646d2SAndroid Build Coastguard Worker     }
6400*5e7646d2SAndroid Build Coastguard Worker 
6401*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
6402*5e7646d2SAndroid Build Coastguard Worker   }
6403*5e7646d2SAndroid Build Coastguard Worker   else
6404*5e7646d2SAndroid Build Coastguard Worker   {
6405*5e7646d2SAndroid Build Coastguard Worker    /*
6406*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
6407*5e7646d2SAndroid Build Coastguard Worker     */
6408*5e7646d2SAndroid Build Coastguard Worker 
6409*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6410*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
6411*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
6412*5e7646d2SAndroid Build Coastguard Worker 
6413*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
6414*5e7646d2SAndroid Build Coastguard Worker     {
6415*5e7646d2SAndroid Build Coastguard Worker      /*
6416*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
6417*5e7646d2SAndroid Build Coastguard Worker       */
6418*5e7646d2SAndroid Build Coastguard Worker 
6419*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
6420*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
6421*5e7646d2SAndroid Build Coastguard Worker       return;
6422*5e7646d2SAndroid Build Coastguard Worker     }
6423*5e7646d2SAndroid Build Coastguard Worker 
6424*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
6425*5e7646d2SAndroid Build Coastguard Worker   }
6426*5e7646d2SAndroid Build Coastguard Worker 
6427*5e7646d2SAndroid Build Coastguard Worker  /*
6428*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
6429*5e7646d2SAndroid Build Coastguard Worker   */
6430*5e7646d2SAndroid Build Coastguard Worker 
6431*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
6432*5e7646d2SAndroid Build Coastguard Worker   {
6433*5e7646d2SAndroid Build Coastguard Worker    /*
6434*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
6435*5e7646d2SAndroid Build Coastguard Worker     */
6436*5e7646d2SAndroid Build Coastguard Worker 
6437*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
6438*5e7646d2SAndroid Build Coastguard Worker     return;
6439*5e7646d2SAndroid Build Coastguard Worker   }
6440*5e7646d2SAndroid Build Coastguard Worker 
6441*5e7646d2SAndroid Build Coastguard Worker  /*
6442*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
6443*5e7646d2SAndroid Build Coastguard Worker   */
6444*5e7646d2SAndroid Build Coastguard Worker 
6445*5e7646d2SAndroid Build Coastguard Worker   if ((printer = job->printer) == NULL)
6446*5e7646d2SAndroid Build Coastguard Worker     printer = cupsdFindDest(job->dest);
6447*5e7646d2SAndroid Build Coastguard Worker 
6448*5e7646d2SAndroid Build Coastguard Worker   if (printer)
6449*5e7646d2SAndroid Build Coastguard Worker     policy = printer->op_policy_ptr;
6450*5e7646d2SAndroid Build Coastguard Worker   else
6451*5e7646d2SAndroid Build Coastguard Worker     policy = DefaultPolicyPtr;
6452*5e7646d2SAndroid Build Coastguard Worker 
6453*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK)
6454*5e7646d2SAndroid Build Coastguard Worker   {
6455*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6456*5e7646d2SAndroid Build Coastguard Worker     return;
6457*5e7646d2SAndroid Build Coastguard Worker   }
6458*5e7646d2SAndroid Build Coastguard Worker 
6459*5e7646d2SAndroid Build Coastguard Worker   exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
6460*5e7646d2SAndroid Build Coastguard Worker 
6461*5e7646d2SAndroid Build Coastguard Worker  /*
6462*5e7646d2SAndroid Build Coastguard Worker   * Copy attributes...
6463*5e7646d2SAndroid Build Coastguard Worker   */
6464*5e7646d2SAndroid Build Coastguard Worker 
6465*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadJob(job);
6466*5e7646d2SAndroid Build Coastguard Worker 
6467*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
6468*5e7646d2SAndroid Build Coastguard Worker   copy_job_attrs(con, job, ra, exclude);
6469*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
6470*5e7646d2SAndroid Build Coastguard Worker 
6471*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
6472*5e7646d2SAndroid Build Coastguard Worker }
6473*5e7646d2SAndroid Build Coastguard Worker 
6474*5e7646d2SAndroid Build Coastguard Worker 
6475*5e7646d2SAndroid Build Coastguard Worker /*
6476*5e7646d2SAndroid Build Coastguard Worker  * 'get_jobs()' - Get a list of jobs for the specified printer.
6477*5e7646d2SAndroid Build Coastguard Worker  */
6478*5e7646d2SAndroid Build Coastguard Worker 
6479*5e7646d2SAndroid Build Coastguard Worker static void
get_jobs(cupsd_client_t * con,ipp_attribute_t * uri)6480*5e7646d2SAndroid Build Coastguard Worker get_jobs(cupsd_client_t  *con,		/* I - Client connection */
6481*5e7646d2SAndroid Build Coastguard Worker 	 ipp_attribute_t *uri)		/* I - Printer URI */
6482*5e7646d2SAndroid Build Coastguard Worker {
6483*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
6484*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
6485*5e7646d2SAndroid Build Coastguard Worker   const char	*dest;			/* Destination */
6486*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type (printer/class) */
6487*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dmask;			/* Destination type mask */
6488*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
6489*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
6490*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
6491*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
6492*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
6493*5e7646d2SAndroid Build Coastguard Worker   int		job_comparison;		/* Job comparison */
6494*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t	job_state;		/* job-state value */
6495*5e7646d2SAndroid Build Coastguard Worker   int		first_job_id = 1,	/* First job ID */
6496*5e7646d2SAndroid Build Coastguard Worker 		first_index = 1,	/* First index */
6497*5e7646d2SAndroid Build Coastguard Worker 		limit = 0,		/* Maximum number of jobs to return */
6498*5e7646d2SAndroid Build Coastguard Worker 		count,			/* Number of jobs that match */
6499*5e7646d2SAndroid Build Coastguard Worker 		need_load_job = 0;	/* Do we need to load the job? */
6500*5e7646d2SAndroid Build Coastguard Worker   const char	*job_attr;		/* Job attribute requested */
6501*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *job_ids;		/* job-ids attribute */
6502*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job pointer */
6503*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer */
6504*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*list;			/* Which job list... */
6505*5e7646d2SAndroid Build Coastguard Worker   int		delete_list = 0;	/* Delete the list afterwards? */
6506*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*ra,			/* Requested attributes array */
6507*5e7646d2SAndroid Build Coastguard Worker 		*exclude;		/* Private attributes array */
6508*5e7646d2SAndroid Build Coastguard Worker   cupsd_policy_t *policy;		/* Current policy */
6509*5e7646d2SAndroid Build Coastguard Worker 
6510*5e7646d2SAndroid Build Coastguard Worker 
6511*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->number,
6512*5e7646d2SAndroid Build Coastguard Worker                   uri->values[0].string.text);
6513*5e7646d2SAndroid Build Coastguard Worker 
6514*5e7646d2SAndroid Build Coastguard Worker  /*
6515*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
6516*5e7646d2SAndroid Build Coastguard Worker   */
6517*5e7646d2SAndroid Build Coastguard Worker 
6518*5e7646d2SAndroid Build Coastguard Worker   if (strcmp(uri->name, "printer-uri"))
6519*5e7646d2SAndroid Build Coastguard Worker   {
6520*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request."));
6521*5e7646d2SAndroid Build Coastguard Worker     return;
6522*5e7646d2SAndroid Build Coastguard Worker   }
6523*5e7646d2SAndroid Build Coastguard Worker 
6524*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
6525*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), username, sizeof(username), host,
6526*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
6527*5e7646d2SAndroid Build Coastguard Worker 
6528*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(resource, "/") || !strcmp(resource, "/jobs"))
6529*5e7646d2SAndroid Build Coastguard Worker   {
6530*5e7646d2SAndroid Build Coastguard Worker     dest    = NULL;
6531*5e7646d2SAndroid Build Coastguard Worker     dtype   = (cups_ptype_t)0;
6532*5e7646d2SAndroid Build Coastguard Worker     dmask   = (cups_ptype_t)0;
6533*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
6534*5e7646d2SAndroid Build Coastguard Worker   }
6535*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
6536*5e7646d2SAndroid Build Coastguard Worker   {
6537*5e7646d2SAndroid Build Coastguard Worker     dest    = NULL;
6538*5e7646d2SAndroid Build Coastguard Worker     dtype   = (cups_ptype_t)0;
6539*5e7646d2SAndroid Build Coastguard Worker     dmask   = CUPS_PRINTER_CLASS;
6540*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
6541*5e7646d2SAndroid Build Coastguard Worker   }
6542*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
6543*5e7646d2SAndroid Build Coastguard Worker   {
6544*5e7646d2SAndroid Build Coastguard Worker     dest    = NULL;
6545*5e7646d2SAndroid Build Coastguard Worker     dtype   = CUPS_PRINTER_CLASS;
6546*5e7646d2SAndroid Build Coastguard Worker     dmask   = CUPS_PRINTER_CLASS;
6547*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
6548*5e7646d2SAndroid Build Coastguard Worker   }
6549*5e7646d2SAndroid Build Coastguard Worker   else if ((dest = cupsdValidateDest(uri->values[0].string.text, &dtype,
6550*5e7646d2SAndroid Build Coastguard Worker                                      &printer)) == NULL)
6551*5e7646d2SAndroid Build Coastguard Worker   {
6552*5e7646d2SAndroid Build Coastguard Worker    /*
6553*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
6554*5e7646d2SAndroid Build Coastguard Worker     */
6555*5e7646d2SAndroid Build Coastguard Worker 
6556*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
6557*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
6558*5e7646d2SAndroid Build Coastguard Worker     return;
6559*5e7646d2SAndroid Build Coastguard Worker   }
6560*5e7646d2SAndroid Build Coastguard Worker   else
6561*5e7646d2SAndroid Build Coastguard Worker   {
6562*5e7646d2SAndroid Build Coastguard Worker     dtype &= CUPS_PRINTER_CLASS;
6563*5e7646d2SAndroid Build Coastguard Worker     dmask = CUPS_PRINTER_CLASS;
6564*5e7646d2SAndroid Build Coastguard Worker   }
6565*5e7646d2SAndroid Build Coastguard Worker 
6566*5e7646d2SAndroid Build Coastguard Worker  /*
6567*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
6568*5e7646d2SAndroid Build Coastguard Worker   */
6569*5e7646d2SAndroid Build Coastguard Worker 
6570*5e7646d2SAndroid Build Coastguard Worker   if (printer)
6571*5e7646d2SAndroid Build Coastguard Worker     policy = printer->op_policy_ptr;
6572*5e7646d2SAndroid Build Coastguard Worker   else
6573*5e7646d2SAndroid Build Coastguard Worker     policy = DefaultPolicyPtr;
6574*5e7646d2SAndroid Build Coastguard Worker 
6575*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
6576*5e7646d2SAndroid Build Coastguard Worker   {
6577*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
6578*5e7646d2SAndroid Build Coastguard Worker     return;
6579*5e7646d2SAndroid Build Coastguard Worker   }
6580*5e7646d2SAndroid Build Coastguard Worker 
6581*5e7646d2SAndroid Build Coastguard Worker   job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
6582*5e7646d2SAndroid Build Coastguard Worker 
6583*5e7646d2SAndroid Build Coastguard Worker  /*
6584*5e7646d2SAndroid Build Coastguard Worker   * See if the "which-jobs" attribute have been specified...
6585*5e7646d2SAndroid Build Coastguard Worker   */
6586*5e7646d2SAndroid Build Coastguard Worker 
6587*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "which-jobs",
6588*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL && job_ids)
6589*5e7646d2SAndroid Build Coastguard Worker   {
6590*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_CONFLICT,
6591*5e7646d2SAndroid Build Coastguard Worker                     _("The %s attribute cannot be provided with job-ids."),
6592*5e7646d2SAndroid Build Coastguard Worker                     "which-jobs");
6593*5e7646d2SAndroid Build Coastguard Worker     return;
6594*5e7646d2SAndroid Build Coastguard Worker   }
6595*5e7646d2SAndroid Build Coastguard Worker   else if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
6596*5e7646d2SAndroid Build Coastguard Worker   {
6597*5e7646d2SAndroid Build Coastguard Worker     job_comparison = -1;
6598*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_STOPPED;
6599*5e7646d2SAndroid Build Coastguard Worker     list           = ActiveJobs;
6600*5e7646d2SAndroid Build Coastguard Worker   }
6601*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "completed"))
6602*5e7646d2SAndroid Build Coastguard Worker   {
6603*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 1;
6604*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_CANCELED;
6605*5e7646d2SAndroid Build Coastguard Worker     list           = cupsdGetCompletedJobs(printer);
6606*5e7646d2SAndroid Build Coastguard Worker     delete_list    = 1;
6607*5e7646d2SAndroid Build Coastguard Worker   }
6608*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "aborted"))
6609*5e7646d2SAndroid Build Coastguard Worker   {
6610*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6611*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_ABORTED;
6612*5e7646d2SAndroid Build Coastguard Worker     list           = cupsdGetCompletedJobs(printer);
6613*5e7646d2SAndroid Build Coastguard Worker     delete_list    = 1;
6614*5e7646d2SAndroid Build Coastguard Worker   }
6615*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "all"))
6616*5e7646d2SAndroid Build Coastguard Worker   {
6617*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 1;
6618*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_PENDING;
6619*5e7646d2SAndroid Build Coastguard Worker     list           = Jobs;
6620*5e7646d2SAndroid Build Coastguard Worker   }
6621*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "canceled"))
6622*5e7646d2SAndroid Build Coastguard Worker   {
6623*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6624*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_CANCELED;
6625*5e7646d2SAndroid Build Coastguard Worker     list           = cupsdGetCompletedJobs(printer);
6626*5e7646d2SAndroid Build Coastguard Worker     delete_list    = 1;
6627*5e7646d2SAndroid Build Coastguard Worker   }
6628*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "pending"))
6629*5e7646d2SAndroid Build Coastguard Worker   {
6630*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6631*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_PENDING;
6632*5e7646d2SAndroid Build Coastguard Worker     list           = ActiveJobs;
6633*5e7646d2SAndroid Build Coastguard Worker   }
6634*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "pending-held"))
6635*5e7646d2SAndroid Build Coastguard Worker   {
6636*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6637*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_HELD;
6638*5e7646d2SAndroid Build Coastguard Worker     list           = ActiveJobs;
6639*5e7646d2SAndroid Build Coastguard Worker   }
6640*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "processing"))
6641*5e7646d2SAndroid Build Coastguard Worker   {
6642*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6643*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_PROCESSING;
6644*5e7646d2SAndroid Build Coastguard Worker     list           = PrintingJobs;
6645*5e7646d2SAndroid Build Coastguard Worker   }
6646*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
6647*5e7646d2SAndroid Build Coastguard Worker   {
6648*5e7646d2SAndroid Build Coastguard Worker     job_comparison = 0;
6649*5e7646d2SAndroid Build Coastguard Worker     job_state      = IPP_JOB_STOPPED;
6650*5e7646d2SAndroid Build Coastguard Worker     list           = ActiveJobs;
6651*5e7646d2SAndroid Build Coastguard Worker   }
6652*5e7646d2SAndroid Build Coastguard Worker   else
6653*5e7646d2SAndroid Build Coastguard Worker   {
6654*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_ATTRIBUTES,
6655*5e7646d2SAndroid Build Coastguard Worker                     _("The which-jobs value \"%s\" is not supported."),
6656*5e7646d2SAndroid Build Coastguard Worker 		    attr->values[0].string.text);
6657*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
6658*5e7646d2SAndroid Build Coastguard Worker                  "which-jobs", NULL, attr->values[0].string.text);
6659*5e7646d2SAndroid Build Coastguard Worker     return;
6660*5e7646d2SAndroid Build Coastguard Worker   }
6661*5e7646d2SAndroid Build Coastguard Worker 
6662*5e7646d2SAndroid Build Coastguard Worker  /*
6663*5e7646d2SAndroid Build Coastguard Worker   * See if they want to limit the number of jobs reported...
6664*5e7646d2SAndroid Build Coastguard Worker   */
6665*5e7646d2SAndroid Build Coastguard Worker 
6666*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL)
6667*5e7646d2SAndroid Build Coastguard Worker   {
6668*5e7646d2SAndroid Build Coastguard Worker     if (job_ids)
6669*5e7646d2SAndroid Build Coastguard Worker     {
6670*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_CONFLICT,
6671*5e7646d2SAndroid Build Coastguard Worker 		      _("The %s attribute cannot be provided with job-ids."),
6672*5e7646d2SAndroid Build Coastguard Worker 		      "limit");
6673*5e7646d2SAndroid Build Coastguard Worker       return;
6674*5e7646d2SAndroid Build Coastguard Worker     }
6675*5e7646d2SAndroid Build Coastguard Worker 
6676*5e7646d2SAndroid Build Coastguard Worker     limit = attr->values[0].integer;
6677*5e7646d2SAndroid Build Coastguard Worker   }
6678*5e7646d2SAndroid Build Coastguard Worker 
6679*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "first-index", IPP_TAG_INTEGER)) != NULL)
6680*5e7646d2SAndroid Build Coastguard Worker   {
6681*5e7646d2SAndroid Build Coastguard Worker     if (job_ids)
6682*5e7646d2SAndroid Build Coastguard Worker     {
6683*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_CONFLICT,
6684*5e7646d2SAndroid Build Coastguard Worker 		      _("The %s attribute cannot be provided with job-ids."),
6685*5e7646d2SAndroid Build Coastguard Worker 		      "first-index");
6686*5e7646d2SAndroid Build Coastguard Worker       return;
6687*5e7646d2SAndroid Build Coastguard Worker     }
6688*5e7646d2SAndroid Build Coastguard Worker 
6689*5e7646d2SAndroid Build Coastguard Worker     first_index = attr->values[0].integer;
6690*5e7646d2SAndroid Build Coastguard Worker   }
6691*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL)
6692*5e7646d2SAndroid Build Coastguard Worker   {
6693*5e7646d2SAndroid Build Coastguard Worker     if (job_ids)
6694*5e7646d2SAndroid Build Coastguard Worker     {
6695*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_CONFLICT,
6696*5e7646d2SAndroid Build Coastguard Worker 		      _("The %s attribute cannot be provided with job-ids."),
6697*5e7646d2SAndroid Build Coastguard Worker 		      "first-job-id");
6698*5e7646d2SAndroid Build Coastguard Worker       return;
6699*5e7646d2SAndroid Build Coastguard Worker     }
6700*5e7646d2SAndroid Build Coastguard Worker 
6701*5e7646d2SAndroid Build Coastguard Worker     first_job_id = attr->values[0].integer;
6702*5e7646d2SAndroid Build Coastguard Worker   }
6703*5e7646d2SAndroid Build Coastguard Worker 
6704*5e7646d2SAndroid Build Coastguard Worker  /*
6705*5e7646d2SAndroid Build Coastguard Worker   * See if we only want to see jobs for a specific user...
6706*5e7646d2SAndroid Build Coastguard Worker   */
6707*5e7646d2SAndroid Build Coastguard Worker 
6708*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids)
6709*5e7646d2SAndroid Build Coastguard Worker   {
6710*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_CONFLICT,
6711*5e7646d2SAndroid Build Coastguard Worker                     _("The %s attribute cannot be provided with job-ids."),
6712*5e7646d2SAndroid Build Coastguard Worker                     "my-jobs");
6713*5e7646d2SAndroid Build Coastguard Worker     return;
6714*5e7646d2SAndroid Build Coastguard Worker   }
6715*5e7646d2SAndroid Build Coastguard Worker   else if (attr && attr->values[0].boolean)
6716*5e7646d2SAndroid Build Coastguard Worker     strlcpy(username, get_username(con), sizeof(username));
6717*5e7646d2SAndroid Build Coastguard Worker   else
6718*5e7646d2SAndroid Build Coastguard Worker     username[0] = '\0';
6719*5e7646d2SAndroid Build Coastguard Worker 
6720*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
6721*5e7646d2SAndroid Build Coastguard Worker   for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra))
6722*5e7646d2SAndroid Build Coastguard Worker     if (strcmp(job_attr, "job-id") &&
6723*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-k-octets") &&
6724*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-media-progress") &&
6725*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-more-info") &&
6726*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-name") &&
6727*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-originating-user-name") &&
6728*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-preserved") &&
6729*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-printer-up-time") &&
6730*5e7646d2SAndroid Build Coastguard Worker         strcmp(job_attr, "job-printer-uri") &&
6731*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-state") &&
6732*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-state-reasons") &&
6733*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "job-uri") &&
6734*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "time-at-completed") &&
6735*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "time-at-creation") &&
6736*5e7646d2SAndroid Build Coastguard Worker 	strcmp(job_attr, "number-of-documents"))
6737*5e7646d2SAndroid Build Coastguard Worker     {
6738*5e7646d2SAndroid Build Coastguard Worker       need_load_job = 1;
6739*5e7646d2SAndroid Build Coastguard Worker       break;
6740*5e7646d2SAndroid Build Coastguard Worker     }
6741*5e7646d2SAndroid Build Coastguard Worker 
6742*5e7646d2SAndroid Build Coastguard Worker   if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list))
6743*5e7646d2SAndroid Build Coastguard Worker   {
6744*5e7646d2SAndroid Build Coastguard Worker    /*
6745*5e7646d2SAndroid Build Coastguard Worker     * Limit expensive Get-Jobs for job history to 500 jobs...
6746*5e7646d2SAndroid Build Coastguard Worker     */
6747*5e7646d2SAndroid Build Coastguard Worker 
6748*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500);
6749*5e7646d2SAndroid Build Coastguard Worker 
6750*5e7646d2SAndroid Build Coastguard Worker     if (limit)
6751*5e7646d2SAndroid Build Coastguard Worker       ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit);
6752*5e7646d2SAndroid Build Coastguard Worker 
6753*5e7646d2SAndroid Build Coastguard Worker     limit = 500;
6754*5e7646d2SAndroid Build Coastguard Worker 
6755*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit);
6756*5e7646d2SAndroid Build Coastguard Worker   }
6757*5e7646d2SAndroid Build Coastguard Worker 
6758*5e7646d2SAndroid Build Coastguard Worker  /*
6759*5e7646d2SAndroid Build Coastguard Worker   * OK, build a list of jobs for this printer...
6760*5e7646d2SAndroid Build Coastguard Worker   */
6761*5e7646d2SAndroid Build Coastguard Worker 
6762*5e7646d2SAndroid Build Coastguard Worker   if (job_ids)
6763*5e7646d2SAndroid Build Coastguard Worker   {
6764*5e7646d2SAndroid Build Coastguard Worker     int	i;				/* Looping var */
6765*5e7646d2SAndroid Build Coastguard Worker 
6766*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < job_ids->num_values; i ++)
6767*5e7646d2SAndroid Build Coastguard Worker     {
6768*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdFindJob(job_ids->values[i].integer))
6769*5e7646d2SAndroid Build Coastguard Worker         break;
6770*5e7646d2SAndroid Build Coastguard Worker     }
6771*5e7646d2SAndroid Build Coastguard Worker 
6772*5e7646d2SAndroid Build Coastguard Worker     if (i < job_ids->num_values)
6773*5e7646d2SAndroid Build Coastguard Worker     {
6774*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
6775*5e7646d2SAndroid Build Coastguard Worker                       job_ids->values[i].integer);
6776*5e7646d2SAndroid Build Coastguard Worker       return;
6777*5e7646d2SAndroid Build Coastguard Worker     }
6778*5e7646d2SAndroid Build Coastguard Worker 
6779*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < job_ids->num_values; i ++)
6780*5e7646d2SAndroid Build Coastguard Worker     {
6781*5e7646d2SAndroid Build Coastguard Worker       job = cupsdFindJob(job_ids->values[i].integer);
6782*5e7646d2SAndroid Build Coastguard Worker 
6783*5e7646d2SAndroid Build Coastguard Worker       if (need_load_job && !job->attrs)
6784*5e7646d2SAndroid Build Coastguard Worker       {
6785*5e7646d2SAndroid Build Coastguard Worker         cupsdLoadJob(job);
6786*5e7646d2SAndroid Build Coastguard Worker 
6787*5e7646d2SAndroid Build Coastguard Worker 	if (!job->attrs)
6788*5e7646d2SAndroid Build Coastguard Worker 	{
6789*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
6790*5e7646d2SAndroid Build Coastguard Worker 	  continue;
6791*5e7646d2SAndroid Build Coastguard Worker 	}
6792*5e7646d2SAndroid Build Coastguard Worker       }
6793*5e7646d2SAndroid Build Coastguard Worker 
6794*5e7646d2SAndroid Build Coastguard Worker       if (i > 0)
6795*5e7646d2SAndroid Build Coastguard Worker 	ippAddSeparator(con->response);
6796*5e7646d2SAndroid Build Coastguard Worker 
6797*5e7646d2SAndroid Build Coastguard Worker       exclude = cupsdGetPrivateAttrs(job->printer ?
6798*5e7646d2SAndroid Build Coastguard Worker                                          job->printer->op_policy_ptr :
6799*5e7646d2SAndroid Build Coastguard Worker 					 policy, con, job->printer,
6800*5e7646d2SAndroid Build Coastguard Worker 					 job->username);
6801*5e7646d2SAndroid Build Coastguard Worker 
6802*5e7646d2SAndroid Build Coastguard Worker       copy_job_attrs(con, job, ra, exclude);
6803*5e7646d2SAndroid Build Coastguard Worker     }
6804*5e7646d2SAndroid Build Coastguard Worker   }
6805*5e7646d2SAndroid Build Coastguard Worker   else
6806*5e7646d2SAndroid Build Coastguard Worker   {
6807*5e7646d2SAndroid Build Coastguard Worker     if (first_index > 1)
6808*5e7646d2SAndroid Build Coastguard Worker       job = (cupsd_job_t *)cupsArrayIndex(list, first_index - 1);
6809*5e7646d2SAndroid Build Coastguard Worker     else
6810*5e7646d2SAndroid Build Coastguard Worker       job = (cupsd_job_t *)cupsArrayFirst(list);
6811*5e7646d2SAndroid Build Coastguard Worker 
6812*5e7646d2SAndroid Build Coastguard Worker     for (count = 0; (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list))
6813*5e7646d2SAndroid Build Coastguard Worker     {
6814*5e7646d2SAndroid Build Coastguard Worker      /*
6815*5e7646d2SAndroid Build Coastguard Worker       * Filter out jobs that don't match...
6816*5e7646d2SAndroid Build Coastguard Worker       */
6817*5e7646d2SAndroid Build Coastguard Worker 
6818*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG2,
6819*5e7646d2SAndroid Build Coastguard Worker 		      "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
6820*5e7646d2SAndroid Build Coastguard Worker 		      "state_value=%d, attrs=%p", job->id, job->dest,
6821*5e7646d2SAndroid Build Coastguard Worker 		      job->username, job->state_value, job->attrs);
6822*5e7646d2SAndroid Build Coastguard Worker 
6823*5e7646d2SAndroid Build Coastguard Worker       if (!job->dest || !job->username)
6824*5e7646d2SAndroid Build Coastguard Worker 	cupsdLoadJob(job);
6825*5e7646d2SAndroid Build Coastguard Worker 
6826*5e7646d2SAndroid Build Coastguard Worker       if (!job->dest || !job->username)
6827*5e7646d2SAndroid Build Coastguard Worker 	continue;
6828*5e7646d2SAndroid Build Coastguard Worker 
6829*5e7646d2SAndroid Build Coastguard Worker       if ((dest && strcmp(job->dest, dest)) &&
6830*5e7646d2SAndroid Build Coastguard Worker 	  (!job->printer || !dest || strcmp(job->printer->name, dest)))
6831*5e7646d2SAndroid Build Coastguard Worker 	continue;
6832*5e7646d2SAndroid Build Coastguard Worker       if ((job->dtype & dmask) != dtype &&
6833*5e7646d2SAndroid Build Coastguard Worker 	  (!job->printer || (job->printer->type & dmask) != dtype))
6834*5e7646d2SAndroid Build Coastguard Worker 	continue;
6835*5e7646d2SAndroid Build Coastguard Worker 
6836*5e7646d2SAndroid Build Coastguard Worker       if ((job_comparison < 0 && job->state_value > job_state) ||
6837*5e7646d2SAndroid Build Coastguard Worker           (job_comparison == 0 && job->state_value != job_state) ||
6838*5e7646d2SAndroid Build Coastguard Worker           (job_comparison > 0 && job->state_value < job_state))
6839*5e7646d2SAndroid Build Coastguard Worker 	continue;
6840*5e7646d2SAndroid Build Coastguard Worker 
6841*5e7646d2SAndroid Build Coastguard Worker       if (job->id < first_job_id)
6842*5e7646d2SAndroid Build Coastguard Worker 	continue;
6843*5e7646d2SAndroid Build Coastguard Worker 
6844*5e7646d2SAndroid Build Coastguard Worker       if (need_load_job && !job->attrs)
6845*5e7646d2SAndroid Build Coastguard Worker       {
6846*5e7646d2SAndroid Build Coastguard Worker         cupsdLoadJob(job);
6847*5e7646d2SAndroid Build Coastguard Worker 
6848*5e7646d2SAndroid Build Coastguard Worker 	if (!job->attrs)
6849*5e7646d2SAndroid Build Coastguard Worker 	{
6850*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id);
6851*5e7646d2SAndroid Build Coastguard Worker 	  continue;
6852*5e7646d2SAndroid Build Coastguard Worker 	}
6853*5e7646d2SAndroid Build Coastguard Worker       }
6854*5e7646d2SAndroid Build Coastguard Worker 
6855*5e7646d2SAndroid Build Coastguard Worker       if (username[0] && _cups_strcasecmp(username, job->username))
6856*5e7646d2SAndroid Build Coastguard Worker 	continue;
6857*5e7646d2SAndroid Build Coastguard Worker 
6858*5e7646d2SAndroid Build Coastguard Worker       if (count > 0)
6859*5e7646d2SAndroid Build Coastguard Worker 	ippAddSeparator(con->response);
6860*5e7646d2SAndroid Build Coastguard Worker 
6861*5e7646d2SAndroid Build Coastguard Worker       count ++;
6862*5e7646d2SAndroid Build Coastguard Worker 
6863*5e7646d2SAndroid Build Coastguard Worker       exclude = cupsdGetPrivateAttrs(job->printer ?
6864*5e7646d2SAndroid Build Coastguard Worker                                          job->printer->op_policy_ptr :
6865*5e7646d2SAndroid Build Coastguard Worker 					 policy, con, job->printer,
6866*5e7646d2SAndroid Build Coastguard Worker 					 job->username);
6867*5e7646d2SAndroid Build Coastguard Worker 
6868*5e7646d2SAndroid Build Coastguard Worker       copy_job_attrs(con, job, ra, exclude);
6869*5e7646d2SAndroid Build Coastguard Worker     }
6870*5e7646d2SAndroid Build Coastguard Worker 
6871*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
6872*5e7646d2SAndroid Build Coastguard Worker   }
6873*5e7646d2SAndroid Build Coastguard Worker 
6874*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
6875*5e7646d2SAndroid Build Coastguard Worker 
6876*5e7646d2SAndroid Build Coastguard Worker   if (delete_list)
6877*5e7646d2SAndroid Build Coastguard Worker     cupsArrayDelete(list);
6878*5e7646d2SAndroid Build Coastguard Worker 
6879*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
6880*5e7646d2SAndroid Build Coastguard Worker }
6881*5e7646d2SAndroid Build Coastguard Worker 
6882*5e7646d2SAndroid Build Coastguard Worker 
6883*5e7646d2SAndroid Build Coastguard Worker /*
6884*5e7646d2SAndroid Build Coastguard Worker  * 'get_notifications()' - Get events for a subscription.
6885*5e7646d2SAndroid Build Coastguard Worker  */
6886*5e7646d2SAndroid Build Coastguard Worker 
6887*5e7646d2SAndroid Build Coastguard Worker static void
get_notifications(cupsd_client_t * con)6888*5e7646d2SAndroid Build Coastguard Worker get_notifications(cupsd_client_t *con)	/* I - Client connection */
6889*5e7646d2SAndroid Build Coastguard Worker {
6890*5e7646d2SAndroid Build Coastguard Worker   int			i, j;		/* Looping vars */
6891*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
6892*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription */
6893*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*ids,		/* notify-subscription-ids */
6894*5e7646d2SAndroid Build Coastguard Worker 			*sequences;	/* notify-sequence-numbers */
6895*5e7646d2SAndroid Build Coastguard Worker   int			min_seq;	/* Minimum sequence number */
6896*5e7646d2SAndroid Build Coastguard Worker   int			interval;	/* Poll interval */
6897*5e7646d2SAndroid Build Coastguard Worker 
6898*5e7646d2SAndroid Build Coastguard Worker 
6899*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])",
6900*5e7646d2SAndroid Build Coastguard Worker                   con, con->number);
6901*5e7646d2SAndroid Build Coastguard Worker 
6902*5e7646d2SAndroid Build Coastguard Worker  /*
6903*5e7646d2SAndroid Build Coastguard Worker   * Get subscription attributes...
6904*5e7646d2SAndroid Build Coastguard Worker   */
6905*5e7646d2SAndroid Build Coastguard Worker 
6906*5e7646d2SAndroid Build Coastguard Worker   ids       = ippFindAttribute(con->request, "notify-subscription-ids",
6907*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER);
6908*5e7646d2SAndroid Build Coastguard Worker   sequences = ippFindAttribute(con->request, "notify-sequence-numbers",
6909*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER);
6910*5e7646d2SAndroid Build Coastguard Worker 
6911*5e7646d2SAndroid Build Coastguard Worker   if (!ids)
6912*5e7646d2SAndroid Build Coastguard Worker   {
6913*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
6914*5e7646d2SAndroid Build Coastguard Worker                     _("Missing notify-subscription-ids attribute."));
6915*5e7646d2SAndroid Build Coastguard Worker     return;
6916*5e7646d2SAndroid Build Coastguard Worker   }
6917*5e7646d2SAndroid Build Coastguard Worker 
6918*5e7646d2SAndroid Build Coastguard Worker  /*
6919*5e7646d2SAndroid Build Coastguard Worker   * Are the subscription IDs valid?
6920*5e7646d2SAndroid Build Coastguard Worker   */
6921*5e7646d2SAndroid Build Coastguard Worker 
6922*5e7646d2SAndroid Build Coastguard Worker   for (i = 0, interval = 60; i < ids->num_values; i ++)
6923*5e7646d2SAndroid Build Coastguard Worker   {
6924*5e7646d2SAndroid Build Coastguard Worker     if ((sub = cupsdFindSubscription(ids->values[i].integer)) == NULL)
6925*5e7646d2SAndroid Build Coastguard Worker     {
6926*5e7646d2SAndroid Build Coastguard Worker      /*
6927*5e7646d2SAndroid Build Coastguard Worker       * Bad subscription ID...
6928*5e7646d2SAndroid Build Coastguard Worker       */
6929*5e7646d2SAndroid Build Coastguard Worker 
6930*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
6931*5e7646d2SAndroid Build Coastguard Worker 		      ids->values[i].integer);
6932*5e7646d2SAndroid Build Coastguard Worker       return;
6933*5e7646d2SAndroid Build Coastguard Worker     }
6934*5e7646d2SAndroid Build Coastguard Worker 
6935*5e7646d2SAndroid Build Coastguard Worker    /*
6936*5e7646d2SAndroid Build Coastguard Worker     * Check policy...
6937*5e7646d2SAndroid Build Coastguard Worker     */
6938*5e7646d2SAndroid Build Coastguard Worker 
6939*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
6940*5e7646d2SAndroid Build Coastguard Worker                                                DefaultPolicyPtr,
6941*5e7646d2SAndroid Build Coastguard Worker                                    con, sub->owner)) != HTTP_OK)
6942*5e7646d2SAndroid Build Coastguard Worker     {
6943*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, sub->dest);
6944*5e7646d2SAndroid Build Coastguard Worker       return;
6945*5e7646d2SAndroid Build Coastguard Worker     }
6946*5e7646d2SAndroid Build Coastguard Worker 
6947*5e7646d2SAndroid Build Coastguard Worker    /*
6948*5e7646d2SAndroid Build Coastguard Worker     * Check the subscription type and update the interval accordingly.
6949*5e7646d2SAndroid Build Coastguard Worker     */
6950*5e7646d2SAndroid Build Coastguard Worker 
6951*5e7646d2SAndroid Build Coastguard Worker     if (sub->job && sub->job->state_value == IPP_JOB_PROCESSING &&
6952*5e7646d2SAndroid Build Coastguard Worker         interval > 10)
6953*5e7646d2SAndroid Build Coastguard Worker       interval = 10;
6954*5e7646d2SAndroid Build Coastguard Worker     else if (sub->job && sub->job->state_value >= IPP_JOB_STOPPED)
6955*5e7646d2SAndroid Build Coastguard Worker       interval = 0;
6956*5e7646d2SAndroid Build Coastguard Worker     else if (sub->dest && sub->dest->state == IPP_PRINTER_PROCESSING &&
6957*5e7646d2SAndroid Build Coastguard Worker              interval > 30)
6958*5e7646d2SAndroid Build Coastguard Worker       interval = 30;
6959*5e7646d2SAndroid Build Coastguard Worker   }
6960*5e7646d2SAndroid Build Coastguard Worker 
6961*5e7646d2SAndroid Build Coastguard Worker  /*
6962*5e7646d2SAndroid Build Coastguard Worker   * Tell the client to poll again in N seconds...
6963*5e7646d2SAndroid Build Coastguard Worker   */
6964*5e7646d2SAndroid Build Coastguard Worker 
6965*5e7646d2SAndroid Build Coastguard Worker   if (interval > 0)
6966*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
6967*5e7646d2SAndroid Build Coastguard Worker                   "notify-get-interval", interval);
6968*5e7646d2SAndroid Build Coastguard Worker 
6969*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
6970*5e7646d2SAndroid Build Coastguard Worker                 "printer-up-time", time(NULL));
6971*5e7646d2SAndroid Build Coastguard Worker 
6972*5e7646d2SAndroid Build Coastguard Worker  /*
6973*5e7646d2SAndroid Build Coastguard Worker   * Copy the subscription event attributes to the response.
6974*5e7646d2SAndroid Build Coastguard Worker   */
6975*5e7646d2SAndroid Build Coastguard Worker 
6976*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code =
6977*5e7646d2SAndroid Build Coastguard Worker       interval ? IPP_OK : IPP_OK_EVENTS_COMPLETE;
6978*5e7646d2SAndroid Build Coastguard Worker 
6979*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < ids->num_values; i ++)
6980*5e7646d2SAndroid Build Coastguard Worker   {
6981*5e7646d2SAndroid Build Coastguard Worker    /*
6982*5e7646d2SAndroid Build Coastguard Worker     * Get the subscription and sequence number...
6983*5e7646d2SAndroid Build Coastguard Worker     */
6984*5e7646d2SAndroid Build Coastguard Worker 
6985*5e7646d2SAndroid Build Coastguard Worker     sub = cupsdFindSubscription(ids->values[i].integer);
6986*5e7646d2SAndroid Build Coastguard Worker 
6987*5e7646d2SAndroid Build Coastguard Worker     if (sequences && i < sequences->num_values)
6988*5e7646d2SAndroid Build Coastguard Worker       min_seq = sequences->values[i].integer;
6989*5e7646d2SAndroid Build Coastguard Worker     else
6990*5e7646d2SAndroid Build Coastguard Worker       min_seq = 1;
6991*5e7646d2SAndroid Build Coastguard Worker 
6992*5e7646d2SAndroid Build Coastguard Worker    /*
6993*5e7646d2SAndroid Build Coastguard Worker     * If we don't have any new events, nothing to do here...
6994*5e7646d2SAndroid Build Coastguard Worker     */
6995*5e7646d2SAndroid Build Coastguard Worker 
6996*5e7646d2SAndroid Build Coastguard Worker     if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events)))
6997*5e7646d2SAndroid Build Coastguard Worker       continue;
6998*5e7646d2SAndroid Build Coastguard Worker 
6999*5e7646d2SAndroid Build Coastguard Worker    /*
7000*5e7646d2SAndroid Build Coastguard Worker     * Otherwise copy all of the new events...
7001*5e7646d2SAndroid Build Coastguard Worker     */
7002*5e7646d2SAndroid Build Coastguard Worker 
7003*5e7646d2SAndroid Build Coastguard Worker     if (sub->first_event_id > min_seq)
7004*5e7646d2SAndroid Build Coastguard Worker       j = 0;
7005*5e7646d2SAndroid Build Coastguard Worker     else
7006*5e7646d2SAndroid Build Coastguard Worker       j = min_seq - sub->first_event_id;
7007*5e7646d2SAndroid Build Coastguard Worker 
7008*5e7646d2SAndroid Build Coastguard Worker     for (; j < cupsArrayCount(sub->events); j ++)
7009*5e7646d2SAndroid Build Coastguard Worker     {
7010*5e7646d2SAndroid Build Coastguard Worker       ippAddSeparator(con->response);
7011*5e7646d2SAndroid Build Coastguard Worker 
7012*5e7646d2SAndroid Build Coastguard Worker       copy_attrs(con->response,
7013*5e7646d2SAndroid Build Coastguard Worker                  ((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL,
7014*5e7646d2SAndroid Build Coastguard Worker         	 IPP_TAG_EVENT_NOTIFICATION, 0, NULL);
7015*5e7646d2SAndroid Build Coastguard Worker     }
7016*5e7646d2SAndroid Build Coastguard Worker   }
7017*5e7646d2SAndroid Build Coastguard Worker }
7018*5e7646d2SAndroid Build Coastguard Worker 
7019*5e7646d2SAndroid Build Coastguard Worker 
7020*5e7646d2SAndroid Build Coastguard Worker /*
7021*5e7646d2SAndroid Build Coastguard Worker  * 'get_ppd()' - Get a named PPD from the local system.
7022*5e7646d2SAndroid Build Coastguard Worker  */
7023*5e7646d2SAndroid Build Coastguard Worker 
7024*5e7646d2SAndroid Build Coastguard Worker static void
get_ppd(cupsd_client_t * con,ipp_attribute_t * uri)7025*5e7646d2SAndroid Build Coastguard Worker get_ppd(cupsd_client_t  *con,		/* I - Client connection */
7026*5e7646d2SAndroid Build Coastguard Worker         ipp_attribute_t *uri)		/* I - Printer URI or PPD name */
7027*5e7646d2SAndroid Build Coastguard Worker {
7028*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7029*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*dest;		/* Destination */
7030*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type */
7031*5e7646d2SAndroid Build Coastguard Worker 
7032*5e7646d2SAndroid Build Coastguard Worker 
7033*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
7034*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri, uri->name, uri->values[0].string.text);
7035*5e7646d2SAndroid Build Coastguard Worker 
7036*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(ippGetName(uri), "ppd-name"))
7037*5e7646d2SAndroid Build Coastguard Worker   {
7038*5e7646d2SAndroid Build Coastguard Worker    /*
7039*5e7646d2SAndroid Build Coastguard Worker     * Return a PPD file from cups-driverd...
7040*5e7646d2SAndroid Build Coastguard Worker     */
7041*5e7646d2SAndroid Build Coastguard Worker 
7042*5e7646d2SAndroid Build Coastguard Worker     const char *ppd_name = ippGetString(uri, 0, NULL);
7043*5e7646d2SAndroid Build Coastguard Worker 					/* ppd-name value */
7044*5e7646d2SAndroid Build Coastguard Worker     char	command[1024],		/* cups-driverd command */
7045*5e7646d2SAndroid Build Coastguard Worker 		options[1024],		/* Options to pass to command */
7046*5e7646d2SAndroid Build Coastguard Worker 		oppd_name[1024];	/* Escaped ppd-name */
7047*5e7646d2SAndroid Build Coastguard Worker 
7048*5e7646d2SAndroid Build Coastguard Worker    /*
7049*5e7646d2SAndroid Build Coastguard Worker     * Check policy...
7050*5e7646d2SAndroid Build Coastguard Worker     */
7051*5e7646d2SAndroid Build Coastguard Worker 
7052*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7053*5e7646d2SAndroid Build Coastguard Worker     {
7054*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, NULL);
7055*5e7646d2SAndroid Build Coastguard Worker       return;
7056*5e7646d2SAndroid Build Coastguard Worker     }
7057*5e7646d2SAndroid Build Coastguard Worker 
7058*5e7646d2SAndroid Build Coastguard Worker    /*
7059*5e7646d2SAndroid Build Coastguard Worker     * Check ppd-name value...
7060*5e7646d2SAndroid Build Coastguard Worker     */
7061*5e7646d2SAndroid Build Coastguard Worker 
7062*5e7646d2SAndroid Build Coastguard Worker     if (strstr(ppd_name, "../"))
7063*5e7646d2SAndroid Build Coastguard Worker     {
7064*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value."));
7065*5e7646d2SAndroid Build Coastguard Worker       return;
7066*5e7646d2SAndroid Build Coastguard Worker     }
7067*5e7646d2SAndroid Build Coastguard Worker 
7068*5e7646d2SAndroid Build Coastguard Worker    /*
7069*5e7646d2SAndroid Build Coastguard Worker     * Run cups-driverd command with the given options...
7070*5e7646d2SAndroid Build Coastguard Worker     */
7071*5e7646d2SAndroid Build Coastguard Worker 
7072*5e7646d2SAndroid Build Coastguard Worker     snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
7073*5e7646d2SAndroid Build Coastguard Worker     url_encode_string(ppd_name, oppd_name, sizeof(oppd_name));
7074*5e7646d2SAndroid Build Coastguard Worker     snprintf(options, sizeof(options), "get+%d+%s", ippGetRequestId(con->request), oppd_name);
7075*5e7646d2SAndroid Build Coastguard Worker 
7076*5e7646d2SAndroid Build Coastguard Worker     if (cupsdSendCommand(con, command, options, 0))
7077*5e7646d2SAndroid Build Coastguard Worker     {
7078*5e7646d2SAndroid Build Coastguard Worker      /*
7079*5e7646d2SAndroid Build Coastguard Worker       * Command started successfully, don't send an IPP response here...
7080*5e7646d2SAndroid Build Coastguard Worker       */
7081*5e7646d2SAndroid Build Coastguard Worker 
7082*5e7646d2SAndroid Build Coastguard Worker       ippDelete(con->response);
7083*5e7646d2SAndroid Build Coastguard Worker       con->response = NULL;
7084*5e7646d2SAndroid Build Coastguard Worker     }
7085*5e7646d2SAndroid Build Coastguard Worker     else
7086*5e7646d2SAndroid Build Coastguard Worker     {
7087*5e7646d2SAndroid Build Coastguard Worker      /*
7088*5e7646d2SAndroid Build Coastguard Worker       * Command failed, return "internal error" so the user knows something
7089*5e7646d2SAndroid Build Coastguard Worker       * went wrong...
7090*5e7646d2SAndroid Build Coastguard Worker       */
7091*5e7646d2SAndroid Build Coastguard Worker 
7092*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_INTERNAL_ERROR, _("cups-driverd failed to execute."));
7093*5e7646d2SAndroid Build Coastguard Worker     }
7094*5e7646d2SAndroid Build Coastguard Worker   }
7095*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(ippGetName(uri), "printer-uri") && cupsdValidateDest(ippGetString(uri, 0, NULL), &dtype, &dest))
7096*5e7646d2SAndroid Build Coastguard Worker   {
7097*5e7646d2SAndroid Build Coastguard Worker     int 	i;			/* Looping var */
7098*5e7646d2SAndroid Build Coastguard Worker     char	filename[1024];		/* PPD filename */
7099*5e7646d2SAndroid Build Coastguard Worker 
7100*5e7646d2SAndroid Build Coastguard Worker    /*
7101*5e7646d2SAndroid Build Coastguard Worker     * Check policy...
7102*5e7646d2SAndroid Build Coastguard Worker     */
7103*5e7646d2SAndroid Build Coastguard Worker 
7104*5e7646d2SAndroid Build Coastguard Worker     if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
7105*5e7646d2SAndroid Build Coastguard Worker     {
7106*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, status, dest);
7107*5e7646d2SAndroid Build Coastguard Worker       return;
7108*5e7646d2SAndroid Build Coastguard Worker     }
7109*5e7646d2SAndroid Build Coastguard Worker 
7110*5e7646d2SAndroid Build Coastguard Worker    /*
7111*5e7646d2SAndroid Build Coastguard Worker     * See if we need the PPD for a class or remote printer...
7112*5e7646d2SAndroid Build Coastguard Worker     */
7113*5e7646d2SAndroid Build Coastguard Worker 
7114*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->name);
7115*5e7646d2SAndroid Build Coastguard Worker 
7116*5e7646d2SAndroid Build Coastguard Worker     if ((dtype & CUPS_PRINTER_REMOTE) && access(filename, 0))
7117*5e7646d2SAndroid Build Coastguard Worker     {
7118*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer."));
7119*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->uri);
7120*5e7646d2SAndroid Build Coastguard Worker       return;
7121*5e7646d2SAndroid Build Coastguard Worker     }
7122*5e7646d2SAndroid Build Coastguard Worker     else if (dtype & CUPS_PRINTER_CLASS)
7123*5e7646d2SAndroid Build Coastguard Worker     {
7124*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < dest->num_printers; i ++)
7125*5e7646d2SAndroid Build Coastguard Worker         if (!(dest->printers[i]->type & CUPS_PRINTER_CLASS))
7126*5e7646d2SAndroid Build Coastguard Worker 	{
7127*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->printers[i]->name);
7128*5e7646d2SAndroid Build Coastguard Worker 
7129*5e7646d2SAndroid Build Coastguard Worker           if (!access(filename, 0))
7130*5e7646d2SAndroid Build Coastguard Worker 	    break;
7131*5e7646d2SAndroid Build Coastguard Worker         }
7132*5e7646d2SAndroid Build Coastguard Worker 
7133*5e7646d2SAndroid Build Coastguard Worker       if (i < dest->num_printers)
7134*5e7646d2SAndroid Build Coastguard Worker         dest = dest->printers[i];
7135*5e7646d2SAndroid Build Coastguard Worker       else
7136*5e7646d2SAndroid Build Coastguard Worker       {
7137*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer."));
7138*5e7646d2SAndroid Build Coastguard Worker         ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->printers[0]->uri);
7139*5e7646d2SAndroid Build Coastguard Worker         return;
7140*5e7646d2SAndroid Build Coastguard Worker       }
7141*5e7646d2SAndroid Build Coastguard Worker     }
7142*5e7646d2SAndroid Build Coastguard Worker 
7143*5e7646d2SAndroid Build Coastguard Worker    /*
7144*5e7646d2SAndroid Build Coastguard Worker     * Found the printer with the PPD file, now see if there is one...
7145*5e7646d2SAndroid Build Coastguard Worker     */
7146*5e7646d2SAndroid Build Coastguard Worker 
7147*5e7646d2SAndroid Build Coastguard Worker     if ((con->file = open(filename, O_RDONLY)) < 0)
7148*5e7646d2SAndroid Build Coastguard Worker     {
7149*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be opened: %s"), ippGetString(uri, 0, NULL), strerror(errno));
7150*5e7646d2SAndroid Build Coastguard Worker       return;
7151*5e7646d2SAndroid Build Coastguard Worker     }
7152*5e7646d2SAndroid Build Coastguard Worker 
7153*5e7646d2SAndroid Build Coastguard Worker     fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
7154*5e7646d2SAndroid Build Coastguard Worker 
7155*5e7646d2SAndroid Build Coastguard Worker     con->pipe_pid = 0;
7156*5e7646d2SAndroid Build Coastguard Worker 
7157*5e7646d2SAndroid Build Coastguard Worker     ippSetStatusCode(con->response, IPP_STATUS_OK);
7158*5e7646d2SAndroid Build Coastguard Worker   }
7159*5e7646d2SAndroid Build Coastguard Worker   else
7160*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be found."), ippGetString(uri, 0, NULL));
7161*5e7646d2SAndroid Build Coastguard Worker }
7162*5e7646d2SAndroid Build Coastguard Worker 
7163*5e7646d2SAndroid Build Coastguard Worker 
7164*5e7646d2SAndroid Build Coastguard Worker /*
7165*5e7646d2SAndroid Build Coastguard Worker  * 'get_ppds()' - Get the list of PPD files on the local system.
7166*5e7646d2SAndroid Build Coastguard Worker  */
7167*5e7646d2SAndroid Build Coastguard Worker 
7168*5e7646d2SAndroid Build Coastguard Worker static void
get_ppds(cupsd_client_t * con)7169*5e7646d2SAndroid Build Coastguard Worker get_ppds(cupsd_client_t *con)		/* I - Client connection */
7170*5e7646d2SAndroid Build Coastguard Worker {
7171*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7172*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*limit,		/* Limit attribute */
7173*5e7646d2SAndroid Build Coastguard Worker 			*device,	/* ppd-device-id attribute */
7174*5e7646d2SAndroid Build Coastguard Worker 			*language,	/* ppd-natural-language attribute */
7175*5e7646d2SAndroid Build Coastguard Worker 			*make,		/* ppd-make attribute */
7176*5e7646d2SAndroid Build Coastguard Worker 			*model,		/* ppd-make-and-model attribute */
7177*5e7646d2SAndroid Build Coastguard Worker 			*model_number,	/* ppd-model-number attribute */
7178*5e7646d2SAndroid Build Coastguard Worker 			*product,	/* ppd-product attribute */
7179*5e7646d2SAndroid Build Coastguard Worker 			*psversion,	/* ppd-psverion attribute */
7180*5e7646d2SAndroid Build Coastguard Worker 			*type,		/* ppd-type attribute */
7181*5e7646d2SAndroid Build Coastguard Worker 			*requested,	/* requested-attributes attribute */
7182*5e7646d2SAndroid Build Coastguard Worker 			*exclude,	/* exclude-schemes attribute */
7183*5e7646d2SAndroid Build Coastguard Worker 			*include;	/* include-schemes attribute */
7184*5e7646d2SAndroid Build Coastguard Worker   char			command[1024],	/* cups-driverd command */
7185*5e7646d2SAndroid Build Coastguard Worker 			options[4096],	/* Options to pass to command */
7186*5e7646d2SAndroid Build Coastguard Worker 			device_str[256],/* Escaped ppd-device-id string */
7187*5e7646d2SAndroid Build Coastguard Worker 			language_str[256],
7188*5e7646d2SAndroid Build Coastguard Worker 					/* Escaped ppd-natural-language */
7189*5e7646d2SAndroid Build Coastguard Worker 			make_str[256],	/* Escaped ppd-make string */
7190*5e7646d2SAndroid Build Coastguard Worker 			model_str[256],	/* Escaped ppd-make-and-model string */
7191*5e7646d2SAndroid Build Coastguard Worker 			model_number_str[256],
7192*5e7646d2SAndroid Build Coastguard Worker 					/* ppd-model-number string */
7193*5e7646d2SAndroid Build Coastguard Worker 			product_str[256],
7194*5e7646d2SAndroid Build Coastguard Worker 					/* Escaped ppd-product string */
7195*5e7646d2SAndroid Build Coastguard Worker 			psversion_str[256],
7196*5e7646d2SAndroid Build Coastguard Worker 					/* Escaped ppd-psversion string */
7197*5e7646d2SAndroid Build Coastguard Worker 			type_str[256],	/* Escaped ppd-type string */
7198*5e7646d2SAndroid Build Coastguard Worker 			requested_str[256],
7199*5e7646d2SAndroid Build Coastguard Worker 					/* String for requested attributes */
7200*5e7646d2SAndroid Build Coastguard Worker 			exclude_str[512],
7201*5e7646d2SAndroid Build Coastguard Worker 					/* String for excluded schemes */
7202*5e7646d2SAndroid Build Coastguard Worker 			include_str[512];
7203*5e7646d2SAndroid Build Coastguard Worker 					/* String for included schemes */
7204*5e7646d2SAndroid Build Coastguard Worker 
7205*5e7646d2SAndroid Build Coastguard Worker 
7206*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->number);
7207*5e7646d2SAndroid Build Coastguard Worker 
7208*5e7646d2SAndroid Build Coastguard Worker  /*
7209*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7210*5e7646d2SAndroid Build Coastguard Worker   */
7211*5e7646d2SAndroid Build Coastguard Worker 
7212*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7213*5e7646d2SAndroid Build Coastguard Worker   {
7214*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
7215*5e7646d2SAndroid Build Coastguard Worker     return;
7216*5e7646d2SAndroid Build Coastguard Worker   }
7217*5e7646d2SAndroid Build Coastguard Worker 
7218*5e7646d2SAndroid Build Coastguard Worker  /*
7219*5e7646d2SAndroid Build Coastguard Worker   * Run cups-driverd command with the given options...
7220*5e7646d2SAndroid Build Coastguard Worker   */
7221*5e7646d2SAndroid Build Coastguard Worker 
7222*5e7646d2SAndroid Build Coastguard Worker   limit        = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
7223*5e7646d2SAndroid Build Coastguard Worker   device       = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
7224*5e7646d2SAndroid Build Coastguard Worker   language     = ippFindAttribute(con->request, "ppd-natural-language",
7225*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_LANGUAGE);
7226*5e7646d2SAndroid Build Coastguard Worker   make         = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
7227*5e7646d2SAndroid Build Coastguard Worker   model        = ippFindAttribute(con->request, "ppd-make-and-model",
7228*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_TEXT);
7229*5e7646d2SAndroid Build Coastguard Worker   model_number = ippFindAttribute(con->request, "ppd-model-number",
7230*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_INTEGER);
7231*5e7646d2SAndroid Build Coastguard Worker   product      = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
7232*5e7646d2SAndroid Build Coastguard Worker   psversion    = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
7233*5e7646d2SAndroid Build Coastguard Worker   type         = ippFindAttribute(con->request, "ppd-type", IPP_TAG_KEYWORD);
7234*5e7646d2SAndroid Build Coastguard Worker   requested    = ippFindAttribute(con->request, "requested-attributes",
7235*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_KEYWORD);
7236*5e7646d2SAndroid Build Coastguard Worker   exclude      = ippFindAttribute(con->request, "exclude-schemes",
7237*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_NAME);
7238*5e7646d2SAndroid Build Coastguard Worker   include      = ippFindAttribute(con->request, "include-schemes",
7239*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_NAME);
7240*5e7646d2SAndroid Build Coastguard Worker 
7241*5e7646d2SAndroid Build Coastguard Worker   if (requested)
7242*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(requested, requested_str, sizeof(requested_str));
7243*5e7646d2SAndroid Build Coastguard Worker   else
7244*5e7646d2SAndroid Build Coastguard Worker     strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
7245*5e7646d2SAndroid Build Coastguard Worker 
7246*5e7646d2SAndroid Build Coastguard Worker   if (device)
7247*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(device, device_str, sizeof(device_str));
7248*5e7646d2SAndroid Build Coastguard Worker   else
7249*5e7646d2SAndroid Build Coastguard Worker     device_str[0] = '\0';
7250*5e7646d2SAndroid Build Coastguard Worker 
7251*5e7646d2SAndroid Build Coastguard Worker   if (language)
7252*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(language, language_str, sizeof(language_str));
7253*5e7646d2SAndroid Build Coastguard Worker   else
7254*5e7646d2SAndroid Build Coastguard Worker     language_str[0] = '\0';
7255*5e7646d2SAndroid Build Coastguard Worker 
7256*5e7646d2SAndroid Build Coastguard Worker   if (make)
7257*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(make, make_str, sizeof(make_str));
7258*5e7646d2SAndroid Build Coastguard Worker   else
7259*5e7646d2SAndroid Build Coastguard Worker     make_str[0] = '\0';
7260*5e7646d2SAndroid Build Coastguard Worker 
7261*5e7646d2SAndroid Build Coastguard Worker   if (model)
7262*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(model, model_str, sizeof(model_str));
7263*5e7646d2SAndroid Build Coastguard Worker   else
7264*5e7646d2SAndroid Build Coastguard Worker     model_str[0] = '\0';
7265*5e7646d2SAndroid Build Coastguard Worker 
7266*5e7646d2SAndroid Build Coastguard Worker   if (model_number)
7267*5e7646d2SAndroid Build Coastguard Worker     snprintf(model_number_str, sizeof(model_number_str), "ppd-model-number=%d",
7268*5e7646d2SAndroid Build Coastguard Worker              model_number->values[0].integer);
7269*5e7646d2SAndroid Build Coastguard Worker   else
7270*5e7646d2SAndroid Build Coastguard Worker     model_number_str[0] = '\0';
7271*5e7646d2SAndroid Build Coastguard Worker 
7272*5e7646d2SAndroid Build Coastguard Worker   if (product)
7273*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(product, product_str, sizeof(product_str));
7274*5e7646d2SAndroid Build Coastguard Worker   else
7275*5e7646d2SAndroid Build Coastguard Worker     product_str[0] = '\0';
7276*5e7646d2SAndroid Build Coastguard Worker 
7277*5e7646d2SAndroid Build Coastguard Worker   if (psversion)
7278*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
7279*5e7646d2SAndroid Build Coastguard Worker   else
7280*5e7646d2SAndroid Build Coastguard Worker     psversion_str[0] = '\0';
7281*5e7646d2SAndroid Build Coastguard Worker 
7282*5e7646d2SAndroid Build Coastguard Worker   if (type)
7283*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(type, type_str, sizeof(type_str));
7284*5e7646d2SAndroid Build Coastguard Worker   else
7285*5e7646d2SAndroid Build Coastguard Worker     type_str[0] = '\0';
7286*5e7646d2SAndroid Build Coastguard Worker 
7287*5e7646d2SAndroid Build Coastguard Worker   if (exclude)
7288*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
7289*5e7646d2SAndroid Build Coastguard Worker   else
7290*5e7646d2SAndroid Build Coastguard Worker     exclude_str[0] = '\0';
7291*5e7646d2SAndroid Build Coastguard Worker 
7292*5e7646d2SAndroid Build Coastguard Worker   if (include)
7293*5e7646d2SAndroid Build Coastguard Worker     url_encode_attr(include, include_str, sizeof(include_str));
7294*5e7646d2SAndroid Build Coastguard Worker   else
7295*5e7646d2SAndroid Build Coastguard Worker     include_str[0] = '\0';
7296*5e7646d2SAndroid Build Coastguard Worker 
7297*5e7646d2SAndroid Build Coastguard Worker   snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
7298*5e7646d2SAndroid Build Coastguard Worker   snprintf(options, sizeof(options),
7299*5e7646d2SAndroid Build Coastguard Worker            "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
7300*5e7646d2SAndroid Build Coastguard Worker            con->request->request.op.request_id,
7301*5e7646d2SAndroid Build Coastguard Worker            limit ? limit->values[0].integer : 0,
7302*5e7646d2SAndroid Build Coastguard Worker 	   requested_str,
7303*5e7646d2SAndroid Build Coastguard Worker 	   device ? "%20" : "", device_str,
7304*5e7646d2SAndroid Build Coastguard Worker 	   language ? "%20" : "", language_str,
7305*5e7646d2SAndroid Build Coastguard Worker 	   make ? "%20" : "", make_str,
7306*5e7646d2SAndroid Build Coastguard Worker 	   model ? "%20" : "", model_str,
7307*5e7646d2SAndroid Build Coastguard Worker 	   model_number ? "%20" : "", model_number_str,
7308*5e7646d2SAndroid Build Coastguard Worker 	   product ? "%20" : "", product_str,
7309*5e7646d2SAndroid Build Coastguard Worker 	   psversion ? "%20" : "", psversion_str,
7310*5e7646d2SAndroid Build Coastguard Worker 	   type ? "%20" : "", type_str,
7311*5e7646d2SAndroid Build Coastguard Worker 	   exclude_str[0] ? "%20" : "", exclude_str,
7312*5e7646d2SAndroid Build Coastguard Worker 	   include_str[0] ? "%20" : "", include_str);
7313*5e7646d2SAndroid Build Coastguard Worker 
7314*5e7646d2SAndroid Build Coastguard Worker   if (cupsdSendCommand(con, command, options, 0))
7315*5e7646d2SAndroid Build Coastguard Worker   {
7316*5e7646d2SAndroid Build Coastguard Worker    /*
7317*5e7646d2SAndroid Build Coastguard Worker     * Command started successfully, don't send an IPP response here...
7318*5e7646d2SAndroid Build Coastguard Worker     */
7319*5e7646d2SAndroid Build Coastguard Worker 
7320*5e7646d2SAndroid Build Coastguard Worker     ippDelete(con->response);
7321*5e7646d2SAndroid Build Coastguard Worker     con->response = NULL;
7322*5e7646d2SAndroid Build Coastguard Worker   }
7323*5e7646d2SAndroid Build Coastguard Worker   else
7324*5e7646d2SAndroid Build Coastguard Worker   {
7325*5e7646d2SAndroid Build Coastguard Worker    /*
7326*5e7646d2SAndroid Build Coastguard Worker     * Command failed, return "internal error" so the user knows something
7327*5e7646d2SAndroid Build Coastguard Worker     * went wrong...
7328*5e7646d2SAndroid Build Coastguard Worker     */
7329*5e7646d2SAndroid Build Coastguard Worker 
7330*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_INTERNAL_ERROR,
7331*5e7646d2SAndroid Build Coastguard Worker                     _("cups-driverd failed to execute."));
7332*5e7646d2SAndroid Build Coastguard Worker   }
7333*5e7646d2SAndroid Build Coastguard Worker }
7334*5e7646d2SAndroid Build Coastguard Worker 
7335*5e7646d2SAndroid Build Coastguard Worker 
7336*5e7646d2SAndroid Build Coastguard Worker /*
7337*5e7646d2SAndroid Build Coastguard Worker  * 'get_printer_attrs()' - Get printer attributes.
7338*5e7646d2SAndroid Build Coastguard Worker  */
7339*5e7646d2SAndroid Build Coastguard Worker 
7340*5e7646d2SAndroid Build Coastguard Worker static void
get_printer_attrs(cupsd_client_t * con,ipp_attribute_t * uri)7341*5e7646d2SAndroid Build Coastguard Worker get_printer_attrs(cupsd_client_t  *con,	/* I - Client connection */
7342*5e7646d2SAndroid Build Coastguard Worker 		  ipp_attribute_t *uri)	/* I - Printer URI */
7343*5e7646d2SAndroid Build Coastguard Worker {
7344*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7345*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
7346*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer/class */
7347*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*ra;		/* Requested attributes array */
7348*5e7646d2SAndroid Build Coastguard Worker 
7349*5e7646d2SAndroid Build Coastguard Worker 
7350*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con,
7351*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
7352*5e7646d2SAndroid Build Coastguard Worker 
7353*5e7646d2SAndroid Build Coastguard Worker  /*
7354*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
7355*5e7646d2SAndroid Build Coastguard Worker   */
7356*5e7646d2SAndroid Build Coastguard Worker 
7357*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7358*5e7646d2SAndroid Build Coastguard Worker   {
7359*5e7646d2SAndroid Build Coastguard Worker    /*
7360*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
7361*5e7646d2SAndroid Build Coastguard Worker     */
7362*5e7646d2SAndroid Build Coastguard Worker 
7363*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
7364*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
7365*5e7646d2SAndroid Build Coastguard Worker     return;
7366*5e7646d2SAndroid Build Coastguard Worker   }
7367*5e7646d2SAndroid Build Coastguard Worker 
7368*5e7646d2SAndroid Build Coastguard Worker  /*
7369*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7370*5e7646d2SAndroid Build Coastguard Worker   */
7371*5e7646d2SAndroid Build Coastguard Worker 
7372*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
7373*5e7646d2SAndroid Build Coastguard Worker   {
7374*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
7375*5e7646d2SAndroid Build Coastguard Worker     return;
7376*5e7646d2SAndroid Build Coastguard Worker   }
7377*5e7646d2SAndroid Build Coastguard Worker 
7378*5e7646d2SAndroid Build Coastguard Worker  /*
7379*5e7646d2SAndroid Build Coastguard Worker   * Send the attributes...
7380*5e7646d2SAndroid Build Coastguard Worker   */
7381*5e7646d2SAndroid Build Coastguard Worker 
7382*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
7383*5e7646d2SAndroid Build Coastguard Worker 
7384*5e7646d2SAndroid Build Coastguard Worker   copy_printer_attrs(con, printer, ra);
7385*5e7646d2SAndroid Build Coastguard Worker 
7386*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
7387*5e7646d2SAndroid Build Coastguard Worker 
7388*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
7389*5e7646d2SAndroid Build Coastguard Worker }
7390*5e7646d2SAndroid Build Coastguard Worker 
7391*5e7646d2SAndroid Build Coastguard Worker 
7392*5e7646d2SAndroid Build Coastguard Worker /*
7393*5e7646d2SAndroid Build Coastguard Worker  * 'get_printer_supported()' - Get printer supported values.
7394*5e7646d2SAndroid Build Coastguard Worker  */
7395*5e7646d2SAndroid Build Coastguard Worker 
7396*5e7646d2SAndroid Build Coastguard Worker static void
get_printer_supported(cupsd_client_t * con,ipp_attribute_t * uri)7397*5e7646d2SAndroid Build Coastguard Worker get_printer_supported(
7398*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
7399*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t *uri)		/* I - Printer URI */
7400*5e7646d2SAndroid Build Coastguard Worker {
7401*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7402*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
7403*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer/class */
7404*5e7646d2SAndroid Build Coastguard Worker 
7405*5e7646d2SAndroid Build Coastguard Worker 
7406*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con,
7407*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
7408*5e7646d2SAndroid Build Coastguard Worker 
7409*5e7646d2SAndroid Build Coastguard Worker  /*
7410*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
7411*5e7646d2SAndroid Build Coastguard Worker   */
7412*5e7646d2SAndroid Build Coastguard Worker 
7413*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7414*5e7646d2SAndroid Build Coastguard Worker   {
7415*5e7646d2SAndroid Build Coastguard Worker    /*
7416*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
7417*5e7646d2SAndroid Build Coastguard Worker     */
7418*5e7646d2SAndroid Build Coastguard Worker 
7419*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
7420*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
7421*5e7646d2SAndroid Build Coastguard Worker     return;
7422*5e7646d2SAndroid Build Coastguard Worker   }
7423*5e7646d2SAndroid Build Coastguard Worker 
7424*5e7646d2SAndroid Build Coastguard Worker  /*
7425*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7426*5e7646d2SAndroid Build Coastguard Worker   */
7427*5e7646d2SAndroid Build Coastguard Worker 
7428*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
7429*5e7646d2SAndroid Build Coastguard Worker   {
7430*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
7431*5e7646d2SAndroid Build Coastguard Worker     return;
7432*5e7646d2SAndroid Build Coastguard Worker   }
7433*5e7646d2SAndroid Build Coastguard Worker 
7434*5e7646d2SAndroid Build Coastguard Worker  /*
7435*5e7646d2SAndroid Build Coastguard Worker   * Return a list of attributes that can be set via Set-Printer-Attributes.
7436*5e7646d2SAndroid Build Coastguard Worker   */
7437*5e7646d2SAndroid Build Coastguard Worker 
7438*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7439*5e7646d2SAndroid Build Coastguard Worker                 "printer-geo-location", 0);
7440*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7441*5e7646d2SAndroid Build Coastguard Worker                 "printer-info", 0);
7442*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7443*5e7646d2SAndroid Build Coastguard Worker                 "printer-location", 0);
7444*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7445*5e7646d2SAndroid Build Coastguard Worker                 "printer-organization", 0);
7446*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
7447*5e7646d2SAndroid Build Coastguard Worker                 "printer-organizational-unit", 0);
7448*5e7646d2SAndroid Build Coastguard Worker 
7449*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
7450*5e7646d2SAndroid Build Coastguard Worker }
7451*5e7646d2SAndroid Build Coastguard Worker 
7452*5e7646d2SAndroid Build Coastguard Worker 
7453*5e7646d2SAndroid Build Coastguard Worker /*
7454*5e7646d2SAndroid Build Coastguard Worker  * 'get_printers()' - Get a list of printers or classes.
7455*5e7646d2SAndroid Build Coastguard Worker  */
7456*5e7646d2SAndroid Build Coastguard Worker 
7457*5e7646d2SAndroid Build Coastguard Worker static void
get_printers(cupsd_client_t * con,int type)7458*5e7646d2SAndroid Build Coastguard Worker get_printers(cupsd_client_t *con,	/* I - Client connection */
7459*5e7646d2SAndroid Build Coastguard Worker              int            type)	/* I - 0 or CUPS_PRINTER_CLASS */
7460*5e7646d2SAndroid Build Coastguard Worker {
7461*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
7462*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
7463*5e7646d2SAndroid Build Coastguard Worker   int		limit;			/* Max number of printers to return */
7464*5e7646d2SAndroid Build Coastguard Worker   int		count;			/* Number of printers that match */
7465*5e7646d2SAndroid Build Coastguard Worker   int		printer_id;		/* Printer we are interested in */
7466*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Current printer pointer */
7467*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	printer_type,		/* printer-type attribute */
7468*5e7646d2SAndroid Build Coastguard Worker 		printer_mask;		/* printer-type-mask attribute */
7469*5e7646d2SAndroid Build Coastguard Worker   char		*location;		/* Location string */
7470*5e7646d2SAndroid Build Coastguard Worker   const char	*username;		/* Current user */
7471*5e7646d2SAndroid Build Coastguard Worker   char		*first_printer_name;	/* first-printer-name attribute */
7472*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*ra;			/* Requested attributes array */
7473*5e7646d2SAndroid Build Coastguard Worker   int		local;			/* Local connection? */
7474*5e7646d2SAndroid Build Coastguard Worker 
7475*5e7646d2SAndroid Build Coastguard Worker 
7476*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con,
7477*5e7646d2SAndroid Build Coastguard Worker                   con->number, type);
7478*5e7646d2SAndroid Build Coastguard Worker 
7479*5e7646d2SAndroid Build Coastguard Worker  /*
7480*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7481*5e7646d2SAndroid Build Coastguard Worker   */
7482*5e7646d2SAndroid Build Coastguard Worker 
7483*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
7484*5e7646d2SAndroid Build Coastguard Worker   {
7485*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
7486*5e7646d2SAndroid Build Coastguard Worker     return;
7487*5e7646d2SAndroid Build Coastguard Worker   }
7488*5e7646d2SAndroid Build Coastguard Worker 
7489*5e7646d2SAndroid Build Coastguard Worker  /*
7490*5e7646d2SAndroid Build Coastguard Worker   * Check for printers...
7491*5e7646d2SAndroid Build Coastguard Worker   */
7492*5e7646d2SAndroid Build Coastguard Worker 
7493*5e7646d2SAndroid Build Coastguard Worker   if (!Printers || !cupsArrayCount(Printers))
7494*5e7646d2SAndroid Build Coastguard Worker   {
7495*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("No destinations added."));
7496*5e7646d2SAndroid Build Coastguard Worker     return;
7497*5e7646d2SAndroid Build Coastguard Worker   }
7498*5e7646d2SAndroid Build Coastguard Worker 
7499*5e7646d2SAndroid Build Coastguard Worker  /*
7500*5e7646d2SAndroid Build Coastguard Worker   * See if they want to limit the number of printers reported...
7501*5e7646d2SAndroid Build Coastguard Worker   */
7502*5e7646d2SAndroid Build Coastguard Worker 
7503*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "limit",
7504*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
7505*5e7646d2SAndroid Build Coastguard Worker     limit = attr->values[0].integer;
7506*5e7646d2SAndroid Build Coastguard Worker   else
7507*5e7646d2SAndroid Build Coastguard Worker     limit = 10000000;
7508*5e7646d2SAndroid Build Coastguard Worker 
7509*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "first-printer-name",
7510*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_NAME)) != NULL)
7511*5e7646d2SAndroid Build Coastguard Worker     first_printer_name = attr->values[0].string.text;
7512*5e7646d2SAndroid Build Coastguard Worker   else
7513*5e7646d2SAndroid Build Coastguard Worker     first_printer_name = NULL;
7514*5e7646d2SAndroid Build Coastguard Worker 
7515*5e7646d2SAndroid Build Coastguard Worker  /*
7516*5e7646d2SAndroid Build Coastguard Worker   * Support filtering...
7517*5e7646d2SAndroid Build Coastguard Worker   */
7518*5e7646d2SAndroid Build Coastguard Worker 
7519*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-id", IPP_TAG_INTEGER)) != NULL)
7520*5e7646d2SAndroid Build Coastguard Worker   {
7521*5e7646d2SAndroid Build Coastguard Worker     if ((printer_id = ippGetInteger(attr, 0)) <= 0)
7522*5e7646d2SAndroid Build Coastguard Worker     {
7523*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad \"printer-id\" value %d."), printer_id);
7524*5e7646d2SAndroid Build Coastguard Worker       return;
7525*5e7646d2SAndroid Build Coastguard Worker     }
7526*5e7646d2SAndroid Build Coastguard Worker   }
7527*5e7646d2SAndroid Build Coastguard Worker   else
7528*5e7646d2SAndroid Build Coastguard Worker     printer_id = 0;
7529*5e7646d2SAndroid Build Coastguard Worker 
7530*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-type",
7531*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ENUM)) != NULL)
7532*5e7646d2SAndroid Build Coastguard Worker     printer_type = (cups_ptype_t)attr->values[0].integer;
7533*5e7646d2SAndroid Build Coastguard Worker   else
7534*5e7646d2SAndroid Build Coastguard Worker     printer_type = (cups_ptype_t)0;
7535*5e7646d2SAndroid Build Coastguard Worker 
7536*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-type-mask",
7537*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_ENUM)) != NULL)
7538*5e7646d2SAndroid Build Coastguard Worker     printer_mask = (cups_ptype_t)attr->values[0].integer;
7539*5e7646d2SAndroid Build Coastguard Worker   else
7540*5e7646d2SAndroid Build Coastguard Worker     printer_mask = (cups_ptype_t)0;
7541*5e7646d2SAndroid Build Coastguard Worker 
7542*5e7646d2SAndroid Build Coastguard Worker   local = httpAddrLocalhost(&(con->clientaddr));
7543*5e7646d2SAndroid Build Coastguard Worker 
7544*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-location",
7545*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
7546*5e7646d2SAndroid Build Coastguard Worker     location = attr->values[0].string.text;
7547*5e7646d2SAndroid Build Coastguard Worker   else
7548*5e7646d2SAndroid Build Coastguard Worker     location = NULL;
7549*5e7646d2SAndroid Build Coastguard Worker 
7550*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0])
7551*5e7646d2SAndroid Build Coastguard Worker     username = con->username;
7552*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
7553*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_NAME)) != NULL)
7554*5e7646d2SAndroid Build Coastguard Worker     username = attr->values[0].string.text;
7555*5e7646d2SAndroid Build Coastguard Worker   else
7556*5e7646d2SAndroid Build Coastguard Worker     username = NULL;
7557*5e7646d2SAndroid Build Coastguard Worker 
7558*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
7559*5e7646d2SAndroid Build Coastguard Worker 
7560*5e7646d2SAndroid Build Coastguard Worker  /*
7561*5e7646d2SAndroid Build Coastguard Worker   * OK, build a list of printers for this printer...
7562*5e7646d2SAndroid Build Coastguard Worker   */
7563*5e7646d2SAndroid Build Coastguard Worker 
7564*5e7646d2SAndroid Build Coastguard Worker   if (first_printer_name)
7565*5e7646d2SAndroid Build Coastguard Worker   {
7566*5e7646d2SAndroid Build Coastguard Worker     if ((printer = cupsdFindDest(first_printer_name)) == NULL)
7567*5e7646d2SAndroid Build Coastguard Worker       printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
7568*5e7646d2SAndroid Build Coastguard Worker   }
7569*5e7646d2SAndroid Build Coastguard Worker   else
7570*5e7646d2SAndroid Build Coastguard Worker     printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
7571*5e7646d2SAndroid Build Coastguard Worker 
7572*5e7646d2SAndroid Build Coastguard Worker   for (count = 0;
7573*5e7646d2SAndroid Build Coastguard Worker        count < limit && printer;
7574*5e7646d2SAndroid Build Coastguard Worker        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
7575*5e7646d2SAndroid Build Coastguard Worker   {
7576*5e7646d2SAndroid Build Coastguard Worker     if (!local && !printer->shared)
7577*5e7646d2SAndroid Build Coastguard Worker       continue;
7578*5e7646d2SAndroid Build Coastguard Worker 
7579*5e7646d2SAndroid Build Coastguard Worker     if (printer_id && printer->printer_id != printer_id)
7580*5e7646d2SAndroid Build Coastguard Worker       continue;
7581*5e7646d2SAndroid Build Coastguard Worker 
7582*5e7646d2SAndroid Build Coastguard Worker     if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) &&
7583*5e7646d2SAndroid Build Coastguard Worker         (printer->type & printer_mask) == printer_type &&
7584*5e7646d2SAndroid Build Coastguard Worker 	(!location ||
7585*5e7646d2SAndroid Build Coastguard Worker 	 (printer->location && !_cups_strcasecmp(printer->location, location))))
7586*5e7646d2SAndroid Build Coastguard Worker     {
7587*5e7646d2SAndroid Build Coastguard Worker      /*
7588*5e7646d2SAndroid Build Coastguard Worker       * If a username is specified, see if it is allowed or denied
7589*5e7646d2SAndroid Build Coastguard Worker       * access...
7590*5e7646d2SAndroid Build Coastguard Worker       */
7591*5e7646d2SAndroid Build Coastguard Worker 
7592*5e7646d2SAndroid Build Coastguard Worker       if (cupsArrayCount(printer->users) && username &&
7593*5e7646d2SAndroid Build Coastguard Worker 	  !user_allowed(printer, username))
7594*5e7646d2SAndroid Build Coastguard Worker         continue;
7595*5e7646d2SAndroid Build Coastguard Worker 
7596*5e7646d2SAndroid Build Coastguard Worker      /*
7597*5e7646d2SAndroid Build Coastguard Worker       * Add the group separator as needed...
7598*5e7646d2SAndroid Build Coastguard Worker       */
7599*5e7646d2SAndroid Build Coastguard Worker 
7600*5e7646d2SAndroid Build Coastguard Worker       if (count > 0)
7601*5e7646d2SAndroid Build Coastguard Worker         ippAddSeparator(con->response);
7602*5e7646d2SAndroid Build Coastguard Worker 
7603*5e7646d2SAndroid Build Coastguard Worker       count ++;
7604*5e7646d2SAndroid Build Coastguard Worker 
7605*5e7646d2SAndroid Build Coastguard Worker      /*
7606*5e7646d2SAndroid Build Coastguard Worker       * Send the attributes...
7607*5e7646d2SAndroid Build Coastguard Worker       */
7608*5e7646d2SAndroid Build Coastguard Worker 
7609*5e7646d2SAndroid Build Coastguard Worker       copy_printer_attrs(con, printer, ra);
7610*5e7646d2SAndroid Build Coastguard Worker     }
7611*5e7646d2SAndroid Build Coastguard Worker   }
7612*5e7646d2SAndroid Build Coastguard Worker 
7613*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
7614*5e7646d2SAndroid Build Coastguard Worker 
7615*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
7616*5e7646d2SAndroid Build Coastguard Worker }
7617*5e7646d2SAndroid Build Coastguard Worker 
7618*5e7646d2SAndroid Build Coastguard Worker 
7619*5e7646d2SAndroid Build Coastguard Worker /*
7620*5e7646d2SAndroid Build Coastguard Worker  * 'get_subscription_attrs()' - Get subscription attributes.
7621*5e7646d2SAndroid Build Coastguard Worker  */
7622*5e7646d2SAndroid Build Coastguard Worker 
7623*5e7646d2SAndroid Build Coastguard Worker static void
get_subscription_attrs(cupsd_client_t * con,int sub_id)7624*5e7646d2SAndroid Build Coastguard Worker get_subscription_attrs(
7625*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
7626*5e7646d2SAndroid Build Coastguard Worker     int            sub_id)		/* I - Subscription ID */
7627*5e7646d2SAndroid Build Coastguard Worker {
7628*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7629*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription */
7630*5e7646d2SAndroid Build Coastguard Worker   cupsd_policy_t	*policy;	/* Current security policy */
7631*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*ra,		/* Requested attributes array */
7632*5e7646d2SAndroid Build Coastguard Worker 			*exclude;	/* Private attributes array */
7633*5e7646d2SAndroid Build Coastguard Worker 
7634*5e7646d2SAndroid Build Coastguard Worker 
7635*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
7636*5e7646d2SAndroid Build Coastguard Worker                   "get_subscription_attrs(con=%p[%d], sub_id=%d)",
7637*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, sub_id);
7638*5e7646d2SAndroid Build Coastguard Worker 
7639*5e7646d2SAndroid Build Coastguard Worker  /*
7640*5e7646d2SAndroid Build Coastguard Worker   * Expire subscriptions as needed...
7641*5e7646d2SAndroid Build Coastguard Worker   */
7642*5e7646d2SAndroid Build Coastguard Worker 
7643*5e7646d2SAndroid Build Coastguard Worker   cupsdExpireSubscriptions(NULL, NULL);
7644*5e7646d2SAndroid Build Coastguard Worker 
7645*5e7646d2SAndroid Build Coastguard Worker  /*
7646*5e7646d2SAndroid Build Coastguard Worker   * Is the subscription ID valid?
7647*5e7646d2SAndroid Build Coastguard Worker   */
7648*5e7646d2SAndroid Build Coastguard Worker 
7649*5e7646d2SAndroid Build Coastguard Worker   if ((sub = cupsdFindSubscription(sub_id)) == NULL)
7650*5e7646d2SAndroid Build Coastguard Worker   {
7651*5e7646d2SAndroid Build Coastguard Worker    /*
7652*5e7646d2SAndroid Build Coastguard Worker     * Bad subscription ID...
7653*5e7646d2SAndroid Build Coastguard Worker     */
7654*5e7646d2SAndroid Build Coastguard Worker 
7655*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
7656*5e7646d2SAndroid Build Coastguard Worker                     sub_id);
7657*5e7646d2SAndroid Build Coastguard Worker     return;
7658*5e7646d2SAndroid Build Coastguard Worker   }
7659*5e7646d2SAndroid Build Coastguard Worker 
7660*5e7646d2SAndroid Build Coastguard Worker  /*
7661*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7662*5e7646d2SAndroid Build Coastguard Worker   */
7663*5e7646d2SAndroid Build Coastguard Worker 
7664*5e7646d2SAndroid Build Coastguard Worker   if (sub->dest)
7665*5e7646d2SAndroid Build Coastguard Worker     policy = sub->dest->op_policy_ptr;
7666*5e7646d2SAndroid Build Coastguard Worker   else
7667*5e7646d2SAndroid Build Coastguard Worker     policy = DefaultPolicyPtr;
7668*5e7646d2SAndroid Build Coastguard Worker 
7669*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK)
7670*5e7646d2SAndroid Build Coastguard Worker   {
7671*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, sub->dest);
7672*5e7646d2SAndroid Build Coastguard Worker     return;
7673*5e7646d2SAndroid Build Coastguard Worker   }
7674*5e7646d2SAndroid Build Coastguard Worker 
7675*5e7646d2SAndroid Build Coastguard Worker   exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner);
7676*5e7646d2SAndroid Build Coastguard Worker 
7677*5e7646d2SAndroid Build Coastguard Worker  /*
7678*5e7646d2SAndroid Build Coastguard Worker   * Copy the subscription attributes to the response using the
7679*5e7646d2SAndroid Build Coastguard Worker   * requested-attributes attribute that may be provided by the client.
7680*5e7646d2SAndroid Build Coastguard Worker   */
7681*5e7646d2SAndroid Build Coastguard Worker 
7682*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
7683*5e7646d2SAndroid Build Coastguard Worker 
7684*5e7646d2SAndroid Build Coastguard Worker   copy_subscription_attrs(con, sub, ra, exclude);
7685*5e7646d2SAndroid Build Coastguard Worker 
7686*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
7687*5e7646d2SAndroid Build Coastguard Worker 
7688*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
7689*5e7646d2SAndroid Build Coastguard Worker }
7690*5e7646d2SAndroid Build Coastguard Worker 
7691*5e7646d2SAndroid Build Coastguard Worker 
7692*5e7646d2SAndroid Build Coastguard Worker /*
7693*5e7646d2SAndroid Build Coastguard Worker  * 'get_subscriptions()' - Get subscriptions.
7694*5e7646d2SAndroid Build Coastguard Worker  */
7695*5e7646d2SAndroid Build Coastguard Worker 
7696*5e7646d2SAndroid Build Coastguard Worker static void
get_subscriptions(cupsd_client_t * con,ipp_attribute_t * uri)7697*5e7646d2SAndroid Build Coastguard Worker get_subscriptions(cupsd_client_t  *con,	/* I - Client connection */
7698*5e7646d2SAndroid Build Coastguard Worker                   ipp_attribute_t *uri)	/* I - Printer/job URI */
7699*5e7646d2SAndroid Build Coastguard Worker {
7700*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
7701*5e7646d2SAndroid Build Coastguard Worker   int			count;		/* Number of subscriptions */
7702*5e7646d2SAndroid Build Coastguard Worker   int			limit;		/* Limit */
7703*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription */
7704*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*ra;		/* Requested attributes array */
7705*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Attribute */
7706*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
7707*5e7646d2SAndroid Build Coastguard Worker   char			scheme[HTTP_MAX_URI],
7708*5e7646d2SAndroid Build Coastguard Worker 					/* Scheme portion of URI */
7709*5e7646d2SAndroid Build Coastguard Worker 			username[HTTP_MAX_URI],
7710*5e7646d2SAndroid Build Coastguard Worker 					/* Username portion of URI */
7711*5e7646d2SAndroid Build Coastguard Worker 			host[HTTP_MAX_URI],
7712*5e7646d2SAndroid Build Coastguard Worker 					/* Host portion of URI */
7713*5e7646d2SAndroid Build Coastguard Worker 			resource[HTTP_MAX_URI];
7714*5e7646d2SAndroid Build Coastguard Worker 					/* Resource portion of URI */
7715*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port portion of URI */
7716*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Job pointer */
7717*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer */
7718*5e7646d2SAndroid Build Coastguard Worker   cupsd_policy_t	*policy;	/* Policy */
7719*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*exclude;	/* Private attributes array */
7720*5e7646d2SAndroid Build Coastguard Worker 
7721*5e7646d2SAndroid Build Coastguard Worker 
7722*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
7723*5e7646d2SAndroid Build Coastguard Worker                   "get_subscriptions(con=%p[%d], uri=%s)",
7724*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, uri->values[0].string.text);
7725*5e7646d2SAndroid Build Coastguard Worker 
7726*5e7646d2SAndroid Build Coastguard Worker  /*
7727*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
7728*5e7646d2SAndroid Build Coastguard Worker   */
7729*5e7646d2SAndroid Build Coastguard Worker 
7730*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
7731*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), username, sizeof(username), host,
7732*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
7733*5e7646d2SAndroid Build Coastguard Worker 
7734*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(resource, "/") ||
7735*5e7646d2SAndroid Build Coastguard Worker       (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) ||
7736*5e7646d2SAndroid Build Coastguard Worker       (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) ||
7737*5e7646d2SAndroid Build Coastguard Worker       (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9))
7738*5e7646d2SAndroid Build Coastguard Worker   {
7739*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
7740*5e7646d2SAndroid Build Coastguard Worker     job     = NULL;
7741*5e7646d2SAndroid Build Coastguard Worker   }
7742*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(resource, "/jobs/", 6) && resource[6])
7743*5e7646d2SAndroid Build Coastguard Worker   {
7744*5e7646d2SAndroid Build Coastguard Worker     printer = NULL;
7745*5e7646d2SAndroid Build Coastguard Worker     job     = cupsdFindJob(atoi(resource + 6));
7746*5e7646d2SAndroid Build Coastguard Worker 
7747*5e7646d2SAndroid Build Coastguard Worker     if (!job)
7748*5e7646d2SAndroid Build Coastguard Worker     {
7749*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
7750*5e7646d2SAndroid Build Coastguard Worker                       atoi(resource + 6));
7751*5e7646d2SAndroid Build Coastguard Worker       return;
7752*5e7646d2SAndroid Build Coastguard Worker     }
7753*5e7646d2SAndroid Build Coastguard Worker   }
7754*5e7646d2SAndroid Build Coastguard Worker   else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
7755*5e7646d2SAndroid Build Coastguard Worker   {
7756*5e7646d2SAndroid Build Coastguard Worker    /*
7757*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
7758*5e7646d2SAndroid Build Coastguard Worker     */
7759*5e7646d2SAndroid Build Coastguard Worker 
7760*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
7761*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
7762*5e7646d2SAndroid Build Coastguard Worker     return;
7763*5e7646d2SAndroid Build Coastguard Worker   }
7764*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(con->request, "notify-job-id",
7765*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_INTEGER)) != NULL)
7766*5e7646d2SAndroid Build Coastguard Worker   {
7767*5e7646d2SAndroid Build Coastguard Worker     job = cupsdFindJob(attr->values[0].integer);
7768*5e7646d2SAndroid Build Coastguard Worker 
7769*5e7646d2SAndroid Build Coastguard Worker     if (!job)
7770*5e7646d2SAndroid Build Coastguard Worker     {
7771*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
7772*5e7646d2SAndroid Build Coastguard Worker                       attr->values[0].integer);
7773*5e7646d2SAndroid Build Coastguard Worker       return;
7774*5e7646d2SAndroid Build Coastguard Worker     }
7775*5e7646d2SAndroid Build Coastguard Worker   }
7776*5e7646d2SAndroid Build Coastguard Worker   else
7777*5e7646d2SAndroid Build Coastguard Worker     job = NULL;
7778*5e7646d2SAndroid Build Coastguard Worker 
7779*5e7646d2SAndroid Build Coastguard Worker  /*
7780*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
7781*5e7646d2SAndroid Build Coastguard Worker   */
7782*5e7646d2SAndroid Build Coastguard Worker 
7783*5e7646d2SAndroid Build Coastguard Worker   if (printer)
7784*5e7646d2SAndroid Build Coastguard Worker     policy = printer->op_policy_ptr;
7785*5e7646d2SAndroid Build Coastguard Worker   else
7786*5e7646d2SAndroid Build Coastguard Worker     policy = DefaultPolicyPtr;
7787*5e7646d2SAndroid Build Coastguard Worker 
7788*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
7789*5e7646d2SAndroid Build Coastguard Worker   {
7790*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
7791*5e7646d2SAndroid Build Coastguard Worker     return;
7792*5e7646d2SAndroid Build Coastguard Worker   }
7793*5e7646d2SAndroid Build Coastguard Worker 
7794*5e7646d2SAndroid Build Coastguard Worker  /*
7795*5e7646d2SAndroid Build Coastguard Worker   * Expire subscriptions as needed...
7796*5e7646d2SAndroid Build Coastguard Worker   */
7797*5e7646d2SAndroid Build Coastguard Worker 
7798*5e7646d2SAndroid Build Coastguard Worker   cupsdExpireSubscriptions(NULL, NULL);
7799*5e7646d2SAndroid Build Coastguard Worker 
7800*5e7646d2SAndroid Build Coastguard Worker  /*
7801*5e7646d2SAndroid Build Coastguard Worker   * Copy the subscription attributes to the response using the
7802*5e7646d2SAndroid Build Coastguard Worker   * requested-attributes attribute that may be provided by the client.
7803*5e7646d2SAndroid Build Coastguard Worker   */
7804*5e7646d2SAndroid Build Coastguard Worker 
7805*5e7646d2SAndroid Build Coastguard Worker   ra = create_requested_array(con->request);
7806*5e7646d2SAndroid Build Coastguard Worker 
7807*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "limit",
7808*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
7809*5e7646d2SAndroid Build Coastguard Worker     limit = attr->values[0].integer;
7810*5e7646d2SAndroid Build Coastguard Worker   else
7811*5e7646d2SAndroid Build Coastguard Worker     limit = 0;
7812*5e7646d2SAndroid Build Coastguard Worker 
7813*5e7646d2SAndroid Build Coastguard Worker  /*
7814*5e7646d2SAndroid Build Coastguard Worker   * See if we only want to see subscriptions for a specific user...
7815*5e7646d2SAndroid Build Coastguard Worker   */
7816*5e7646d2SAndroid Build Coastguard Worker 
7817*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "my-subscriptions",
7818*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_BOOLEAN)) != NULL &&
7819*5e7646d2SAndroid Build Coastguard Worker       attr->values[0].boolean)
7820*5e7646d2SAndroid Build Coastguard Worker     strlcpy(username, get_username(con), sizeof(username));
7821*5e7646d2SAndroid Build Coastguard Worker   else
7822*5e7646d2SAndroid Build Coastguard Worker     username[0] = '\0';
7823*5e7646d2SAndroid Build Coastguard Worker 
7824*5e7646d2SAndroid Build Coastguard Worker   for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0;
7825*5e7646d2SAndroid Build Coastguard Worker        sub;
7826*5e7646d2SAndroid Build Coastguard Worker        sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
7827*5e7646d2SAndroid Build Coastguard Worker     if ((!printer || sub->dest == printer) && (!job || sub->job == job) &&
7828*5e7646d2SAndroid Build Coastguard Worker         (!username[0] || !_cups_strcasecmp(username, sub->owner)))
7829*5e7646d2SAndroid Build Coastguard Worker     {
7830*5e7646d2SAndroid Build Coastguard Worker       ippAddSeparator(con->response);
7831*5e7646d2SAndroid Build Coastguard Worker 
7832*5e7646d2SAndroid Build Coastguard Worker       exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr :
7833*5e7646d2SAndroid Build Coastguard Worker 						 policy, con, sub->dest,
7834*5e7646d2SAndroid Build Coastguard Worker 						 sub->owner);
7835*5e7646d2SAndroid Build Coastguard Worker 
7836*5e7646d2SAndroid Build Coastguard Worker       copy_subscription_attrs(con, sub, ra, exclude);
7837*5e7646d2SAndroid Build Coastguard Worker 
7838*5e7646d2SAndroid Build Coastguard Worker       count ++;
7839*5e7646d2SAndroid Build Coastguard Worker       if (limit && count >= limit)
7840*5e7646d2SAndroid Build Coastguard Worker         break;
7841*5e7646d2SAndroid Build Coastguard Worker     }
7842*5e7646d2SAndroid Build Coastguard Worker 
7843*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(ra);
7844*5e7646d2SAndroid Build Coastguard Worker 
7845*5e7646d2SAndroid Build Coastguard Worker   if (count)
7846*5e7646d2SAndroid Build Coastguard Worker     con->response->request.status.status_code = IPP_OK;
7847*5e7646d2SAndroid Build Coastguard Worker   else
7848*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found."));
7849*5e7646d2SAndroid Build Coastguard Worker }
7850*5e7646d2SAndroid Build Coastguard Worker 
7851*5e7646d2SAndroid Build Coastguard Worker 
7852*5e7646d2SAndroid Build Coastguard Worker /*
7853*5e7646d2SAndroid Build Coastguard Worker  * 'get_username()' - Get the username associated with a request.
7854*5e7646d2SAndroid Build Coastguard Worker  */
7855*5e7646d2SAndroid Build Coastguard Worker 
7856*5e7646d2SAndroid Build Coastguard Worker static const char *			/* O - Username */
get_username(cupsd_client_t * con)7857*5e7646d2SAndroid Build Coastguard Worker get_username(cupsd_client_t *con)	/* I - Connection */
7858*5e7646d2SAndroid Build Coastguard Worker {
7859*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Attribute */
7860*5e7646d2SAndroid Build Coastguard Worker 
7861*5e7646d2SAndroid Build Coastguard Worker 
7862*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0])
7863*5e7646d2SAndroid Build Coastguard Worker     return (con->username);
7864*5e7646d2SAndroid Build Coastguard Worker   else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
7865*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_NAME)) != NULL)
7866*5e7646d2SAndroid Build Coastguard Worker     return (attr->values[0].string.text);
7867*5e7646d2SAndroid Build Coastguard Worker   else
7868*5e7646d2SAndroid Build Coastguard Worker     return ("anonymous");
7869*5e7646d2SAndroid Build Coastguard Worker }
7870*5e7646d2SAndroid Build Coastguard Worker 
7871*5e7646d2SAndroid Build Coastguard Worker 
7872*5e7646d2SAndroid Build Coastguard Worker /*
7873*5e7646d2SAndroid Build Coastguard Worker  * 'hold_job()' - Hold a print job.
7874*5e7646d2SAndroid Build Coastguard Worker  */
7875*5e7646d2SAndroid Build Coastguard Worker 
7876*5e7646d2SAndroid Build Coastguard Worker static void
hold_job(cupsd_client_t * con,ipp_attribute_t * uri)7877*5e7646d2SAndroid Build Coastguard Worker hold_job(cupsd_client_t  *con,		/* I - Client connection */
7878*5e7646d2SAndroid Build Coastguard Worker          ipp_attribute_t *uri)		/* I - Job or Printer URI */
7879*5e7646d2SAndroid Build Coastguard Worker {
7880*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current job-hold-until */
7881*5e7646d2SAndroid Build Coastguard Worker   const char	*when;			/* New value */
7882*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
7883*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
7884*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
7885*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
7886*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
7887*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
7888*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Job information */
7889*5e7646d2SAndroid Build Coastguard Worker 
7890*5e7646d2SAndroid Build Coastguard Worker 
7891*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->number,
7892*5e7646d2SAndroid Build Coastguard Worker                   uri->values[0].string.text);
7893*5e7646d2SAndroid Build Coastguard Worker 
7894*5e7646d2SAndroid Build Coastguard Worker  /*
7895*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
7896*5e7646d2SAndroid Build Coastguard Worker   */
7897*5e7646d2SAndroid Build Coastguard Worker 
7898*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
7899*5e7646d2SAndroid Build Coastguard Worker   {
7900*5e7646d2SAndroid Build Coastguard Worker    /*
7901*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
7902*5e7646d2SAndroid Build Coastguard Worker     */
7903*5e7646d2SAndroid Build Coastguard Worker 
7904*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
7905*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
7906*5e7646d2SAndroid Build Coastguard Worker     {
7907*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
7908*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
7909*5e7646d2SAndroid Build Coastguard Worker       return;
7910*5e7646d2SAndroid Build Coastguard Worker     }
7911*5e7646d2SAndroid Build Coastguard Worker 
7912*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
7913*5e7646d2SAndroid Build Coastguard Worker   }
7914*5e7646d2SAndroid Build Coastguard Worker   else
7915*5e7646d2SAndroid Build Coastguard Worker   {
7916*5e7646d2SAndroid Build Coastguard Worker    /*
7917*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
7918*5e7646d2SAndroid Build Coastguard Worker     */
7919*5e7646d2SAndroid Build Coastguard Worker 
7920*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
7921*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
7922*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
7923*5e7646d2SAndroid Build Coastguard Worker 
7924*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
7925*5e7646d2SAndroid Build Coastguard Worker     {
7926*5e7646d2SAndroid Build Coastguard Worker      /*
7927*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
7928*5e7646d2SAndroid Build Coastguard Worker       */
7929*5e7646d2SAndroid Build Coastguard Worker 
7930*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
7931*5e7646d2SAndroid Build Coastguard Worker                       _("Bad job-uri \"%s\"."),
7932*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
7933*5e7646d2SAndroid Build Coastguard Worker       return;
7934*5e7646d2SAndroid Build Coastguard Worker     }
7935*5e7646d2SAndroid Build Coastguard Worker 
7936*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
7937*5e7646d2SAndroid Build Coastguard Worker   }
7938*5e7646d2SAndroid Build Coastguard Worker 
7939*5e7646d2SAndroid Build Coastguard Worker  /*
7940*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
7941*5e7646d2SAndroid Build Coastguard Worker   */
7942*5e7646d2SAndroid Build Coastguard Worker 
7943*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
7944*5e7646d2SAndroid Build Coastguard Worker   {
7945*5e7646d2SAndroid Build Coastguard Worker    /*
7946*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
7947*5e7646d2SAndroid Build Coastguard Worker     */
7948*5e7646d2SAndroid Build Coastguard Worker 
7949*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
7950*5e7646d2SAndroid Build Coastguard Worker     return;
7951*5e7646d2SAndroid Build Coastguard Worker   }
7952*5e7646d2SAndroid Build Coastguard Worker 
7953*5e7646d2SAndroid Build Coastguard Worker  /*
7954*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
7955*5e7646d2SAndroid Build Coastguard Worker   */
7956*5e7646d2SAndroid Build Coastguard Worker 
7957*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
7958*5e7646d2SAndroid Build Coastguard Worker   {
7959*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
7960*5e7646d2SAndroid Build Coastguard Worker 		    cupsdFindDest(job->dest));
7961*5e7646d2SAndroid Build Coastguard Worker     return;
7962*5e7646d2SAndroid Build Coastguard Worker   }
7963*5e7646d2SAndroid Build Coastguard Worker 
7964*5e7646d2SAndroid Build Coastguard Worker  /*
7965*5e7646d2SAndroid Build Coastguard Worker   * See if the job is in a state that allows holding...
7966*5e7646d2SAndroid Build Coastguard Worker   */
7967*5e7646d2SAndroid Build Coastguard Worker 
7968*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value > IPP_JOB_STOPPED)
7969*5e7646d2SAndroid Build Coastguard Worker   {
7970*5e7646d2SAndroid Build Coastguard Worker    /*
7971*5e7646d2SAndroid Build Coastguard Worker     * Return a "not-possible" error...
7972*5e7646d2SAndroid Build Coastguard Worker     */
7973*5e7646d2SAndroid Build Coastguard Worker 
7974*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE,
7975*5e7646d2SAndroid Build Coastguard Worker 		    _("Job #%d is finished and cannot be altered."),
7976*5e7646d2SAndroid Build Coastguard Worker 		    job->id);
7977*5e7646d2SAndroid Build Coastguard Worker     return;
7978*5e7646d2SAndroid Build Coastguard Worker   }
7979*5e7646d2SAndroid Build Coastguard Worker 
7980*5e7646d2SAndroid Build Coastguard Worker  /*
7981*5e7646d2SAndroid Build Coastguard Worker   * Hold the job and return...
7982*5e7646d2SAndroid Build Coastguard Worker   */
7983*5e7646d2SAndroid Build Coastguard Worker 
7984*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL)
7985*5e7646d2SAndroid Build Coastguard Worker   {
7986*5e7646d2SAndroid Build Coastguard Worker     if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr))
7987*5e7646d2SAndroid Build Coastguard Worker     {
7988*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
7989*5e7646d2SAndroid Build Coastguard Worker       ippCopyAttribute(con->response, attr, 0);
7990*5e7646d2SAndroid Build Coastguard Worker       return;
7991*5e7646d2SAndroid Build Coastguard Worker     }
7992*5e7646d2SAndroid Build Coastguard Worker 
7993*5e7646d2SAndroid Build Coastguard Worker     when = ippGetString(attr, 0, NULL);
7994*5e7646d2SAndroid Build Coastguard Worker 
7995*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
7996*5e7646d2SAndroid Build Coastguard Worker 		  "Job job-hold-until value changed by user.");
7997*5e7646d2SAndroid Build Coastguard Worker   }
7998*5e7646d2SAndroid Build Coastguard Worker   else
7999*5e7646d2SAndroid Build Coastguard Worker     when = "indefinite";
8000*5e7646d2SAndroid Build Coastguard Worker 
8001*5e7646d2SAndroid Build Coastguard Worker   cupsdSetJobHoldUntil(job, when, 1);
8002*5e7646d2SAndroid Build Coastguard Worker   cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".",
8003*5e7646d2SAndroid Build Coastguard Worker                    username);
8004*5e7646d2SAndroid Build Coastguard Worker 
8005*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
8006*5e7646d2SAndroid Build Coastguard Worker }
8007*5e7646d2SAndroid Build Coastguard Worker 
8008*5e7646d2SAndroid Build Coastguard Worker 
8009*5e7646d2SAndroid Build Coastguard Worker /*
8010*5e7646d2SAndroid Build Coastguard Worker  * 'hold_new_jobs()' - Hold pending/new jobs on a printer or class.
8011*5e7646d2SAndroid Build Coastguard Worker  */
8012*5e7646d2SAndroid Build Coastguard Worker 
8013*5e7646d2SAndroid Build Coastguard Worker static void
hold_new_jobs(cupsd_client_t * con,ipp_attribute_t * uri)8014*5e7646d2SAndroid Build Coastguard Worker hold_new_jobs(cupsd_client_t  *con,	/* I - Connection */
8015*5e7646d2SAndroid Build Coastguard Worker               ipp_attribute_t *uri)	/* I - Printer URI */
8016*5e7646d2SAndroid Build Coastguard Worker {
8017*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
8018*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
8019*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer data */
8020*5e7646d2SAndroid Build Coastguard Worker 
8021*5e7646d2SAndroid Build Coastguard Worker 
8022*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con,
8023*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
8024*5e7646d2SAndroid Build Coastguard Worker 
8025*5e7646d2SAndroid Build Coastguard Worker  /*
8026*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
8027*5e7646d2SAndroid Build Coastguard Worker   */
8028*5e7646d2SAndroid Build Coastguard Worker 
8029*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
8030*5e7646d2SAndroid Build Coastguard Worker   {
8031*5e7646d2SAndroid Build Coastguard Worker    /*
8032*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
8033*5e7646d2SAndroid Build Coastguard Worker     */
8034*5e7646d2SAndroid Build Coastguard Worker 
8035*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
8036*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
8037*5e7646d2SAndroid Build Coastguard Worker     return;
8038*5e7646d2SAndroid Build Coastguard Worker   }
8039*5e7646d2SAndroid Build Coastguard Worker 
8040*5e7646d2SAndroid Build Coastguard Worker  /*
8041*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
8042*5e7646d2SAndroid Build Coastguard Worker   */
8043*5e7646d2SAndroid Build Coastguard Worker 
8044*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
8045*5e7646d2SAndroid Build Coastguard Worker   {
8046*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
8047*5e7646d2SAndroid Build Coastguard Worker     return;
8048*5e7646d2SAndroid Build Coastguard Worker   }
8049*5e7646d2SAndroid Build Coastguard Worker 
8050*5e7646d2SAndroid Build Coastguard Worker  /*
8051*5e7646d2SAndroid Build Coastguard Worker   * Hold pending/new jobs sent to the printer...
8052*5e7646d2SAndroid Build Coastguard Worker   */
8053*5e7646d2SAndroid Build Coastguard Worker 
8054*5e7646d2SAndroid Build Coastguard Worker   printer->holding_new_jobs = 1;
8055*5e7646d2SAndroid Build Coastguard Worker 
8056*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterReasons(printer, "+hold-new-jobs");
8057*5e7646d2SAndroid Build Coastguard Worker 
8058*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
8059*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
8060*5e7646d2SAndroid Build Coastguard Worker                     "Class \"%s\" now holding pending/new jobs (\"%s\").",
8061*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
8062*5e7646d2SAndroid Build Coastguard Worker   else
8063*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
8064*5e7646d2SAndroid Build Coastguard Worker                     "Printer \"%s\" now holding pending/new jobs (\"%s\").",
8065*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
8066*5e7646d2SAndroid Build Coastguard Worker 
8067*5e7646d2SAndroid Build Coastguard Worker  /*
8068*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
8069*5e7646d2SAndroid Build Coastguard Worker   */
8070*5e7646d2SAndroid Build Coastguard Worker 
8071*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
8072*5e7646d2SAndroid Build Coastguard Worker }
8073*5e7646d2SAndroid Build Coastguard Worker 
8074*5e7646d2SAndroid Build Coastguard Worker 
8075*5e7646d2SAndroid Build Coastguard Worker /*
8076*5e7646d2SAndroid Build Coastguard Worker  * 'move_job()' - Move a job to a new destination.
8077*5e7646d2SAndroid Build Coastguard Worker  */
8078*5e7646d2SAndroid Build Coastguard Worker 
8079*5e7646d2SAndroid Build Coastguard Worker static void
move_job(cupsd_client_t * con,ipp_attribute_t * uri)8080*5e7646d2SAndroid Build Coastguard Worker move_job(cupsd_client_t  *con,		/* I - Client connection */
8081*5e7646d2SAndroid Build Coastguard Worker 	 ipp_attribute_t *uri)		/* I - Job URI */
8082*5e7646d2SAndroid Build Coastguard Worker {
8083*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
8084*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
8085*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
8086*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
8087*5e7646d2SAndroid Build Coastguard Worker   const char	*src;			/* Source printer/class */
8088*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	stype,			/* Source type (printer or class) */
8089*5e7646d2SAndroid Build Coastguard Worker 		dtype;			/* Destination type (printer/class) */
8090*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Scheme portion of URI */
8091*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
8092*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
8093*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
8094*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
8095*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *sprinter,		/* Source printer */
8096*5e7646d2SAndroid Build Coastguard Worker 		*dprinter;		/* Destination printer */
8097*5e7646d2SAndroid Build Coastguard Worker 
8098*5e7646d2SAndroid Build Coastguard Worker 
8099*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->number,
8100*5e7646d2SAndroid Build Coastguard Worker                   uri->values[0].string.text);
8101*5e7646d2SAndroid Build Coastguard Worker 
8102*5e7646d2SAndroid Build Coastguard Worker  /*
8103*5e7646d2SAndroid Build Coastguard Worker   * Get the new printer or class...
8104*5e7646d2SAndroid Build Coastguard Worker   */
8105*5e7646d2SAndroid Build Coastguard Worker 
8106*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-printer-uri",
8107*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_URI)) == NULL)
8108*5e7646d2SAndroid Build Coastguard Worker   {
8109*5e7646d2SAndroid Build Coastguard Worker    /*
8110*5e7646d2SAndroid Build Coastguard Worker     * Need job-printer-uri...
8111*5e7646d2SAndroid Build Coastguard Worker     */
8112*5e7646d2SAndroid Build Coastguard Worker 
8113*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
8114*5e7646d2SAndroid Build Coastguard Worker                     _("job-printer-uri attribute missing."));
8115*5e7646d2SAndroid Build Coastguard Worker     return;
8116*5e7646d2SAndroid Build Coastguard Worker   }
8117*5e7646d2SAndroid Build Coastguard Worker 
8118*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(attr->values[0].string.text, &dtype, &dprinter))
8119*5e7646d2SAndroid Build Coastguard Worker   {
8120*5e7646d2SAndroid Build Coastguard Worker    /*
8121*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
8122*5e7646d2SAndroid Build Coastguard Worker     */
8123*5e7646d2SAndroid Build Coastguard Worker 
8124*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
8125*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
8126*5e7646d2SAndroid Build Coastguard Worker     return;
8127*5e7646d2SAndroid Build Coastguard Worker   }
8128*5e7646d2SAndroid Build Coastguard Worker 
8129*5e7646d2SAndroid Build Coastguard Worker  /*
8130*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
8131*5e7646d2SAndroid Build Coastguard Worker   */
8132*5e7646d2SAndroid Build Coastguard Worker 
8133*5e7646d2SAndroid Build Coastguard Worker   httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
8134*5e7646d2SAndroid Build Coastguard Worker                   sizeof(scheme), username, sizeof(username), host,
8135*5e7646d2SAndroid Build Coastguard Worker 		  sizeof(host), &port, resource, sizeof(resource));
8136*5e7646d2SAndroid Build Coastguard Worker 
8137*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
8138*5e7646d2SAndroid Build Coastguard Worker   {
8139*5e7646d2SAndroid Build Coastguard Worker    /*
8140*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
8141*5e7646d2SAndroid Build Coastguard Worker     */
8142*5e7646d2SAndroid Build Coastguard Worker 
8143*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
8144*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
8145*5e7646d2SAndroid Build Coastguard Worker     {
8146*5e7646d2SAndroid Build Coastguard Worker      /*
8147*5e7646d2SAndroid Build Coastguard Worker       * Move all jobs...
8148*5e7646d2SAndroid Build Coastguard Worker       */
8149*5e7646d2SAndroid Build Coastguard Worker 
8150*5e7646d2SAndroid Build Coastguard Worker       if ((src = cupsdValidateDest(uri->values[0].string.text, &stype,
8151*5e7646d2SAndroid Build Coastguard Worker                                    &sprinter)) == NULL)
8152*5e7646d2SAndroid Build Coastguard Worker       {
8153*5e7646d2SAndroid Build Coastguard Worker        /*
8154*5e7646d2SAndroid Build Coastguard Worker 	* Bad URI...
8155*5e7646d2SAndroid Build Coastguard Worker 	*/
8156*5e7646d2SAndroid Build Coastguard Worker 
8157*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND,
8158*5e7646d2SAndroid Build Coastguard Worker                 	_("The printer or class does not exist."));
8159*5e7646d2SAndroid Build Coastguard Worker 	return;
8160*5e7646d2SAndroid Build Coastguard Worker       }
8161*5e7646d2SAndroid Build Coastguard Worker 
8162*5e7646d2SAndroid Build Coastguard Worker       job = NULL;
8163*5e7646d2SAndroid Build Coastguard Worker     }
8164*5e7646d2SAndroid Build Coastguard Worker     else
8165*5e7646d2SAndroid Build Coastguard Worker     {
8166*5e7646d2SAndroid Build Coastguard Worker      /*
8167*5e7646d2SAndroid Build Coastguard Worker       * Otherwise, just move a single job...
8168*5e7646d2SAndroid Build Coastguard Worker       */
8169*5e7646d2SAndroid Build Coastguard Worker 
8170*5e7646d2SAndroid Build Coastguard Worker       if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
8171*5e7646d2SAndroid Build Coastguard Worker       {
8172*5e7646d2SAndroid Build Coastguard Worker        /*
8173*5e7646d2SAndroid Build Coastguard Worker 	* Nope - return a "not found" error...
8174*5e7646d2SAndroid Build Coastguard Worker 	*/
8175*5e7646d2SAndroid Build Coastguard Worker 
8176*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_FOUND,
8177*5e7646d2SAndroid Build Coastguard Worker                 	_("Job #%d does not exist."), attr->values[0].integer);
8178*5e7646d2SAndroid Build Coastguard Worker 	return;
8179*5e7646d2SAndroid Build Coastguard Worker       }
8180*5e7646d2SAndroid Build Coastguard Worker       else
8181*5e7646d2SAndroid Build Coastguard Worker       {
8182*5e7646d2SAndroid Build Coastguard Worker        /*
8183*5e7646d2SAndroid Build Coastguard Worker         * Job found, initialize source pointers...
8184*5e7646d2SAndroid Build Coastguard Worker 	*/
8185*5e7646d2SAndroid Build Coastguard Worker 
8186*5e7646d2SAndroid Build Coastguard Worker 	src      = NULL;
8187*5e7646d2SAndroid Build Coastguard Worker 	sprinter = NULL;
8188*5e7646d2SAndroid Build Coastguard Worker       }
8189*5e7646d2SAndroid Build Coastguard Worker     }
8190*5e7646d2SAndroid Build Coastguard Worker   }
8191*5e7646d2SAndroid Build Coastguard Worker   else
8192*5e7646d2SAndroid Build Coastguard Worker   {
8193*5e7646d2SAndroid Build Coastguard Worker    /*
8194*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
8195*5e7646d2SAndroid Build Coastguard Worker     */
8196*5e7646d2SAndroid Build Coastguard Worker 
8197*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
8198*5e7646d2SAndroid Build Coastguard Worker     {
8199*5e7646d2SAndroid Build Coastguard Worker      /*
8200*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
8201*5e7646d2SAndroid Build Coastguard Worker       */
8202*5e7646d2SAndroid Build Coastguard Worker 
8203*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
8204*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
8205*5e7646d2SAndroid Build Coastguard Worker       return;
8206*5e7646d2SAndroid Build Coastguard Worker     }
8207*5e7646d2SAndroid Build Coastguard Worker 
8208*5e7646d2SAndroid Build Coastguard Worker    /*
8209*5e7646d2SAndroid Build Coastguard Worker     * See if the job exists...
8210*5e7646d2SAndroid Build Coastguard Worker     */
8211*5e7646d2SAndroid Build Coastguard Worker 
8212*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
8213*5e7646d2SAndroid Build Coastguard Worker 
8214*5e7646d2SAndroid Build Coastguard Worker     if ((job = cupsdFindJob(jobid)) == NULL)
8215*5e7646d2SAndroid Build Coastguard Worker     {
8216*5e7646d2SAndroid Build Coastguard Worker      /*
8217*5e7646d2SAndroid Build Coastguard Worker       * Nope - return a "not found" error...
8218*5e7646d2SAndroid Build Coastguard Worker       */
8219*5e7646d2SAndroid Build Coastguard Worker 
8220*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
8221*5e7646d2SAndroid Build Coastguard Worker       return;
8222*5e7646d2SAndroid Build Coastguard Worker     }
8223*5e7646d2SAndroid Build Coastguard Worker     else
8224*5e7646d2SAndroid Build Coastguard Worker     {
8225*5e7646d2SAndroid Build Coastguard Worker      /*
8226*5e7646d2SAndroid Build Coastguard Worker       * Job found, initialize source pointers...
8227*5e7646d2SAndroid Build Coastguard Worker       */
8228*5e7646d2SAndroid Build Coastguard Worker 
8229*5e7646d2SAndroid Build Coastguard Worker       src      = NULL;
8230*5e7646d2SAndroid Build Coastguard Worker       sprinter = NULL;
8231*5e7646d2SAndroid Build Coastguard Worker     }
8232*5e7646d2SAndroid Build Coastguard Worker   }
8233*5e7646d2SAndroid Build Coastguard Worker 
8234*5e7646d2SAndroid Build Coastguard Worker  /*
8235*5e7646d2SAndroid Build Coastguard Worker   * Check the policy of the destination printer...
8236*5e7646d2SAndroid Build Coastguard Worker   */
8237*5e7646d2SAndroid Build Coastguard Worker 
8238*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con,
8239*5e7646d2SAndroid Build Coastguard Worker                                  job ? job->username : NULL)) != HTTP_OK)
8240*5e7646d2SAndroid Build Coastguard Worker   {
8241*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, dprinter);
8242*5e7646d2SAndroid Build Coastguard Worker     return;
8243*5e7646d2SAndroid Build Coastguard Worker   }
8244*5e7646d2SAndroid Build Coastguard Worker 
8245*5e7646d2SAndroid Build Coastguard Worker  /*
8246*5e7646d2SAndroid Build Coastguard Worker   * Now move the job or jobs...
8247*5e7646d2SAndroid Build Coastguard Worker   */
8248*5e7646d2SAndroid Build Coastguard Worker 
8249*5e7646d2SAndroid Build Coastguard Worker   if (job)
8250*5e7646d2SAndroid Build Coastguard Worker   {
8251*5e7646d2SAndroid Build Coastguard Worker    /*
8252*5e7646d2SAndroid Build Coastguard Worker     * See if the job has been completed...
8253*5e7646d2SAndroid Build Coastguard Worker     */
8254*5e7646d2SAndroid Build Coastguard Worker 
8255*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value > IPP_JOB_STOPPED)
8256*5e7646d2SAndroid Build Coastguard Worker     {
8257*5e7646d2SAndroid Build Coastguard Worker      /*
8258*5e7646d2SAndroid Build Coastguard Worker       * Return a "not-possible" error...
8259*5e7646d2SAndroid Build Coastguard Worker       */
8260*5e7646d2SAndroid Build Coastguard Worker 
8261*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_NOT_POSSIBLE,
8262*5e7646d2SAndroid Build Coastguard Worker                       _("Job #%d is finished and cannot be altered."),
8263*5e7646d2SAndroid Build Coastguard Worker 		      job->id);
8264*5e7646d2SAndroid Build Coastguard Worker       return;
8265*5e7646d2SAndroid Build Coastguard Worker     }
8266*5e7646d2SAndroid Build Coastguard Worker 
8267*5e7646d2SAndroid Build Coastguard Worker    /*
8268*5e7646d2SAndroid Build Coastguard Worker     * See if the job is owned by the requesting user...
8269*5e7646d2SAndroid Build Coastguard Worker     */
8270*5e7646d2SAndroid Build Coastguard Worker 
8271*5e7646d2SAndroid Build Coastguard Worker     if (!validate_user(job, con, job->username, username, sizeof(username)))
8272*5e7646d2SAndroid Build Coastguard Worker     {
8273*5e7646d2SAndroid Build Coastguard Worker       send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
8274*5e7646d2SAndroid Build Coastguard Worker                       cupsdFindDest(job->dest));
8275*5e7646d2SAndroid Build Coastguard Worker       return;
8276*5e7646d2SAndroid Build Coastguard Worker     }
8277*5e7646d2SAndroid Build Coastguard Worker 
8278*5e7646d2SAndroid Build Coastguard Worker    /*
8279*5e7646d2SAndroid Build Coastguard Worker     * Move the job to a different printer or class...
8280*5e7646d2SAndroid Build Coastguard Worker     */
8281*5e7646d2SAndroid Build Coastguard Worker 
8282*5e7646d2SAndroid Build Coastguard Worker     cupsdMoveJob(job, dprinter);
8283*5e7646d2SAndroid Build Coastguard Worker   }
8284*5e7646d2SAndroid Build Coastguard Worker   else
8285*5e7646d2SAndroid Build Coastguard Worker   {
8286*5e7646d2SAndroid Build Coastguard Worker    /*
8287*5e7646d2SAndroid Build Coastguard Worker     * Got the source printer, now look through the jobs...
8288*5e7646d2SAndroid Build Coastguard Worker     */
8289*5e7646d2SAndroid Build Coastguard Worker 
8290*5e7646d2SAndroid Build Coastguard Worker     for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
8291*5e7646d2SAndroid Build Coastguard Worker          job;
8292*5e7646d2SAndroid Build Coastguard Worker 	 job = (cupsd_job_t *)cupsArrayNext(Jobs))
8293*5e7646d2SAndroid Build Coastguard Worker     {
8294*5e7646d2SAndroid Build Coastguard Worker      /*
8295*5e7646d2SAndroid Build Coastguard Worker       * See if the job is pointing at the source printer or has not been
8296*5e7646d2SAndroid Build Coastguard Worker       * completed...
8297*5e7646d2SAndroid Build Coastguard Worker       */
8298*5e7646d2SAndroid Build Coastguard Worker 
8299*5e7646d2SAndroid Build Coastguard Worker       if (_cups_strcasecmp(job->dest, src) ||
8300*5e7646d2SAndroid Build Coastguard Worker           job->state_value > IPP_JOB_STOPPED)
8301*5e7646d2SAndroid Build Coastguard Worker 	continue;
8302*5e7646d2SAndroid Build Coastguard Worker 
8303*5e7646d2SAndroid Build Coastguard Worker      /*
8304*5e7646d2SAndroid Build Coastguard Worker       * See if the job can be moved by the requesting user...
8305*5e7646d2SAndroid Build Coastguard Worker       */
8306*5e7646d2SAndroid Build Coastguard Worker 
8307*5e7646d2SAndroid Build Coastguard Worker       if (!validate_user(job, con, job->username, username, sizeof(username)))
8308*5e7646d2SAndroid Build Coastguard Worker         continue;
8309*5e7646d2SAndroid Build Coastguard Worker 
8310*5e7646d2SAndroid Build Coastguard Worker      /*
8311*5e7646d2SAndroid Build Coastguard Worker       * Move the job to a different printer or class...
8312*5e7646d2SAndroid Build Coastguard Worker       */
8313*5e7646d2SAndroid Build Coastguard Worker 
8314*5e7646d2SAndroid Build Coastguard Worker       cupsdMoveJob(job, dprinter);
8315*5e7646d2SAndroid Build Coastguard Worker     }
8316*5e7646d2SAndroid Build Coastguard Worker   }
8317*5e7646d2SAndroid Build Coastguard Worker 
8318*5e7646d2SAndroid Build Coastguard Worker  /*
8319*5e7646d2SAndroid Build Coastguard Worker   * Start jobs if possible...
8320*5e7646d2SAndroid Build Coastguard Worker   */
8321*5e7646d2SAndroid Build Coastguard Worker 
8322*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
8323*5e7646d2SAndroid Build Coastguard Worker 
8324*5e7646d2SAndroid Build Coastguard Worker  /*
8325*5e7646d2SAndroid Build Coastguard Worker   * Return with "everything is OK" status...
8326*5e7646d2SAndroid Build Coastguard Worker   */
8327*5e7646d2SAndroid Build Coastguard Worker 
8328*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
8329*5e7646d2SAndroid Build Coastguard Worker }
8330*5e7646d2SAndroid Build Coastguard Worker 
8331*5e7646d2SAndroid Build Coastguard Worker 
8332*5e7646d2SAndroid Build Coastguard Worker /*
8333*5e7646d2SAndroid Build Coastguard Worker  * 'ppd_parse_line()' - Parse a PPD default line.
8334*5e7646d2SAndroid Build Coastguard Worker  */
8335*5e7646d2SAndroid Build Coastguard Worker 
8336*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on failure */
ppd_parse_line(const char * line,char * option,int olen,char * choice,int clen)8337*5e7646d2SAndroid Build Coastguard Worker ppd_parse_line(const char *line,	/* I - Line */
8338*5e7646d2SAndroid Build Coastguard Worker                char       *option,	/* O - Option name */
8339*5e7646d2SAndroid Build Coastguard Worker 	       int        olen,		/* I - Size of option name */
8340*5e7646d2SAndroid Build Coastguard Worker                char       *choice,	/* O - Choice name */
8341*5e7646d2SAndroid Build Coastguard Worker 	       int        clen)		/* I - Size of choice name */
8342*5e7646d2SAndroid Build Coastguard Worker {
8343*5e7646d2SAndroid Build Coastguard Worker  /*
8344*5e7646d2SAndroid Build Coastguard Worker   * Verify this is a default option line...
8345*5e7646d2SAndroid Build Coastguard Worker   */
8346*5e7646d2SAndroid Build Coastguard Worker 
8347*5e7646d2SAndroid Build Coastguard Worker   if (strncmp(line, "*Default", 8))
8348*5e7646d2SAndroid Build Coastguard Worker     return (-1);
8349*5e7646d2SAndroid Build Coastguard Worker 
8350*5e7646d2SAndroid Build Coastguard Worker  /*
8351*5e7646d2SAndroid Build Coastguard Worker   * Read the option name...
8352*5e7646d2SAndroid Build Coastguard Worker   */
8353*5e7646d2SAndroid Build Coastguard Worker 
8354*5e7646d2SAndroid Build Coastguard Worker   for (line += 8, olen --;
8355*5e7646d2SAndroid Build Coastguard Worker        *line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
8356*5e7646d2SAndroid Build Coastguard Worker        line ++)
8357*5e7646d2SAndroid Build Coastguard Worker     if (olen > 0)
8358*5e7646d2SAndroid Build Coastguard Worker     {
8359*5e7646d2SAndroid Build Coastguard Worker       *option++ = *line;
8360*5e7646d2SAndroid Build Coastguard Worker       olen --;
8361*5e7646d2SAndroid Build Coastguard Worker     }
8362*5e7646d2SAndroid Build Coastguard Worker 
8363*5e7646d2SAndroid Build Coastguard Worker   *option = '\0';
8364*5e7646d2SAndroid Build Coastguard Worker 
8365*5e7646d2SAndroid Build Coastguard Worker  /*
8366*5e7646d2SAndroid Build Coastguard Worker   * Skip everything else up to the colon (:)...
8367*5e7646d2SAndroid Build Coastguard Worker   */
8368*5e7646d2SAndroid Build Coastguard Worker 
8369*5e7646d2SAndroid Build Coastguard Worker   while (*line && *line != ':')
8370*5e7646d2SAndroid Build Coastguard Worker     line ++;
8371*5e7646d2SAndroid Build Coastguard Worker 
8372*5e7646d2SAndroid Build Coastguard Worker   if (!*line)
8373*5e7646d2SAndroid Build Coastguard Worker     return (-1);
8374*5e7646d2SAndroid Build Coastguard Worker 
8375*5e7646d2SAndroid Build Coastguard Worker   line ++;
8376*5e7646d2SAndroid Build Coastguard Worker 
8377*5e7646d2SAndroid Build Coastguard Worker  /*
8378*5e7646d2SAndroid Build Coastguard Worker   * Now grab the option choice, skipping leading whitespace...
8379*5e7646d2SAndroid Build Coastguard Worker   */
8380*5e7646d2SAndroid Build Coastguard Worker 
8381*5e7646d2SAndroid Build Coastguard Worker   while (isspace(*line & 255))
8382*5e7646d2SAndroid Build Coastguard Worker     line ++;
8383*5e7646d2SAndroid Build Coastguard Worker 
8384*5e7646d2SAndroid Build Coastguard Worker   for (clen --;
8385*5e7646d2SAndroid Build Coastguard Worker        *line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
8386*5e7646d2SAndroid Build Coastguard Worker        line ++)
8387*5e7646d2SAndroid Build Coastguard Worker     if (clen > 0)
8388*5e7646d2SAndroid Build Coastguard Worker     {
8389*5e7646d2SAndroid Build Coastguard Worker       *choice++ = *line;
8390*5e7646d2SAndroid Build Coastguard Worker       clen --;
8391*5e7646d2SAndroid Build Coastguard Worker     }
8392*5e7646d2SAndroid Build Coastguard Worker 
8393*5e7646d2SAndroid Build Coastguard Worker   *choice = '\0';
8394*5e7646d2SAndroid Build Coastguard Worker 
8395*5e7646d2SAndroid Build Coastguard Worker  /*
8396*5e7646d2SAndroid Build Coastguard Worker   * Return with no errors...
8397*5e7646d2SAndroid Build Coastguard Worker   */
8398*5e7646d2SAndroid Build Coastguard Worker 
8399*5e7646d2SAndroid Build Coastguard Worker   return (0);
8400*5e7646d2SAndroid Build Coastguard Worker }
8401*5e7646d2SAndroid Build Coastguard Worker 
8402*5e7646d2SAndroid Build Coastguard Worker 
8403*5e7646d2SAndroid Build Coastguard Worker /*
8404*5e7646d2SAndroid Build Coastguard Worker  * 'print_job()' - Print a file to a printer or class.
8405*5e7646d2SAndroid Build Coastguard Worker  */
8406*5e7646d2SAndroid Build Coastguard Worker 
8407*5e7646d2SAndroid Build Coastguard Worker static void
print_job(cupsd_client_t * con,ipp_attribute_t * uri)8408*5e7646d2SAndroid Build Coastguard Worker print_job(cupsd_client_t  *con,		/* I - Client connection */
8409*5e7646d2SAndroid Build Coastguard Worker 	  ipp_attribute_t *uri)		/* I - Printer URI */
8410*5e7646d2SAndroid Build Coastguard Worker {
8411*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
8412*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *doc_name;		/* document-name attribute */
8413*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *format;		/* Document-format attribute */
8414*5e7646d2SAndroid Build Coastguard Worker   const char	*default_format;	/* document-format-default value */
8415*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* New job */
8416*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Job filename */
8417*5e7646d2SAndroid Build Coastguard Worker   mime_type_t	*filetype;		/* Type of file */
8418*5e7646d2SAndroid Build Coastguard Worker   char		super[MIME_MAX_SUPER],	/* Supertype of file */
8419*5e7646d2SAndroid Build Coastguard Worker 		type[MIME_MAX_TYPE],	/* Subtype of file */
8420*5e7646d2SAndroid Build Coastguard Worker 		mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
8421*5e7646d2SAndroid Build Coastguard Worker 					/* Textual name of mime type */
8422*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer data */
8423*5e7646d2SAndroid Build Coastguard Worker   struct stat	fileinfo;		/* File information */
8424*5e7646d2SAndroid Build Coastguard Worker   int		kbytes;			/* Size of file */
8425*5e7646d2SAndroid Build Coastguard Worker   int		compression;		/* Document compression */
8426*5e7646d2SAndroid Build Coastguard Worker 
8427*5e7646d2SAndroid Build Coastguard Worker 
8428*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->number,
8429*5e7646d2SAndroid Build Coastguard Worker                   uri->values[0].string.text);
8430*5e7646d2SAndroid Build Coastguard Worker 
8431*5e7646d2SAndroid Build Coastguard Worker  /*
8432*5e7646d2SAndroid Build Coastguard Worker   * Validate print file attributes, for now just document-format and
8433*5e7646d2SAndroid Build Coastguard Worker   * compression (CUPS only supports "none" and "gzip")...
8434*5e7646d2SAndroid Build Coastguard Worker   */
8435*5e7646d2SAndroid Build Coastguard Worker 
8436*5e7646d2SAndroid Build Coastguard Worker   compression = CUPS_FILE_NONE;
8437*5e7646d2SAndroid Build Coastguard Worker 
8438*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "compression",
8439*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
8440*5e7646d2SAndroid Build Coastguard Worker   {
8441*5e7646d2SAndroid Build Coastguard Worker     if (strcmp(attr->values[0].string.text, "none")
8442*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LIBZ
8443*5e7646d2SAndroid Build Coastguard Worker         && strcmp(attr->values[0].string.text, "gzip")
8444*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LIBZ */
8445*5e7646d2SAndroid Build Coastguard Worker       )
8446*5e7646d2SAndroid Build Coastguard Worker     {
8447*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES,
8448*5e7646d2SAndroid Build Coastguard Worker                       _("Unsupported compression \"%s\"."),
8449*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].string.text);
8450*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
8451*5e7646d2SAndroid Build Coastguard Worker 	           "compression", NULL, attr->values[0].string.text);
8452*5e7646d2SAndroid Build Coastguard Worker       return;
8453*5e7646d2SAndroid Build Coastguard Worker     }
8454*5e7646d2SAndroid Build Coastguard Worker 
8455*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LIBZ
8456*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->values[0].string.text, "gzip"))
8457*5e7646d2SAndroid Build Coastguard Worker       compression = CUPS_FILE_GZIP;
8458*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LIBZ */
8459*5e7646d2SAndroid Build Coastguard Worker   }
8460*5e7646d2SAndroid Build Coastguard Worker 
8461*5e7646d2SAndroid Build Coastguard Worker  /*
8462*5e7646d2SAndroid Build Coastguard Worker   * Do we have a file to print?
8463*5e7646d2SAndroid Build Coastguard Worker   */
8464*5e7646d2SAndroid Build Coastguard Worker 
8465*5e7646d2SAndroid Build Coastguard Worker   if (!con->filename)
8466*5e7646d2SAndroid Build Coastguard Worker   {
8467*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
8468*5e7646d2SAndroid Build Coastguard Worker     return;
8469*5e7646d2SAndroid Build Coastguard Worker   }
8470*5e7646d2SAndroid Build Coastguard Worker 
8471*5e7646d2SAndroid Build Coastguard Worker  /*
8472*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
8473*5e7646d2SAndroid Build Coastguard Worker   */
8474*5e7646d2SAndroid Build Coastguard Worker 
8475*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
8476*5e7646d2SAndroid Build Coastguard Worker   {
8477*5e7646d2SAndroid Build Coastguard Worker    /*
8478*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
8479*5e7646d2SAndroid Build Coastguard Worker     */
8480*5e7646d2SAndroid Build Coastguard Worker 
8481*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
8482*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
8483*5e7646d2SAndroid Build Coastguard Worker     return;
8484*5e7646d2SAndroid Build Coastguard Worker   }
8485*5e7646d2SAndroid Build Coastguard Worker 
8486*5e7646d2SAndroid Build Coastguard Worker  /*
8487*5e7646d2SAndroid Build Coastguard Worker   * Is it a format we support?
8488*5e7646d2SAndroid Build Coastguard Worker   */
8489*5e7646d2SAndroid Build Coastguard Worker 
8490*5e7646d2SAndroid Build Coastguard Worker   doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
8491*5e7646d2SAndroid Build Coastguard Worker   if (doc_name)
8492*5e7646d2SAndroid Build Coastguard Worker     ippSetName(con->request, &doc_name, "document-name-supplied");
8493*5e7646d2SAndroid Build Coastguard Worker 
8494*5e7646d2SAndroid Build Coastguard Worker   if ((format = ippFindAttribute(con->request, "document-format",
8495*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_MIMETYPE)) != NULL)
8496*5e7646d2SAndroid Build Coastguard Worker   {
8497*5e7646d2SAndroid Build Coastguard Worker    /*
8498*5e7646d2SAndroid Build Coastguard Worker     * Grab format from client...
8499*5e7646d2SAndroid Build Coastguard Worker     */
8500*5e7646d2SAndroid Build Coastguard Worker 
8501*5e7646d2SAndroid Build Coastguard Worker     if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super,
8502*5e7646d2SAndroid Build Coastguard Worker                type) != 2)
8503*5e7646d2SAndroid Build Coastguard Worker     {
8504*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
8505*5e7646d2SAndroid Build Coastguard Worker                       _("Bad document-format \"%s\"."),
8506*5e7646d2SAndroid Build Coastguard Worker 		      format->values[0].string.text);
8507*5e7646d2SAndroid Build Coastguard Worker       return;
8508*5e7646d2SAndroid Build Coastguard Worker     }
8509*5e7646d2SAndroid Build Coastguard Worker 
8510*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL));
8511*5e7646d2SAndroid Build Coastguard Worker   }
8512*5e7646d2SAndroid Build Coastguard Worker   else if ((default_format = cupsGetOption("document-format",
8513*5e7646d2SAndroid Build Coastguard Worker                                            printer->num_options,
8514*5e7646d2SAndroid Build Coastguard Worker 					   printer->options)) != NULL)
8515*5e7646d2SAndroid Build Coastguard Worker   {
8516*5e7646d2SAndroid Build Coastguard Worker    /*
8517*5e7646d2SAndroid Build Coastguard Worker     * Use default document format...
8518*5e7646d2SAndroid Build Coastguard Worker     */
8519*5e7646d2SAndroid Build Coastguard Worker 
8520*5e7646d2SAndroid Build Coastguard Worker     if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2)
8521*5e7646d2SAndroid Build Coastguard Worker     {
8522*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
8523*5e7646d2SAndroid Build Coastguard Worker                       _("Bad document-format \"%s\"."),
8524*5e7646d2SAndroid Build Coastguard Worker 		      default_format);
8525*5e7646d2SAndroid Build Coastguard Worker       return;
8526*5e7646d2SAndroid Build Coastguard Worker     }
8527*5e7646d2SAndroid Build Coastguard Worker   }
8528*5e7646d2SAndroid Build Coastguard Worker   else
8529*5e7646d2SAndroid Build Coastguard Worker   {
8530*5e7646d2SAndroid Build Coastguard Worker    /*
8531*5e7646d2SAndroid Build Coastguard Worker     * Auto-type it!
8532*5e7646d2SAndroid Build Coastguard Worker     */
8533*5e7646d2SAndroid Build Coastguard Worker 
8534*5e7646d2SAndroid Build Coastguard Worker     strlcpy(super, "application", sizeof(super));
8535*5e7646d2SAndroid Build Coastguard Worker     strlcpy(type, "octet-stream", sizeof(type));
8536*5e7646d2SAndroid Build Coastguard Worker   }
8537*5e7646d2SAndroid Build Coastguard Worker 
8538*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
8539*5e7646d2SAndroid Build Coastguard Worker   {
8540*5e7646d2SAndroid Build Coastguard Worker    /*
8541*5e7646d2SAndroid Build Coastguard Worker     * Auto-type the file...
8542*5e7646d2SAndroid Build Coastguard Worker     */
8543*5e7646d2SAndroid Build Coastguard Worker 
8544*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job ???] Auto-typing file...");
8545*5e7646d2SAndroid Build Coastguard Worker 
8546*5e7646d2SAndroid Build Coastguard Worker 
8547*5e7646d2SAndroid Build Coastguard Worker     filetype = mimeFileType(MimeDatabase, con->filename,
8548*5e7646d2SAndroid Build Coastguard Worker                             doc_name ? doc_name->values[0].string.text : NULL,
8549*5e7646d2SAndroid Build Coastguard Worker 			    &compression);
8550*5e7646d2SAndroid Build Coastguard Worker 
8551*5e7646d2SAndroid Build Coastguard Worker     if (!filetype)
8552*5e7646d2SAndroid Build Coastguard Worker       filetype = mimeType(MimeDatabase, super, type);
8553*5e7646d2SAndroid Build Coastguard Worker 
8554*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "[Job ???] Request file type is %s/%s.",
8555*5e7646d2SAndroid Build Coastguard Worker 		    filetype->super, filetype->type);
8556*5e7646d2SAndroid Build Coastguard Worker 
8557*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type);
8558*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype);
8559*5e7646d2SAndroid Build Coastguard Worker   }
8560*5e7646d2SAndroid Build Coastguard Worker   else
8561*5e7646d2SAndroid Build Coastguard Worker     filetype = mimeType(MimeDatabase, super, type);
8562*5e7646d2SAndroid Build Coastguard Worker 
8563*5e7646d2SAndroid Build Coastguard Worker   if (filetype &&
8564*5e7646d2SAndroid Build Coastguard Worker       (!format ||
8565*5e7646d2SAndroid Build Coastguard Worker        (!strcmp(super, "application") && !strcmp(type, "octet-stream"))))
8566*5e7646d2SAndroid Build Coastguard Worker   {
8567*5e7646d2SAndroid Build Coastguard Worker    /*
8568*5e7646d2SAndroid Build Coastguard Worker     * Replace the document-format attribute value with the auto-typed or
8569*5e7646d2SAndroid Build Coastguard Worker     * default one.
8570*5e7646d2SAndroid Build Coastguard Worker     */
8571*5e7646d2SAndroid Build Coastguard Worker 
8572*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
8573*5e7646d2SAndroid Build Coastguard Worker              filetype->type);
8574*5e7646d2SAndroid Build Coastguard Worker 
8575*5e7646d2SAndroid Build Coastguard Worker     if (format)
8576*5e7646d2SAndroid Build Coastguard Worker       ippSetString(con->request, &format, 0, mimetype);
8577*5e7646d2SAndroid Build Coastguard Worker     else
8578*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
8579*5e7646d2SAndroid Build Coastguard Worker 	           "document-format", NULL, mimetype);
8580*5e7646d2SAndroid Build Coastguard Worker   }
8581*5e7646d2SAndroid Build Coastguard Worker   else if (!filetype)
8582*5e7646d2SAndroid Build Coastguard Worker   {
8583*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_DOCUMENT_FORMAT,
8584*5e7646d2SAndroid Build Coastguard Worker                     _("Unsupported document-format \"%s\"."),
8585*5e7646d2SAndroid Build Coastguard Worker 		    format ? format->values[0].string.text :
8586*5e7646d2SAndroid Build Coastguard Worker 			     "application/octet-stream");
8587*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
8588*5e7646d2SAndroid Build Coastguard Worker                     "Hint: Do you have the raw file printing rules enabled?");
8589*5e7646d2SAndroid Build Coastguard Worker 
8590*5e7646d2SAndroid Build Coastguard Worker     if (format)
8591*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
8592*5e7646d2SAndroid Build Coastguard Worker                    "document-format", NULL, format->values[0].string.text);
8593*5e7646d2SAndroid Build Coastguard Worker 
8594*5e7646d2SAndroid Build Coastguard Worker     return;
8595*5e7646d2SAndroid Build Coastguard Worker   }
8596*5e7646d2SAndroid Build Coastguard Worker 
8597*5e7646d2SAndroid Build Coastguard Worker  /*
8598*5e7646d2SAndroid Build Coastguard Worker   * Read any embedded job ticket info from PS files...
8599*5e7646d2SAndroid Build Coastguard Worker   */
8600*5e7646d2SAndroid Build Coastguard Worker 
8601*5e7646d2SAndroid Build Coastguard Worker   if (!_cups_strcasecmp(filetype->super, "application") &&
8602*5e7646d2SAndroid Build Coastguard Worker       (!_cups_strcasecmp(filetype->type, "postscript") ||
8603*5e7646d2SAndroid Build Coastguard Worker        !_cups_strcasecmp(filetype->type, "pdf")))
8604*5e7646d2SAndroid Build Coastguard Worker     read_job_ticket(con);
8605*5e7646d2SAndroid Build Coastguard Worker 
8606*5e7646d2SAndroid Build Coastguard Worker  /*
8607*5e7646d2SAndroid Build Coastguard Worker   * Create the job object...
8608*5e7646d2SAndroid Build Coastguard Worker   */
8609*5e7646d2SAndroid Build Coastguard Worker 
8610*5e7646d2SAndroid Build Coastguard Worker   if ((job = add_job(con, printer, filetype)) == NULL)
8611*5e7646d2SAndroid Build Coastguard Worker     return;
8612*5e7646d2SAndroid Build Coastguard Worker 
8613*5e7646d2SAndroid Build Coastguard Worker  /*
8614*5e7646d2SAndroid Build Coastguard Worker   * Update quota data...
8615*5e7646d2SAndroid Build Coastguard Worker   */
8616*5e7646d2SAndroid Build Coastguard Worker 
8617*5e7646d2SAndroid Build Coastguard Worker   if (stat(con->filename, &fileinfo))
8618*5e7646d2SAndroid Build Coastguard Worker     kbytes = 0;
8619*5e7646d2SAndroid Build Coastguard Worker   else
8620*5e7646d2SAndroid Build Coastguard Worker     kbytes = (fileinfo.st_size + 1023) / 1024;
8621*5e7646d2SAndroid Build Coastguard Worker 
8622*5e7646d2SAndroid Build Coastguard Worker   cupsdUpdateQuota(printer, job->username, 0, kbytes);
8623*5e7646d2SAndroid Build Coastguard Worker 
8624*5e7646d2SAndroid Build Coastguard Worker   job->koctets += kbytes;
8625*5e7646d2SAndroid Build Coastguard Worker 
8626*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
8627*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer += kbytes;
8628*5e7646d2SAndroid Build Coastguard Worker 
8629*5e7646d2SAndroid Build Coastguard Worker  /*
8630*5e7646d2SAndroid Build Coastguard Worker   * Add the job file...
8631*5e7646d2SAndroid Build Coastguard Worker   */
8632*5e7646d2SAndroid Build Coastguard Worker 
8633*5e7646d2SAndroid Build Coastguard Worker   if (add_file(con, job, filetype, compression))
8634*5e7646d2SAndroid Build Coastguard Worker     return;
8635*5e7646d2SAndroid Build Coastguard Worker 
8636*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files);
8637*5e7646d2SAndroid Build Coastguard Worker   if (rename(con->filename, filename))
8638*5e7646d2SAndroid Build Coastguard Worker   {
8639*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno));
8640*5e7646d2SAndroid Build Coastguard Worker 
8641*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file."));
8642*5e7646d2SAndroid Build Coastguard Worker     return;
8643*5e7646d2SAndroid Build Coastguard Worker   }
8644*5e7646d2SAndroid Build Coastguard Worker 
8645*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&con->filename);
8646*5e7646d2SAndroid Build Coastguard Worker 
8647*5e7646d2SAndroid Build Coastguard Worker  /*
8648*5e7646d2SAndroid Build Coastguard Worker   * See if we need to add the ending sheet...
8649*5e7646d2SAndroid Build Coastguard Worker   */
8650*5e7646d2SAndroid Build Coastguard Worker 
8651*5e7646d2SAndroid Build Coastguard Worker   if (cupsdTimeoutJob(job))
8652*5e7646d2SAndroid Build Coastguard Worker     return;
8653*5e7646d2SAndroid Build Coastguard Worker 
8654*5e7646d2SAndroid Build Coastguard Worker  /*
8655*5e7646d2SAndroid Build Coastguard Worker   * Log and save the job...
8656*5e7646d2SAndroid Build Coastguard Worker   */
8657*5e7646d2SAndroid Build Coastguard Worker 
8658*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO,
8659*5e7646d2SAndroid Build Coastguard Worker 	      "File of type %s/%s queued by \"%s\".",
8660*5e7646d2SAndroid Build Coastguard Worker 	      filetype->super, filetype->type, job->username);
8661*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_DEBUG, "hold_until=%d", (int)job->hold_until);
8662*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
8663*5e7646d2SAndroid Build Coastguard Worker 	      job->dest, job->username);
8664*5e7646d2SAndroid Build Coastguard Worker 
8665*5e7646d2SAndroid Build Coastguard Worker  /*
8666*5e7646d2SAndroid Build Coastguard Worker   * Start the job if possible...
8667*5e7646d2SAndroid Build Coastguard Worker   */
8668*5e7646d2SAndroid Build Coastguard Worker 
8669*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
8670*5e7646d2SAndroid Build Coastguard Worker }
8671*5e7646d2SAndroid Build Coastguard Worker 
8672*5e7646d2SAndroid Build Coastguard Worker 
8673*5e7646d2SAndroid Build Coastguard Worker /*
8674*5e7646d2SAndroid Build Coastguard Worker  * 'read_job_ticket()' - Read a job ticket embedded in a print file.
8675*5e7646d2SAndroid Build Coastguard Worker  *
8676*5e7646d2SAndroid Build Coastguard Worker  * This function only gets called when printing a single PDF or PostScript
8677*5e7646d2SAndroid Build Coastguard Worker  * file using the Print-Job operation.  It doesn't work for Create-Job +
8678*5e7646d2SAndroid Build Coastguard Worker  * Send-File, since the job attributes need to be set at job creation
8679*5e7646d2SAndroid Build Coastguard Worker  * time for banners to work.  The embedded job ticket stuff is here
8680*5e7646d2SAndroid Build Coastguard Worker  * primarily to allow the Windows printer driver for CUPS to pass in JCL
8681*5e7646d2SAndroid Build Coastguard Worker  * options and IPP attributes which otherwise would be lost.
8682*5e7646d2SAndroid Build Coastguard Worker  *
8683*5e7646d2SAndroid Build Coastguard Worker  * The format of a job ticket is simple:
8684*5e7646d2SAndroid Build Coastguard Worker  *
8685*5e7646d2SAndroid Build Coastguard Worker  *     %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
8686*5e7646d2SAndroid Build Coastguard Worker  *
8687*5e7646d2SAndroid Build Coastguard Worker  *     %cupsJobTicket: attr1=value1
8688*5e7646d2SAndroid Build Coastguard Worker  *     %cupsJobTicket: attr2=value2
8689*5e7646d2SAndroid Build Coastguard Worker  *     ...
8690*5e7646d2SAndroid Build Coastguard Worker  *     %cupsJobTicket: attrN=valueN
8691*5e7646d2SAndroid Build Coastguard Worker  *
8692*5e7646d2SAndroid Build Coastguard Worker  * Job ticket lines must appear immediately after the first line that
8693*5e7646d2SAndroid Build Coastguard Worker  * specifies PostScript (%!PS-Adobe-3.0) or PDF (%PDF) format, and CUPS
8694*5e7646d2SAndroid Build Coastguard Worker  * stops looking for job ticket info when it finds a line that does not begin
8695*5e7646d2SAndroid Build Coastguard Worker  * with "%cupsJobTicket:".
8696*5e7646d2SAndroid Build Coastguard Worker  *
8697*5e7646d2SAndroid Build Coastguard Worker  * The maximum length of a job ticket line, including the prefix, is
8698*5e7646d2SAndroid Build Coastguard Worker  * 255 characters to conform with the Adobe DSC.
8699*5e7646d2SAndroid Build Coastguard Worker  *
8700*5e7646d2SAndroid Build Coastguard Worker  * Read-only attributes are rejected with a notice to the error log in
8701*5e7646d2SAndroid Build Coastguard Worker  * case a malicious user tries anything.  Since the job ticket is read
8702*5e7646d2SAndroid Build Coastguard Worker  * prior to attribute validation in print_job(), job ticket attributes
8703*5e7646d2SAndroid Build Coastguard Worker  * will go through the same validation as IPP attributes...
8704*5e7646d2SAndroid Build Coastguard Worker  */
8705*5e7646d2SAndroid Build Coastguard Worker 
8706*5e7646d2SAndroid Build Coastguard Worker static void
read_job_ticket(cupsd_client_t * con)8707*5e7646d2SAndroid Build Coastguard Worker read_job_ticket(cupsd_client_t *con)	/* I - Client connection */
8708*5e7646d2SAndroid Build Coastguard Worker {
8709*5e7646d2SAndroid Build Coastguard Worker   cups_file_t		*fp;		/* File to read from */
8710*5e7646d2SAndroid Build Coastguard Worker   char			line[256];	/* Line data */
8711*5e7646d2SAndroid Build Coastguard Worker   int			num_options;	/* Number of options */
8712*5e7646d2SAndroid Build Coastguard Worker   cups_option_t		*options;	/* Options */
8713*5e7646d2SAndroid Build Coastguard Worker   ipp_t			*ticket;	/* New attributes */
8714*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr,		/* Current attribute */
8715*5e7646d2SAndroid Build Coastguard Worker 			*attr2,		/* Job attribute */
8716*5e7646d2SAndroid Build Coastguard Worker 			*prev2;		/* Previous job attribute */
8717*5e7646d2SAndroid Build Coastguard Worker 
8718*5e7646d2SAndroid Build Coastguard Worker 
8719*5e7646d2SAndroid Build Coastguard Worker  /*
8720*5e7646d2SAndroid Build Coastguard Worker   * First open the print file...
8721*5e7646d2SAndroid Build Coastguard Worker   */
8722*5e7646d2SAndroid Build Coastguard Worker 
8723*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(con->filename, "rb")) == NULL)
8724*5e7646d2SAndroid Build Coastguard Worker   {
8725*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
8726*5e7646d2SAndroid Build Coastguard Worker                     "Unable to open print file for job ticket - %s",
8727*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
8728*5e7646d2SAndroid Build Coastguard Worker     return;
8729*5e7646d2SAndroid Build Coastguard Worker   }
8730*5e7646d2SAndroid Build Coastguard Worker 
8731*5e7646d2SAndroid Build Coastguard Worker  /*
8732*5e7646d2SAndroid Build Coastguard Worker   * Skip the first line...
8733*5e7646d2SAndroid Build Coastguard Worker   */
8734*5e7646d2SAndroid Build Coastguard Worker 
8735*5e7646d2SAndroid Build Coastguard Worker   if (cupsFileGets(fp, line, sizeof(line)) == NULL)
8736*5e7646d2SAndroid Build Coastguard Worker   {
8737*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
8738*5e7646d2SAndroid Build Coastguard Worker                     "Unable to read from print file for job ticket - %s",
8739*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
8740*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(fp);
8741*5e7646d2SAndroid Build Coastguard Worker     return;
8742*5e7646d2SAndroid Build Coastguard Worker   }
8743*5e7646d2SAndroid Build Coastguard Worker 
8744*5e7646d2SAndroid Build Coastguard Worker   if (strncmp(line, "%!PS-Adobe-", 11) && strncmp(line, "%PDF-", 5))
8745*5e7646d2SAndroid Build Coastguard Worker   {
8746*5e7646d2SAndroid Build Coastguard Worker    /*
8747*5e7646d2SAndroid Build Coastguard Worker     * Not a DSC-compliant file, so no job ticket info will be available...
8748*5e7646d2SAndroid Build Coastguard Worker     */
8749*5e7646d2SAndroid Build Coastguard Worker 
8750*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(fp);
8751*5e7646d2SAndroid Build Coastguard Worker     return;
8752*5e7646d2SAndroid Build Coastguard Worker   }
8753*5e7646d2SAndroid Build Coastguard Worker 
8754*5e7646d2SAndroid Build Coastguard Worker  /*
8755*5e7646d2SAndroid Build Coastguard Worker   * Read job ticket info from the file...
8756*5e7646d2SAndroid Build Coastguard Worker   */
8757*5e7646d2SAndroid Build Coastguard Worker 
8758*5e7646d2SAndroid Build Coastguard Worker   num_options = 0;
8759*5e7646d2SAndroid Build Coastguard Worker   options     = NULL;
8760*5e7646d2SAndroid Build Coastguard Worker 
8761*5e7646d2SAndroid Build Coastguard Worker   while (cupsFileGets(fp, line, sizeof(line)))
8762*5e7646d2SAndroid Build Coastguard Worker   {
8763*5e7646d2SAndroid Build Coastguard Worker    /*
8764*5e7646d2SAndroid Build Coastguard Worker     * Stop at the first non-ticket line...
8765*5e7646d2SAndroid Build Coastguard Worker     */
8766*5e7646d2SAndroid Build Coastguard Worker 
8767*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(line, "%cupsJobTicket:", 15))
8768*5e7646d2SAndroid Build Coastguard Worker       break;
8769*5e7646d2SAndroid Build Coastguard Worker 
8770*5e7646d2SAndroid Build Coastguard Worker    /*
8771*5e7646d2SAndroid Build Coastguard Worker     * Add the options to the option array...
8772*5e7646d2SAndroid Build Coastguard Worker     */
8773*5e7646d2SAndroid Build Coastguard Worker 
8774*5e7646d2SAndroid Build Coastguard Worker     num_options = cupsParseOptions(line + 15, num_options, &options);
8775*5e7646d2SAndroid Build Coastguard Worker   }
8776*5e7646d2SAndroid Build Coastguard Worker 
8777*5e7646d2SAndroid Build Coastguard Worker  /*
8778*5e7646d2SAndroid Build Coastguard Worker   * Done with the file; see if we have any options...
8779*5e7646d2SAndroid Build Coastguard Worker   */
8780*5e7646d2SAndroid Build Coastguard Worker 
8781*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
8782*5e7646d2SAndroid Build Coastguard Worker 
8783*5e7646d2SAndroid Build Coastguard Worker   if (num_options == 0)
8784*5e7646d2SAndroid Build Coastguard Worker     return;
8785*5e7646d2SAndroid Build Coastguard Worker 
8786*5e7646d2SAndroid Build Coastguard Worker  /*
8787*5e7646d2SAndroid Build Coastguard Worker   * OK, convert the options to an attribute list, and apply them to
8788*5e7646d2SAndroid Build Coastguard Worker   * the request...
8789*5e7646d2SAndroid Build Coastguard Worker   */
8790*5e7646d2SAndroid Build Coastguard Worker 
8791*5e7646d2SAndroid Build Coastguard Worker   ticket = ippNew();
8792*5e7646d2SAndroid Build Coastguard Worker   cupsEncodeOptions(ticket, num_options, options);
8793*5e7646d2SAndroid Build Coastguard Worker 
8794*5e7646d2SAndroid Build Coastguard Worker  /*
8795*5e7646d2SAndroid Build Coastguard Worker   * See what the user wants to change.
8796*5e7646d2SAndroid Build Coastguard Worker   */
8797*5e7646d2SAndroid Build Coastguard Worker 
8798*5e7646d2SAndroid Build Coastguard Worker   for (attr = ticket->attrs; attr; attr = attr->next)
8799*5e7646d2SAndroid Build Coastguard Worker   {
8800*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag != IPP_TAG_JOB || !attr->name)
8801*5e7646d2SAndroid Build Coastguard Worker       continue;
8802*5e7646d2SAndroid Build Coastguard Worker 
8803*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(attr->name, "date-time-at-", 13) ||
8804*5e7646d2SAndroid Build Coastguard Worker         !strcmp(attr->name, "job-impressions-completed") ||
8805*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-media-sheets-completed") ||
8806*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "job-k-octets", 12) ||
8807*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-id") ||
8808*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-originating-host-name") ||
8809*5e7646d2SAndroid Build Coastguard Worker         !strcmp(attr->name, "job-originating-user-name") ||
8810*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-pages-completed") ||
8811*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-printer-uri") ||
8812*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "job-state", 9) ||
8813*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-uri") ||
8814*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "time-at-", 8))
8815*5e7646d2SAndroid Build Coastguard Worker       continue; /* Read-only attrs */
8816*5e7646d2SAndroid Build Coastguard Worker 
8817*5e7646d2SAndroid Build Coastguard Worker     if ((attr2 = ippFindAttribute(con->request, attr->name,
8818*5e7646d2SAndroid Build Coastguard Worker                                   IPP_TAG_ZERO)) != NULL)
8819*5e7646d2SAndroid Build Coastguard Worker     {
8820*5e7646d2SAndroid Build Coastguard Worker      /*
8821*5e7646d2SAndroid Build Coastguard Worker       * Some other value; first free the old value...
8822*5e7646d2SAndroid Build Coastguard Worker       */
8823*5e7646d2SAndroid Build Coastguard Worker 
8824*5e7646d2SAndroid Build Coastguard Worker       if (con->request->attrs == attr2)
8825*5e7646d2SAndroid Build Coastguard Worker       {
8826*5e7646d2SAndroid Build Coastguard Worker 	con->request->attrs = attr2->next;
8827*5e7646d2SAndroid Build Coastguard Worker 	prev2               = NULL;
8828*5e7646d2SAndroid Build Coastguard Worker       }
8829*5e7646d2SAndroid Build Coastguard Worker       else
8830*5e7646d2SAndroid Build Coastguard Worker       {
8831*5e7646d2SAndroid Build Coastguard Worker 	for (prev2 = con->request->attrs; prev2; prev2 = prev2->next)
8832*5e7646d2SAndroid Build Coastguard Worker 	  if (prev2->next == attr2)
8833*5e7646d2SAndroid Build Coastguard Worker 	  {
8834*5e7646d2SAndroid Build Coastguard Worker 	    prev2->next = attr2->next;
8835*5e7646d2SAndroid Build Coastguard Worker 	    break;
8836*5e7646d2SAndroid Build Coastguard Worker 	  }
8837*5e7646d2SAndroid Build Coastguard Worker       }
8838*5e7646d2SAndroid Build Coastguard Worker 
8839*5e7646d2SAndroid Build Coastguard Worker       if (con->request->last == attr2)
8840*5e7646d2SAndroid Build Coastguard Worker         con->request->last = prev2;
8841*5e7646d2SAndroid Build Coastguard Worker 
8842*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(NULL, attr2);
8843*5e7646d2SAndroid Build Coastguard Worker     }
8844*5e7646d2SAndroid Build Coastguard Worker 
8845*5e7646d2SAndroid Build Coastguard Worker    /*
8846*5e7646d2SAndroid Build Coastguard Worker     * Add new option by copying it...
8847*5e7646d2SAndroid Build Coastguard Worker     */
8848*5e7646d2SAndroid Build Coastguard Worker 
8849*5e7646d2SAndroid Build Coastguard Worker     ippCopyAttribute(con->request, attr, 0);
8850*5e7646d2SAndroid Build Coastguard Worker   }
8851*5e7646d2SAndroid Build Coastguard Worker 
8852*5e7646d2SAndroid Build Coastguard Worker  /*
8853*5e7646d2SAndroid Build Coastguard Worker   * Then free the attribute list and option array...
8854*5e7646d2SAndroid Build Coastguard Worker   */
8855*5e7646d2SAndroid Build Coastguard Worker 
8856*5e7646d2SAndroid Build Coastguard Worker   ippDelete(ticket);
8857*5e7646d2SAndroid Build Coastguard Worker   cupsFreeOptions(num_options, options);
8858*5e7646d2SAndroid Build Coastguard Worker }
8859*5e7646d2SAndroid Build Coastguard Worker 
8860*5e7646d2SAndroid Build Coastguard Worker 
8861*5e7646d2SAndroid Build Coastguard Worker /*
8862*5e7646d2SAndroid Build Coastguard Worker  * 'reject_jobs()' - Reject print jobs to a printer.
8863*5e7646d2SAndroid Build Coastguard Worker  */
8864*5e7646d2SAndroid Build Coastguard Worker 
8865*5e7646d2SAndroid Build Coastguard Worker static void
reject_jobs(cupsd_client_t * con,ipp_attribute_t * uri)8866*5e7646d2SAndroid Build Coastguard Worker reject_jobs(cupsd_client_t  *con,	/* I - Client connection */
8867*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - Printer or class URI */
8868*5e7646d2SAndroid Build Coastguard Worker {
8869*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Policy status */
8870*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t	dtype;			/* Destination type (printer/class) */
8871*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer;		/* Printer data */
8872*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* printer-state-message text */
8873*5e7646d2SAndroid Build Coastguard Worker 
8874*5e7646d2SAndroid Build Coastguard Worker 
8875*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con,
8876*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
8877*5e7646d2SAndroid Build Coastguard Worker 
8878*5e7646d2SAndroid Build Coastguard Worker  /*
8879*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
8880*5e7646d2SAndroid Build Coastguard Worker   */
8881*5e7646d2SAndroid Build Coastguard Worker 
8882*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
8883*5e7646d2SAndroid Build Coastguard Worker   {
8884*5e7646d2SAndroid Build Coastguard Worker    /*
8885*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
8886*5e7646d2SAndroid Build Coastguard Worker     */
8887*5e7646d2SAndroid Build Coastguard Worker 
8888*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
8889*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
8890*5e7646d2SAndroid Build Coastguard Worker     return;
8891*5e7646d2SAndroid Build Coastguard Worker   }
8892*5e7646d2SAndroid Build Coastguard Worker 
8893*5e7646d2SAndroid Build Coastguard Worker  /*
8894*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
8895*5e7646d2SAndroid Build Coastguard Worker   */
8896*5e7646d2SAndroid Build Coastguard Worker 
8897*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
8898*5e7646d2SAndroid Build Coastguard Worker   {
8899*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
8900*5e7646d2SAndroid Build Coastguard Worker     return;
8901*5e7646d2SAndroid Build Coastguard Worker   }
8902*5e7646d2SAndroid Build Coastguard Worker 
8903*5e7646d2SAndroid Build Coastguard Worker  /*
8904*5e7646d2SAndroid Build Coastguard Worker   * Reject jobs sent to the printer...
8905*5e7646d2SAndroid Build Coastguard Worker   */
8906*5e7646d2SAndroid Build Coastguard Worker 
8907*5e7646d2SAndroid Build Coastguard Worker   printer->accepting = 0;
8908*5e7646d2SAndroid Build Coastguard Worker 
8909*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state-message",
8910*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) == NULL)
8911*5e7646d2SAndroid Build Coastguard Worker     strlcpy(printer->state_message, "Rejecting Jobs",
8912*5e7646d2SAndroid Build Coastguard Worker             sizeof(printer->state_message));
8913*5e7646d2SAndroid Build Coastguard Worker   else
8914*5e7646d2SAndroid Build Coastguard Worker     strlcpy(printer->state_message, attr->values[0].string.text,
8915*5e7646d2SAndroid Build Coastguard Worker             sizeof(printer->state_message));
8916*5e7646d2SAndroid Build Coastguard Worker 
8917*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
8918*5e7646d2SAndroid Build Coastguard Worker                 "No longer accepting jobs.");
8919*5e7646d2SAndroid Build Coastguard Worker 
8920*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
8921*5e7646d2SAndroid Build Coastguard Worker   {
8922*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
8923*5e7646d2SAndroid Build Coastguard Worker 
8924*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").",
8925*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
8926*5e7646d2SAndroid Build Coastguard Worker   }
8927*5e7646d2SAndroid Build Coastguard Worker   else
8928*5e7646d2SAndroid Build Coastguard Worker   {
8929*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
8930*5e7646d2SAndroid Build Coastguard Worker 
8931*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").",
8932*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
8933*5e7646d2SAndroid Build Coastguard Worker   }
8934*5e7646d2SAndroid Build Coastguard Worker 
8935*5e7646d2SAndroid Build Coastguard Worker  /*
8936*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
8937*5e7646d2SAndroid Build Coastguard Worker   */
8938*5e7646d2SAndroid Build Coastguard Worker 
8939*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
8940*5e7646d2SAndroid Build Coastguard Worker }
8941*5e7646d2SAndroid Build Coastguard Worker 
8942*5e7646d2SAndroid Build Coastguard Worker 
8943*5e7646d2SAndroid Build Coastguard Worker /*
8944*5e7646d2SAndroid Build Coastguard Worker  * 'release_held_new_jobs()' - Release pending/new jobs on a printer or class.
8945*5e7646d2SAndroid Build Coastguard Worker  */
8946*5e7646d2SAndroid Build Coastguard Worker 
8947*5e7646d2SAndroid Build Coastguard Worker static void
release_held_new_jobs(cupsd_client_t * con,ipp_attribute_t * uri)8948*5e7646d2SAndroid Build Coastguard Worker release_held_new_jobs(
8949*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Connection */
8950*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t *uri)		/* I - Printer URI */
8951*5e7646d2SAndroid Build Coastguard Worker {
8952*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
8953*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
8954*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer data */
8955*5e7646d2SAndroid Build Coastguard Worker 
8956*5e7646d2SAndroid Build Coastguard Worker 
8957*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con,
8958*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
8959*5e7646d2SAndroid Build Coastguard Worker 
8960*5e7646d2SAndroid Build Coastguard Worker  /*
8961*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
8962*5e7646d2SAndroid Build Coastguard Worker   */
8963*5e7646d2SAndroid Build Coastguard Worker 
8964*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
8965*5e7646d2SAndroid Build Coastguard Worker   {
8966*5e7646d2SAndroid Build Coastguard Worker    /*
8967*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
8968*5e7646d2SAndroid Build Coastguard Worker     */
8969*5e7646d2SAndroid Build Coastguard Worker 
8970*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
8971*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
8972*5e7646d2SAndroid Build Coastguard Worker     return;
8973*5e7646d2SAndroid Build Coastguard Worker   }
8974*5e7646d2SAndroid Build Coastguard Worker 
8975*5e7646d2SAndroid Build Coastguard Worker  /*
8976*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
8977*5e7646d2SAndroid Build Coastguard Worker   */
8978*5e7646d2SAndroid Build Coastguard Worker 
8979*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
8980*5e7646d2SAndroid Build Coastguard Worker   {
8981*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
8982*5e7646d2SAndroid Build Coastguard Worker     return;
8983*5e7646d2SAndroid Build Coastguard Worker   }
8984*5e7646d2SAndroid Build Coastguard Worker 
8985*5e7646d2SAndroid Build Coastguard Worker  /*
8986*5e7646d2SAndroid Build Coastguard Worker   * Hold pending/new jobs sent to the printer...
8987*5e7646d2SAndroid Build Coastguard Worker   */
8988*5e7646d2SAndroid Build Coastguard Worker 
8989*5e7646d2SAndroid Build Coastguard Worker   printer->holding_new_jobs = 0;
8990*5e7646d2SAndroid Build Coastguard Worker 
8991*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterReasons(printer, "-hold-new-jobs");
8992*5e7646d2SAndroid Build Coastguard Worker 
8993*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
8994*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
8995*5e7646d2SAndroid Build Coastguard Worker                     "Class \"%s\" now printing pending/new jobs (\"%s\").",
8996*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
8997*5e7646d2SAndroid Build Coastguard Worker   else
8998*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
8999*5e7646d2SAndroid Build Coastguard Worker                     "Printer \"%s\" now printing pending/new jobs (\"%s\").",
9000*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
9001*5e7646d2SAndroid Build Coastguard Worker 
9002*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
9003*5e7646d2SAndroid Build Coastguard Worker 
9004*5e7646d2SAndroid Build Coastguard Worker  /*
9005*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
9006*5e7646d2SAndroid Build Coastguard Worker   */
9007*5e7646d2SAndroid Build Coastguard Worker 
9008*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
9009*5e7646d2SAndroid Build Coastguard Worker }
9010*5e7646d2SAndroid Build Coastguard Worker 
9011*5e7646d2SAndroid Build Coastguard Worker 
9012*5e7646d2SAndroid Build Coastguard Worker /*
9013*5e7646d2SAndroid Build Coastguard Worker  * 'release_job()' - Release a held print job.
9014*5e7646d2SAndroid Build Coastguard Worker  */
9015*5e7646d2SAndroid Build Coastguard Worker 
9016*5e7646d2SAndroid Build Coastguard Worker static void
release_job(cupsd_client_t * con,ipp_attribute_t * uri)9017*5e7646d2SAndroid Build Coastguard Worker release_job(cupsd_client_t  *con,	/* I - Client connection */
9018*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - Job or Printer URI */
9019*5e7646d2SAndroid Build Coastguard Worker {
9020*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
9021*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
9022*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
9023*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
9024*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
9025*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
9026*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
9027*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Job information */
9028*5e7646d2SAndroid Build Coastguard Worker 
9029*5e7646d2SAndroid Build Coastguard Worker 
9030*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con,
9031*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
9032*5e7646d2SAndroid Build Coastguard Worker 
9033*5e7646d2SAndroid Build Coastguard Worker  /*
9034*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
9035*5e7646d2SAndroid Build Coastguard Worker   */
9036*5e7646d2SAndroid Build Coastguard Worker 
9037*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
9038*5e7646d2SAndroid Build Coastguard Worker   {
9039*5e7646d2SAndroid Build Coastguard Worker    /*
9040*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
9041*5e7646d2SAndroid Build Coastguard Worker     */
9042*5e7646d2SAndroid Build Coastguard Worker 
9043*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
9044*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
9045*5e7646d2SAndroid Build Coastguard Worker     {
9046*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
9047*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
9048*5e7646d2SAndroid Build Coastguard Worker       return;
9049*5e7646d2SAndroid Build Coastguard Worker     }
9050*5e7646d2SAndroid Build Coastguard Worker 
9051*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
9052*5e7646d2SAndroid Build Coastguard Worker   }
9053*5e7646d2SAndroid Build Coastguard Worker   else
9054*5e7646d2SAndroid Build Coastguard Worker   {
9055*5e7646d2SAndroid Build Coastguard Worker    /*
9056*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
9057*5e7646d2SAndroid Build Coastguard Worker     */
9058*5e7646d2SAndroid Build Coastguard Worker 
9059*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9060*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
9061*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
9062*5e7646d2SAndroid Build Coastguard Worker 
9063*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
9064*5e7646d2SAndroid Build Coastguard Worker     {
9065*5e7646d2SAndroid Build Coastguard Worker      /*
9066*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
9067*5e7646d2SAndroid Build Coastguard Worker       */
9068*5e7646d2SAndroid Build Coastguard Worker 
9069*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9070*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
9071*5e7646d2SAndroid Build Coastguard Worker       return;
9072*5e7646d2SAndroid Build Coastguard Worker     }
9073*5e7646d2SAndroid Build Coastguard Worker 
9074*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
9075*5e7646d2SAndroid Build Coastguard Worker   }
9076*5e7646d2SAndroid Build Coastguard Worker 
9077*5e7646d2SAndroid Build Coastguard Worker  /*
9078*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
9079*5e7646d2SAndroid Build Coastguard Worker   */
9080*5e7646d2SAndroid Build Coastguard Worker 
9081*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
9082*5e7646d2SAndroid Build Coastguard Worker   {
9083*5e7646d2SAndroid Build Coastguard Worker    /*
9084*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
9085*5e7646d2SAndroid Build Coastguard Worker     */
9086*5e7646d2SAndroid Build Coastguard Worker 
9087*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9088*5e7646d2SAndroid Build Coastguard Worker     return;
9089*5e7646d2SAndroid Build Coastguard Worker   }
9090*5e7646d2SAndroid Build Coastguard Worker 
9091*5e7646d2SAndroid Build Coastguard Worker  /*
9092*5e7646d2SAndroid Build Coastguard Worker   * See if job is "held"...
9093*5e7646d2SAndroid Build Coastguard Worker   */
9094*5e7646d2SAndroid Build Coastguard Worker 
9095*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value != IPP_JOB_HELD)
9096*5e7646d2SAndroid Build Coastguard Worker   {
9097*5e7646d2SAndroid Build Coastguard Worker    /*
9098*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not possible" error...
9099*5e7646d2SAndroid Build Coastguard Worker     */
9100*5e7646d2SAndroid Build Coastguard Worker 
9101*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held."), jobid);
9102*5e7646d2SAndroid Build Coastguard Worker     return;
9103*5e7646d2SAndroid Build Coastguard Worker   }
9104*5e7646d2SAndroid Build Coastguard Worker 
9105*5e7646d2SAndroid Build Coastguard Worker  /*
9106*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
9107*5e7646d2SAndroid Build Coastguard Worker   */
9108*5e7646d2SAndroid Build Coastguard Worker 
9109*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
9110*5e7646d2SAndroid Build Coastguard Worker   {
9111*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9112*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
9113*5e7646d2SAndroid Build Coastguard Worker     return;
9114*5e7646d2SAndroid Build Coastguard Worker   }
9115*5e7646d2SAndroid Build Coastguard Worker 
9116*5e7646d2SAndroid Build Coastguard Worker  /*
9117*5e7646d2SAndroid Build Coastguard Worker   * Reset the job-hold-until value to "no-hold"...
9118*5e7646d2SAndroid Build Coastguard Worker   */
9119*5e7646d2SAndroid Build Coastguard Worker 
9120*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
9121*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) == NULL)
9122*5e7646d2SAndroid Build Coastguard Worker     attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
9123*5e7646d2SAndroid Build Coastguard Worker 
9124*5e7646d2SAndroid Build Coastguard Worker   if (attr)
9125*5e7646d2SAndroid Build Coastguard Worker   {
9126*5e7646d2SAndroid Build Coastguard Worker     ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
9127*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &attr, 0, "no-hold");
9128*5e7646d2SAndroid Build Coastguard Worker 
9129*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
9130*5e7646d2SAndroid Build Coastguard Worker                   "Job job-hold-until value changed by user.");
9131*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "none");
9132*5e7646d2SAndroid Build Coastguard Worker   }
9133*5e7646d2SAndroid Build Coastguard Worker 
9134*5e7646d2SAndroid Build Coastguard Worker  /*
9135*5e7646d2SAndroid Build Coastguard Worker   * Release the job and return...
9136*5e7646d2SAndroid Build Coastguard Worker   */
9137*5e7646d2SAndroid Build Coastguard Worker 
9138*5e7646d2SAndroid Build Coastguard Worker   cupsdReleaseJob(job);
9139*5e7646d2SAndroid Build Coastguard Worker 
9140*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
9141*5e7646d2SAndroid Build Coastguard Worker                 "Job released by user.");
9142*5e7646d2SAndroid Build Coastguard Worker 
9143*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username);
9144*5e7646d2SAndroid Build Coastguard Worker 
9145*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
9146*5e7646d2SAndroid Build Coastguard Worker 
9147*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
9148*5e7646d2SAndroid Build Coastguard Worker }
9149*5e7646d2SAndroid Build Coastguard Worker 
9150*5e7646d2SAndroid Build Coastguard Worker 
9151*5e7646d2SAndroid Build Coastguard Worker /*
9152*5e7646d2SAndroid Build Coastguard Worker  * 'renew_subscription()' - Renew an existing subscription...
9153*5e7646d2SAndroid Build Coastguard Worker  */
9154*5e7646d2SAndroid Build Coastguard Worker 
9155*5e7646d2SAndroid Build Coastguard Worker static void
renew_subscription(cupsd_client_t * con,int sub_id)9156*5e7646d2SAndroid Build Coastguard Worker renew_subscription(
9157*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
9158*5e7646d2SAndroid Build Coastguard Worker     int            sub_id)		/* I - Subscription ID */
9159*5e7646d2SAndroid Build Coastguard Worker {
9160*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
9161*5e7646d2SAndroid Build Coastguard Worker   cupsd_subscription_t	*sub;		/* Subscription */
9162*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*lease;		/* notify-lease-duration */
9163*5e7646d2SAndroid Build Coastguard Worker 
9164*5e7646d2SAndroid Build Coastguard Worker 
9165*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
9166*5e7646d2SAndroid Build Coastguard Worker                   "renew_subscription(con=%p[%d], sub_id=%d)",
9167*5e7646d2SAndroid Build Coastguard Worker                   con, con->number, sub_id);
9168*5e7646d2SAndroid Build Coastguard Worker 
9169*5e7646d2SAndroid Build Coastguard Worker  /*
9170*5e7646d2SAndroid Build Coastguard Worker   * Is the subscription ID valid?
9171*5e7646d2SAndroid Build Coastguard Worker   */
9172*5e7646d2SAndroid Build Coastguard Worker 
9173*5e7646d2SAndroid Build Coastguard Worker   if ((sub = cupsdFindSubscription(sub_id)) == NULL)
9174*5e7646d2SAndroid Build Coastguard Worker   {
9175*5e7646d2SAndroid Build Coastguard Worker    /*
9176*5e7646d2SAndroid Build Coastguard Worker     * Bad subscription ID...
9177*5e7646d2SAndroid Build Coastguard Worker     */
9178*5e7646d2SAndroid Build Coastguard Worker 
9179*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
9180*5e7646d2SAndroid Build Coastguard Worker                     sub_id);
9181*5e7646d2SAndroid Build Coastguard Worker     return;
9182*5e7646d2SAndroid Build Coastguard Worker   }
9183*5e7646d2SAndroid Build Coastguard Worker 
9184*5e7646d2SAndroid Build Coastguard Worker   if (sub->job)
9185*5e7646d2SAndroid Build Coastguard Worker   {
9186*5e7646d2SAndroid Build Coastguard Worker    /*
9187*5e7646d2SAndroid Build Coastguard Worker     * Job subscriptions cannot be renewed...
9188*5e7646d2SAndroid Build Coastguard Worker     */
9189*5e7646d2SAndroid Build Coastguard Worker 
9190*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE,
9191*5e7646d2SAndroid Build Coastguard Worker                     _("Job subscriptions cannot be renewed."));
9192*5e7646d2SAndroid Build Coastguard Worker     return;
9193*5e7646d2SAndroid Build Coastguard Worker   }
9194*5e7646d2SAndroid Build Coastguard Worker 
9195*5e7646d2SAndroid Build Coastguard Worker  /*
9196*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
9197*5e7646d2SAndroid Build Coastguard Worker   */
9198*5e7646d2SAndroid Build Coastguard Worker 
9199*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
9200*5e7646d2SAndroid Build Coastguard Worker                                              DefaultPolicyPtr,
9201*5e7646d2SAndroid Build Coastguard Worker                                  con, sub->owner)) != HTTP_OK)
9202*5e7646d2SAndroid Build Coastguard Worker   {
9203*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, sub->dest);
9204*5e7646d2SAndroid Build Coastguard Worker     return;
9205*5e7646d2SAndroid Build Coastguard Worker   }
9206*5e7646d2SAndroid Build Coastguard Worker 
9207*5e7646d2SAndroid Build Coastguard Worker  /*
9208*5e7646d2SAndroid Build Coastguard Worker   * Renew the subscription...
9209*5e7646d2SAndroid Build Coastguard Worker   */
9210*5e7646d2SAndroid Build Coastguard Worker 
9211*5e7646d2SAndroid Build Coastguard Worker   lease = ippFindAttribute(con->request, "notify-lease-duration",
9212*5e7646d2SAndroid Build Coastguard Worker                            IPP_TAG_INTEGER);
9213*5e7646d2SAndroid Build Coastguard Worker 
9214*5e7646d2SAndroid Build Coastguard Worker   sub->lease = lease ? lease->values[0].integer : DefaultLeaseDuration;
9215*5e7646d2SAndroid Build Coastguard Worker 
9216*5e7646d2SAndroid Build Coastguard Worker   if (MaxLeaseDuration && (sub->lease == 0 || sub->lease > MaxLeaseDuration))
9217*5e7646d2SAndroid Build Coastguard Worker   {
9218*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
9219*5e7646d2SAndroid Build Coastguard Worker                     "renew_subscription: Limiting notify-lease-duration to "
9220*5e7646d2SAndroid Build Coastguard Worker 		    "%d seconds.",
9221*5e7646d2SAndroid Build Coastguard Worker 		    MaxLeaseDuration);
9222*5e7646d2SAndroid Build Coastguard Worker     sub->lease = MaxLeaseDuration;
9223*5e7646d2SAndroid Build Coastguard Worker   }
9224*5e7646d2SAndroid Build Coastguard Worker 
9225*5e7646d2SAndroid Build Coastguard Worker   sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
9226*5e7646d2SAndroid Build Coastguard Worker 
9227*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
9228*5e7646d2SAndroid Build Coastguard Worker 
9229*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
9230*5e7646d2SAndroid Build Coastguard Worker 
9231*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
9232*5e7646d2SAndroid Build Coastguard Worker                 "notify-lease-duration", sub->lease);
9233*5e7646d2SAndroid Build Coastguard Worker }
9234*5e7646d2SAndroid Build Coastguard Worker 
9235*5e7646d2SAndroid Build Coastguard Worker 
9236*5e7646d2SAndroid Build Coastguard Worker /*
9237*5e7646d2SAndroid Build Coastguard Worker  * 'restart_job()' - Restart an old print job.
9238*5e7646d2SAndroid Build Coastguard Worker  */
9239*5e7646d2SAndroid Build Coastguard Worker 
9240*5e7646d2SAndroid Build Coastguard Worker static void
restart_job(cupsd_client_t * con,ipp_attribute_t * uri)9241*5e7646d2SAndroid Build Coastguard Worker restart_job(cupsd_client_t  *con,	/* I - Client connection */
9242*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - Job or Printer URI */
9243*5e7646d2SAndroid Build Coastguard Worker {
9244*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* Current attribute */
9245*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
9246*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Job information */
9247*5e7646d2SAndroid Build Coastguard Worker   char		scheme[HTTP_MAX_URI],	/* Method portion of URI */
9248*5e7646d2SAndroid Build Coastguard Worker 		username[HTTP_MAX_URI],	/* Username portion of URI */
9249*5e7646d2SAndroid Build Coastguard Worker 		host[HTTP_MAX_URI],	/* Host portion of URI */
9250*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource portion of URI */
9251*5e7646d2SAndroid Build Coastguard Worker   int		port;			/* Port portion of URI */
9252*5e7646d2SAndroid Build Coastguard Worker 
9253*5e7646d2SAndroid Build Coastguard Worker 
9254*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con,
9255*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
9256*5e7646d2SAndroid Build Coastguard Worker 
9257*5e7646d2SAndroid Build Coastguard Worker  /*
9258*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
9259*5e7646d2SAndroid Build Coastguard Worker   */
9260*5e7646d2SAndroid Build Coastguard Worker 
9261*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
9262*5e7646d2SAndroid Build Coastguard Worker   {
9263*5e7646d2SAndroid Build Coastguard Worker    /*
9264*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
9265*5e7646d2SAndroid Build Coastguard Worker     */
9266*5e7646d2SAndroid Build Coastguard Worker 
9267*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
9268*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
9269*5e7646d2SAndroid Build Coastguard Worker     {
9270*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
9271*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
9272*5e7646d2SAndroid Build Coastguard Worker       return;
9273*5e7646d2SAndroid Build Coastguard Worker     }
9274*5e7646d2SAndroid Build Coastguard Worker 
9275*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
9276*5e7646d2SAndroid Build Coastguard Worker   }
9277*5e7646d2SAndroid Build Coastguard Worker   else
9278*5e7646d2SAndroid Build Coastguard Worker   {
9279*5e7646d2SAndroid Build Coastguard Worker    /*
9280*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
9281*5e7646d2SAndroid Build Coastguard Worker     */
9282*5e7646d2SAndroid Build Coastguard Worker 
9283*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9284*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
9285*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
9286*5e7646d2SAndroid Build Coastguard Worker 
9287*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
9288*5e7646d2SAndroid Build Coastguard Worker     {
9289*5e7646d2SAndroid Build Coastguard Worker      /*
9290*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
9291*5e7646d2SAndroid Build Coastguard Worker       */
9292*5e7646d2SAndroid Build Coastguard Worker 
9293*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9294*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
9295*5e7646d2SAndroid Build Coastguard Worker       return;
9296*5e7646d2SAndroid Build Coastguard Worker     }
9297*5e7646d2SAndroid Build Coastguard Worker 
9298*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
9299*5e7646d2SAndroid Build Coastguard Worker   }
9300*5e7646d2SAndroid Build Coastguard Worker 
9301*5e7646d2SAndroid Build Coastguard Worker  /*
9302*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
9303*5e7646d2SAndroid Build Coastguard Worker   */
9304*5e7646d2SAndroid Build Coastguard Worker 
9305*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
9306*5e7646d2SAndroid Build Coastguard Worker   {
9307*5e7646d2SAndroid Build Coastguard Worker    /*
9308*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
9309*5e7646d2SAndroid Build Coastguard Worker     */
9310*5e7646d2SAndroid Build Coastguard Worker 
9311*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9312*5e7646d2SAndroid Build Coastguard Worker     return;
9313*5e7646d2SAndroid Build Coastguard Worker   }
9314*5e7646d2SAndroid Build Coastguard Worker 
9315*5e7646d2SAndroid Build Coastguard Worker  /*
9316*5e7646d2SAndroid Build Coastguard Worker   * See if job is in any of the "completed" states...
9317*5e7646d2SAndroid Build Coastguard Worker   */
9318*5e7646d2SAndroid Build Coastguard Worker 
9319*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value <= IPP_JOB_PROCESSING)
9320*5e7646d2SAndroid Build Coastguard Worker   {
9321*5e7646d2SAndroid Build Coastguard Worker    /*
9322*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not possible" error...
9323*5e7646d2SAndroid Build Coastguard Worker     */
9324*5e7646d2SAndroid Build Coastguard Worker 
9325*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete."),
9326*5e7646d2SAndroid Build Coastguard Worker                     jobid);
9327*5e7646d2SAndroid Build Coastguard Worker     return;
9328*5e7646d2SAndroid Build Coastguard Worker   }
9329*5e7646d2SAndroid Build Coastguard Worker 
9330*5e7646d2SAndroid Build Coastguard Worker  /*
9331*5e7646d2SAndroid Build Coastguard Worker   * See if we have retained the job files...
9332*5e7646d2SAndroid Build Coastguard Worker   */
9333*5e7646d2SAndroid Build Coastguard Worker 
9334*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadJob(job);
9335*5e7646d2SAndroid Build Coastguard Worker 
9336*5e7646d2SAndroid Build Coastguard Worker   if (!job->attrs || job->num_files == 0)
9337*5e7646d2SAndroid Build Coastguard Worker   {
9338*5e7646d2SAndroid Build Coastguard Worker    /*
9339*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not possible" error...
9340*5e7646d2SAndroid Build Coastguard Worker     */
9341*5e7646d2SAndroid Build Coastguard Worker 
9342*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE,
9343*5e7646d2SAndroid Build Coastguard Worker                     _("Job #%d cannot be restarted - no files."), jobid);
9344*5e7646d2SAndroid Build Coastguard Worker     return;
9345*5e7646d2SAndroid Build Coastguard Worker   }
9346*5e7646d2SAndroid Build Coastguard Worker 
9347*5e7646d2SAndroid Build Coastguard Worker  /*
9348*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
9349*5e7646d2SAndroid Build Coastguard Worker   */
9350*5e7646d2SAndroid Build Coastguard Worker 
9351*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
9352*5e7646d2SAndroid Build Coastguard Worker   {
9353*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9354*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
9355*5e7646d2SAndroid Build Coastguard Worker     return;
9356*5e7646d2SAndroid Build Coastguard Worker   }
9357*5e7646d2SAndroid Build Coastguard Worker 
9358*5e7646d2SAndroid Build Coastguard Worker  /*
9359*5e7646d2SAndroid Build Coastguard Worker   * See if the job-hold-until attribute is specified...
9360*5e7646d2SAndroid Build Coastguard Worker   */
9361*5e7646d2SAndroid Build Coastguard Worker 
9362*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-hold-until",
9363*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) == NULL)
9364*5e7646d2SAndroid Build Coastguard Worker     attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
9365*5e7646d2SAndroid Build Coastguard Worker 
9366*5e7646d2SAndroid Build Coastguard Worker   if (attr && strcmp(attr->values[0].string.text, "no-hold"))
9367*5e7646d2SAndroid Build Coastguard Worker   {
9368*5e7646d2SAndroid Build Coastguard Worker    /*
9369*5e7646d2SAndroid Build Coastguard Worker     * Return the job to a held state...
9370*5e7646d2SAndroid Build Coastguard Worker     */
9371*5e7646d2SAndroid Build Coastguard Worker 
9372*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
9373*5e7646d2SAndroid Build Coastguard Worker 		"Restarted by \"%s\" with job-hold-until=%s.",
9374*5e7646d2SAndroid Build Coastguard Worker                 username, attr->values[0].string.text);
9375*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobHoldUntil(job, attr->values[0].string.text, 1);
9376*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT,
9377*5e7646d2SAndroid Build Coastguard Worker                      "Job restarted by user with job-hold-until=%s",
9378*5e7646d2SAndroid Build Coastguard Worker                      attr->values[0].string.text);
9379*5e7646d2SAndroid Build Coastguard Worker   }
9380*5e7646d2SAndroid Build Coastguard Worker   else
9381*5e7646d2SAndroid Build Coastguard Worker   {
9382*5e7646d2SAndroid Build Coastguard Worker    /*
9383*5e7646d2SAndroid Build Coastguard Worker     * Restart the job...
9384*5e7646d2SAndroid Build Coastguard Worker     */
9385*5e7646d2SAndroid Build Coastguard Worker 
9386*5e7646d2SAndroid Build Coastguard Worker     cupsdRestartJob(job);
9387*5e7646d2SAndroid Build Coastguard Worker     cupsdCheckJobs();
9388*5e7646d2SAndroid Build Coastguard Worker   }
9389*5e7646d2SAndroid Build Coastguard Worker 
9390*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "Restarted by \"%s\".", username);
9391*5e7646d2SAndroid Build Coastguard Worker 
9392*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
9393*5e7646d2SAndroid Build Coastguard Worker }
9394*5e7646d2SAndroid Build Coastguard Worker 
9395*5e7646d2SAndroid Build Coastguard Worker 
9396*5e7646d2SAndroid Build Coastguard Worker /*
9397*5e7646d2SAndroid Build Coastguard Worker  * 'save_auth_info()' - Save authentication information for a job.
9398*5e7646d2SAndroid Build Coastguard Worker  */
9399*5e7646d2SAndroid Build Coastguard Worker 
9400*5e7646d2SAndroid Build Coastguard Worker static void
save_auth_info(cupsd_client_t * con,cupsd_job_t * job,ipp_attribute_t * auth_info)9401*5e7646d2SAndroid Build Coastguard Worker save_auth_info(
9402*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
9403*5e7646d2SAndroid Build Coastguard Worker     cupsd_job_t     *job,		/* I - Job */
9404*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t *auth_info)		/* I - auth-info attribute, if any */
9405*5e7646d2SAndroid Build Coastguard Worker {
9406*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
9407*5e7646d2SAndroid Build Coastguard Worker   char			filename[1024];	/* Job authentication filename */
9408*5e7646d2SAndroid Build Coastguard Worker   cups_file_t		*fp;		/* Job authentication file */
9409*5e7646d2SAndroid Build Coastguard Worker   char			line[65536];	/* Line for file */
9410*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*dest;		/* Destination printer/class */
9411*5e7646d2SAndroid Build Coastguard Worker 
9412*5e7646d2SAndroid Build Coastguard Worker 
9413*5e7646d2SAndroid Build Coastguard Worker  /*
9414*5e7646d2SAndroid Build Coastguard Worker   * This function saves the in-memory authentication information for
9415*5e7646d2SAndroid Build Coastguard Worker   * a job so that it can be used to authenticate with a remote host.
9416*5e7646d2SAndroid Build Coastguard Worker   * The information is stored in a file that is readable only by the
9417*5e7646d2SAndroid Build Coastguard Worker   * root user.  The fields are Base-64 encoded, each on a separate line,
9418*5e7646d2SAndroid Build Coastguard Worker   * followed by random number (up to 1024) of newlines to limit the
9419*5e7646d2SAndroid Build Coastguard Worker   * amount of information that is exposed.
9420*5e7646d2SAndroid Build Coastguard Worker   *
9421*5e7646d2SAndroid Build Coastguard Worker   * Because of the potential for exposing of authentication information,
9422*5e7646d2SAndroid Build Coastguard Worker   * this functionality is only enabled when running cupsd as root.
9423*5e7646d2SAndroid Build Coastguard Worker   *
9424*5e7646d2SAndroid Build Coastguard Worker   * This caching only works for the Basic and BasicDigest authentication
9425*5e7646d2SAndroid Build Coastguard Worker   * types.  Digest authentication cannot be cached this way, and in
9426*5e7646d2SAndroid Build Coastguard Worker   * the future Kerberos authentication may make all of this obsolete.
9427*5e7646d2SAndroid Build Coastguard Worker   *
9428*5e7646d2SAndroid Build Coastguard Worker   * Authentication information is saved whenever an authenticated
9429*5e7646d2SAndroid Build Coastguard Worker   * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
9430*5e7646d2SAndroid Build Coastguard Worker   * performed.
9431*5e7646d2SAndroid Build Coastguard Worker   *
9432*5e7646d2SAndroid Build Coastguard Worker   * This information is deleted after a job is completed or canceled,
9433*5e7646d2SAndroid Build Coastguard Worker   * so reprints may require subsequent re-authentication.
9434*5e7646d2SAndroid Build Coastguard Worker   */
9435*5e7646d2SAndroid Build Coastguard Worker 
9436*5e7646d2SAndroid Build Coastguard Worker   if (RunUser)
9437*5e7646d2SAndroid Build Coastguard Worker     return;
9438*5e7646d2SAndroid Build Coastguard Worker 
9439*5e7646d2SAndroid Build Coastguard Worker   if ((dest = cupsdFindDest(job->dest)) == NULL)
9440*5e7646d2SAndroid Build Coastguard Worker     return;
9441*5e7646d2SAndroid Build Coastguard Worker 
9442*5e7646d2SAndroid Build Coastguard Worker  /*
9443*5e7646d2SAndroid Build Coastguard Worker   * Create the authentication file and change permissions...
9444*5e7646d2SAndroid Build Coastguard Worker   */
9445*5e7646d2SAndroid Build Coastguard Worker 
9446*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
9447*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(filename, "w")) == NULL)
9448*5e7646d2SAndroid Build Coastguard Worker   {
9449*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
9450*5e7646d2SAndroid Build Coastguard Worker                     "Unable to save authentication info to \"%s\" - %s",
9451*5e7646d2SAndroid Build Coastguard Worker                     filename, strerror(errno));
9452*5e7646d2SAndroid Build Coastguard Worker     return;
9453*5e7646d2SAndroid Build Coastguard Worker   }
9454*5e7646d2SAndroid Build Coastguard Worker 
9455*5e7646d2SAndroid Build Coastguard Worker   fchown(cupsFileNumber(fp), 0, 0);
9456*5e7646d2SAndroid Build Coastguard Worker   fchmod(cupsFileNumber(fp), 0400);
9457*5e7646d2SAndroid Build Coastguard Worker 
9458*5e7646d2SAndroid Build Coastguard Worker   cupsFilePuts(fp, "CUPSD-AUTH-V3\n");
9459*5e7646d2SAndroid Build Coastguard Worker 
9460*5e7646d2SAndroid Build Coastguard Worker   for (i = 0;
9461*5e7646d2SAndroid Build Coastguard Worker        i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
9462*5e7646d2SAndroid Build Coastguard Worker        i ++)
9463*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(job->auth_env + i);
9464*5e7646d2SAndroid Build Coastguard Worker 
9465*5e7646d2SAndroid Build Coastguard Worker   if (auth_info && auth_info->num_values == dest->num_auth_info_required)
9466*5e7646d2SAndroid Build Coastguard Worker   {
9467*5e7646d2SAndroid Build Coastguard Worker    /*
9468*5e7646d2SAndroid Build Coastguard Worker     * Write 1 to 3 auth values...
9469*5e7646d2SAndroid Build Coastguard Worker     */
9470*5e7646d2SAndroid Build Coastguard Worker 
9471*5e7646d2SAndroid Build Coastguard Worker     for (i = 0;
9472*5e7646d2SAndroid Build Coastguard Worker          i < auth_info->num_values &&
9473*5e7646d2SAndroid Build Coastguard Worker 	     i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
9474*5e7646d2SAndroid Build Coastguard Worker 	 i ++)
9475*5e7646d2SAndroid Build Coastguard Worker     {
9476*5e7646d2SAndroid Build Coastguard Worker       if (strcmp(dest->auth_info_required[i], "negotiate"))
9477*5e7646d2SAndroid Build Coastguard Worker       {
9478*5e7646d2SAndroid Build Coastguard Worker 	httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, (int)strlen(auth_info->values[i].string.text));
9479*5e7646d2SAndroid Build Coastguard Worker 	cupsFilePutConf(fp, dest->auth_info_required[i], line);
9480*5e7646d2SAndroid Build Coastguard Worker       }
9481*5e7646d2SAndroid Build Coastguard Worker       else
9482*5e7646d2SAndroid Build Coastguard Worker 	cupsFilePutConf(fp, dest->auth_info_required[i],
9483*5e7646d2SAndroid Build Coastguard Worker 	                auth_info->values[i].string.text);
9484*5e7646d2SAndroid Build Coastguard Worker 
9485*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(dest->auth_info_required[i], "username"))
9486*5e7646d2SAndroid Build Coastguard Worker         cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s",
9487*5e7646d2SAndroid Build Coastguard Worker 	                auth_info->values[i].string.text);
9488*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(dest->auth_info_required[i], "domain"))
9489*5e7646d2SAndroid Build Coastguard Worker         cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s",
9490*5e7646d2SAndroid Build Coastguard Worker 	                auth_info->values[i].string.text);
9491*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(dest->auth_info_required[i], "password"))
9492*5e7646d2SAndroid Build Coastguard Worker         cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s",
9493*5e7646d2SAndroid Build Coastguard Worker 	                auth_info->values[i].string.text);
9494*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(dest->auth_info_required[i], "negotiate"))
9495*5e7646d2SAndroid Build Coastguard Worker         cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s",
9496*5e7646d2SAndroid Build Coastguard Worker 	                auth_info->values[i].string.text);
9497*5e7646d2SAndroid Build Coastguard Worker       else
9498*5e7646d2SAndroid Build Coastguard Worker         i --;
9499*5e7646d2SAndroid Build Coastguard Worker     }
9500*5e7646d2SAndroid Build Coastguard Worker   }
9501*5e7646d2SAndroid Build Coastguard Worker   else if (auth_info && auth_info->num_values == 2 &&
9502*5e7646d2SAndroid Build Coastguard Worker            dest->num_auth_info_required == 1 &&
9503*5e7646d2SAndroid Build Coastguard Worker            !strcmp(dest->auth_info_required[0], "negotiate"))
9504*5e7646d2SAndroid Build Coastguard Worker   {
9505*5e7646d2SAndroid Build Coastguard Worker    /*
9506*5e7646d2SAndroid Build Coastguard Worker     * Allow fallback to username+password for Kerberized queues...
9507*5e7646d2SAndroid Build Coastguard Worker     */
9508*5e7646d2SAndroid Build Coastguard Worker 
9509*5e7646d2SAndroid Build Coastguard Worker     httpEncode64_2(line, sizeof(line), auth_info->values[0].string.text, (int)strlen(auth_info->values[0].string.text));
9510*5e7646d2SAndroid Build Coastguard Worker     cupsFilePutConf(fp, "username", line);
9511*5e7646d2SAndroid Build Coastguard Worker 
9512*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s",
9513*5e7646d2SAndroid Build Coastguard Worker                     auth_info->values[0].string.text);
9514*5e7646d2SAndroid Build Coastguard Worker 
9515*5e7646d2SAndroid Build Coastguard Worker     httpEncode64_2(line, sizeof(line), auth_info->values[1].string.text, (int)strlen(auth_info->values[1].string.text));
9516*5e7646d2SAndroid Build Coastguard Worker     cupsFilePutConf(fp, "password", line);
9517*5e7646d2SAndroid Build Coastguard Worker 
9518*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s",
9519*5e7646d2SAndroid Build Coastguard Worker                     auth_info->values[1].string.text);
9520*5e7646d2SAndroid Build Coastguard Worker   }
9521*5e7646d2SAndroid Build Coastguard Worker   else if (con->username[0])
9522*5e7646d2SAndroid Build Coastguard Worker   {
9523*5e7646d2SAndroid Build Coastguard Worker    /*
9524*5e7646d2SAndroid Build Coastguard Worker     * Write the authenticated username...
9525*5e7646d2SAndroid Build Coastguard Worker     */
9526*5e7646d2SAndroid Build Coastguard Worker 
9527*5e7646d2SAndroid Build Coastguard Worker     httpEncode64_2(line, sizeof(line), con->username, (int)strlen(con->username));
9528*5e7646d2SAndroid Build Coastguard Worker     cupsFilePutConf(fp, "username", line);
9529*5e7646d2SAndroid Build Coastguard Worker 
9530*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s", con->username);
9531*5e7646d2SAndroid Build Coastguard Worker 
9532*5e7646d2SAndroid Build Coastguard Worker    /*
9533*5e7646d2SAndroid Build Coastguard Worker     * Write the authenticated password...
9534*5e7646d2SAndroid Build Coastguard Worker     */
9535*5e7646d2SAndroid Build Coastguard Worker 
9536*5e7646d2SAndroid Build Coastguard Worker     httpEncode64_2(line, sizeof(line), con->password, (int)strlen(con->password));
9537*5e7646d2SAndroid Build Coastguard Worker     cupsFilePutConf(fp, "password", line);
9538*5e7646d2SAndroid Build Coastguard Worker 
9539*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s", con->password);
9540*5e7646d2SAndroid Build Coastguard Worker   }
9541*5e7646d2SAndroid Build Coastguard Worker 
9542*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
9543*5e7646d2SAndroid Build Coastguard Worker   if (con->gss_uid > 0)
9544*5e7646d2SAndroid Build Coastguard Worker   {
9545*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "uid %d\n", (int)con->gss_uid);
9546*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(&job->auth_uid, "AUTH_UID=%d", (int)con->gss_uid);
9547*5e7646d2SAndroid Build Coastguard Worker   }
9548*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI */
9549*5e7646d2SAndroid Build Coastguard Worker 
9550*5e7646d2SAndroid Build Coastguard Worker  /*
9551*5e7646d2SAndroid Build Coastguard Worker   * Write a random number of newlines to the end of the file...
9552*5e7646d2SAndroid Build Coastguard Worker   */
9553*5e7646d2SAndroid Build Coastguard Worker 
9554*5e7646d2SAndroid Build Coastguard Worker   for (i = (CUPS_RAND() % 1024); i >= 0; i --)
9555*5e7646d2SAndroid Build Coastguard Worker     cupsFilePutChar(fp, '\n');
9556*5e7646d2SAndroid Build Coastguard Worker 
9557*5e7646d2SAndroid Build Coastguard Worker  /*
9558*5e7646d2SAndroid Build Coastguard Worker   * Close the file and return...
9559*5e7646d2SAndroid Build Coastguard Worker   */
9560*5e7646d2SAndroid Build Coastguard Worker 
9561*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
9562*5e7646d2SAndroid Build Coastguard Worker }
9563*5e7646d2SAndroid Build Coastguard Worker 
9564*5e7646d2SAndroid Build Coastguard Worker 
9565*5e7646d2SAndroid Build Coastguard Worker /*
9566*5e7646d2SAndroid Build Coastguard Worker  * 'send_document()' - Send a file to a printer or class.
9567*5e7646d2SAndroid Build Coastguard Worker  */
9568*5e7646d2SAndroid Build Coastguard Worker 
9569*5e7646d2SAndroid Build Coastguard Worker static void
send_document(cupsd_client_t * con,ipp_attribute_t * uri)9570*5e7646d2SAndroid Build Coastguard Worker send_document(cupsd_client_t  *con,	/* I - Client connection */
9571*5e7646d2SAndroid Build Coastguard Worker 	      ipp_attribute_t *uri)	/* I - Printer URI */
9572*5e7646d2SAndroid Build Coastguard Worker {
9573*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
9574*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*format;	/* Request's document-format attribute */
9575*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*jformat;	/* Job's document-format attribute */
9576*5e7646d2SAndroid Build Coastguard Worker   const char		*default_format;/* document-format-default value */
9577*5e7646d2SAndroid Build Coastguard Worker   int			jobid;		/* Job ID number */
9578*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Current job */
9579*5e7646d2SAndroid Build Coastguard Worker   char			job_uri[HTTP_MAX_URI],
9580*5e7646d2SAndroid Build Coastguard Worker 					/* Job URI */
9581*5e7646d2SAndroid Build Coastguard Worker 			scheme[HTTP_MAX_URI],
9582*5e7646d2SAndroid Build Coastguard Worker 					/* Method portion of URI */
9583*5e7646d2SAndroid Build Coastguard Worker 			username[HTTP_MAX_URI],
9584*5e7646d2SAndroid Build Coastguard Worker 					/* Username portion of URI */
9585*5e7646d2SAndroid Build Coastguard Worker 			host[HTTP_MAX_URI],
9586*5e7646d2SAndroid Build Coastguard Worker 					/* Host portion of URI */
9587*5e7646d2SAndroid Build Coastguard Worker 			resource[HTTP_MAX_URI];
9588*5e7646d2SAndroid Build Coastguard Worker 					/* Resource portion of URI */
9589*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port portion of URI */
9590*5e7646d2SAndroid Build Coastguard Worker   mime_type_t		*filetype;	/* Type of file */
9591*5e7646d2SAndroid Build Coastguard Worker   char			super[MIME_MAX_SUPER],
9592*5e7646d2SAndroid Build Coastguard Worker 					/* Supertype of file */
9593*5e7646d2SAndroid Build Coastguard Worker 			type[MIME_MAX_TYPE],
9594*5e7646d2SAndroid Build Coastguard Worker 					/* Subtype of file */
9595*5e7646d2SAndroid Build Coastguard Worker 			mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
9596*5e7646d2SAndroid Build Coastguard Worker 					/* Textual name of mime type */
9597*5e7646d2SAndroid Build Coastguard Worker   char			filename[1024];	/* Job filename */
9598*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Current printer */
9599*5e7646d2SAndroid Build Coastguard Worker   struct stat		fileinfo;	/* File information */
9600*5e7646d2SAndroid Build Coastguard Worker   int			kbytes;		/* Size of file */
9601*5e7646d2SAndroid Build Coastguard Worker   int			compression;	/* Type of compression */
9602*5e7646d2SAndroid Build Coastguard Worker   int			start_job;	/* Start the job? */
9603*5e7646d2SAndroid Build Coastguard Worker 
9604*5e7646d2SAndroid Build Coastguard Worker 
9605*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con,
9606*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
9607*5e7646d2SAndroid Build Coastguard Worker 
9608*5e7646d2SAndroid Build Coastguard Worker  /*
9609*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
9610*5e7646d2SAndroid Build Coastguard Worker   */
9611*5e7646d2SAndroid Build Coastguard Worker 
9612*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
9613*5e7646d2SAndroid Build Coastguard Worker   {
9614*5e7646d2SAndroid Build Coastguard Worker    /*
9615*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
9616*5e7646d2SAndroid Build Coastguard Worker     */
9617*5e7646d2SAndroid Build Coastguard Worker 
9618*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
9619*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
9620*5e7646d2SAndroid Build Coastguard Worker     {
9621*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
9622*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
9623*5e7646d2SAndroid Build Coastguard Worker       return;
9624*5e7646d2SAndroid Build Coastguard Worker     }
9625*5e7646d2SAndroid Build Coastguard Worker 
9626*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
9627*5e7646d2SAndroid Build Coastguard Worker   }
9628*5e7646d2SAndroid Build Coastguard Worker   else
9629*5e7646d2SAndroid Build Coastguard Worker   {
9630*5e7646d2SAndroid Build Coastguard Worker    /*
9631*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
9632*5e7646d2SAndroid Build Coastguard Worker     */
9633*5e7646d2SAndroid Build Coastguard Worker 
9634*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
9635*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
9636*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
9637*5e7646d2SAndroid Build Coastguard Worker 
9638*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
9639*5e7646d2SAndroid Build Coastguard Worker     {
9640*5e7646d2SAndroid Build Coastguard Worker      /*
9641*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
9642*5e7646d2SAndroid Build Coastguard Worker       */
9643*5e7646d2SAndroid Build Coastguard Worker 
9644*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
9645*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
9646*5e7646d2SAndroid Build Coastguard Worker       return;
9647*5e7646d2SAndroid Build Coastguard Worker     }
9648*5e7646d2SAndroid Build Coastguard Worker 
9649*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
9650*5e7646d2SAndroid Build Coastguard Worker   }
9651*5e7646d2SAndroid Build Coastguard Worker 
9652*5e7646d2SAndroid Build Coastguard Worker  /*
9653*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
9654*5e7646d2SAndroid Build Coastguard Worker   */
9655*5e7646d2SAndroid Build Coastguard Worker 
9656*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
9657*5e7646d2SAndroid Build Coastguard Worker   {
9658*5e7646d2SAndroid Build Coastguard Worker    /*
9659*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
9660*5e7646d2SAndroid Build Coastguard Worker     */
9661*5e7646d2SAndroid Build Coastguard Worker 
9662*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
9663*5e7646d2SAndroid Build Coastguard Worker     return;
9664*5e7646d2SAndroid Build Coastguard Worker   }
9665*5e7646d2SAndroid Build Coastguard Worker 
9666*5e7646d2SAndroid Build Coastguard Worker   printer = cupsdFindDest(job->dest);
9667*5e7646d2SAndroid Build Coastguard Worker 
9668*5e7646d2SAndroid Build Coastguard Worker  /*
9669*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
9670*5e7646d2SAndroid Build Coastguard Worker   */
9671*5e7646d2SAndroid Build Coastguard Worker 
9672*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
9673*5e7646d2SAndroid Build Coastguard Worker   {
9674*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
9675*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
9676*5e7646d2SAndroid Build Coastguard Worker     return;
9677*5e7646d2SAndroid Build Coastguard Worker   }
9678*5e7646d2SAndroid Build Coastguard Worker 
9679*5e7646d2SAndroid Build Coastguard Worker  /*
9680*5e7646d2SAndroid Build Coastguard Worker   * OK, see if the client is sending the document compressed - CUPS
9681*5e7646d2SAndroid Build Coastguard Worker   * only supports "none" and "gzip".
9682*5e7646d2SAndroid Build Coastguard Worker   */
9683*5e7646d2SAndroid Build Coastguard Worker 
9684*5e7646d2SAndroid Build Coastguard Worker   compression = CUPS_FILE_NONE;
9685*5e7646d2SAndroid Build Coastguard Worker 
9686*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "compression",
9687*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
9688*5e7646d2SAndroid Build Coastguard Worker   {
9689*5e7646d2SAndroid Build Coastguard Worker     if (strcmp(attr->values[0].string.text, "none")
9690*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LIBZ
9691*5e7646d2SAndroid Build Coastguard Worker         && strcmp(attr->values[0].string.text, "gzip")
9692*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LIBZ */
9693*5e7646d2SAndroid Build Coastguard Worker       )
9694*5e7646d2SAndroid Build Coastguard Worker     {
9695*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"."),
9696*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].string.text);
9697*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
9698*5e7646d2SAndroid Build Coastguard Worker 	           "compression", NULL, attr->values[0].string.text);
9699*5e7646d2SAndroid Build Coastguard Worker       return;
9700*5e7646d2SAndroid Build Coastguard Worker     }
9701*5e7646d2SAndroid Build Coastguard Worker 
9702*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LIBZ
9703*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->values[0].string.text, "gzip"))
9704*5e7646d2SAndroid Build Coastguard Worker       compression = CUPS_FILE_GZIP;
9705*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LIBZ */
9706*5e7646d2SAndroid Build Coastguard Worker   }
9707*5e7646d2SAndroid Build Coastguard Worker 
9708*5e7646d2SAndroid Build Coastguard Worker  /*
9709*5e7646d2SAndroid Build Coastguard Worker   * Do we have a file to print?
9710*5e7646d2SAndroid Build Coastguard Worker   */
9711*5e7646d2SAndroid Build Coastguard Worker 
9712*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "last-document",
9713*5e7646d2SAndroid Build Coastguard Worker 	                       IPP_TAG_BOOLEAN)) == NULL)
9714*5e7646d2SAndroid Build Coastguard Worker   {
9715*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST,
9716*5e7646d2SAndroid Build Coastguard Worker                     _("Missing last-document attribute in request."));
9717*5e7646d2SAndroid Build Coastguard Worker     return;
9718*5e7646d2SAndroid Build Coastguard Worker   }
9719*5e7646d2SAndroid Build Coastguard Worker 
9720*5e7646d2SAndroid Build Coastguard Worker   if (!con->filename)
9721*5e7646d2SAndroid Build Coastguard Worker   {
9722*5e7646d2SAndroid Build Coastguard Worker    /*
9723*5e7646d2SAndroid Build Coastguard Worker     * Check for an empty request with "last-document" set to true, which is
9724*5e7646d2SAndroid Build Coastguard Worker     * used to close an "open" job by RFC 2911, section 3.3.2.
9725*5e7646d2SAndroid Build Coastguard Worker     */
9726*5e7646d2SAndroid Build Coastguard Worker 
9727*5e7646d2SAndroid Build Coastguard Worker     if (job->num_files > 0 && attr->values[0].boolean)
9728*5e7646d2SAndroid Build Coastguard Worker       goto last_document;
9729*5e7646d2SAndroid Build Coastguard Worker 
9730*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
9731*5e7646d2SAndroid Build Coastguard Worker     return;
9732*5e7646d2SAndroid Build Coastguard Worker   }
9733*5e7646d2SAndroid Build Coastguard Worker 
9734*5e7646d2SAndroid Build Coastguard Worker  /*
9735*5e7646d2SAndroid Build Coastguard Worker   * Is it a format we support?
9736*5e7646d2SAndroid Build Coastguard Worker   */
9737*5e7646d2SAndroid Build Coastguard Worker 
9738*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadJob(job);
9739*5e7646d2SAndroid Build Coastguard Worker 
9740*5e7646d2SAndroid Build Coastguard Worker   if ((format = ippFindAttribute(con->request, "document-format",
9741*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_MIMETYPE)) != NULL)
9742*5e7646d2SAndroid Build Coastguard Worker   {
9743*5e7646d2SAndroid Build Coastguard Worker    /*
9744*5e7646d2SAndroid Build Coastguard Worker     * Grab format from client...
9745*5e7646d2SAndroid Build Coastguard Worker     */
9746*5e7646d2SAndroid Build Coastguard Worker 
9747*5e7646d2SAndroid Build Coastguard Worker     if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]",
9748*5e7646d2SAndroid Build Coastguard Worker                super, type) != 2)
9749*5e7646d2SAndroid Build Coastguard Worker     {
9750*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."),
9751*5e7646d2SAndroid Build Coastguard Worker 	              format->values[0].string.text);
9752*5e7646d2SAndroid Build Coastguard Worker       return;
9753*5e7646d2SAndroid Build Coastguard Worker     }
9754*5e7646d2SAndroid Build Coastguard Worker 
9755*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL));
9756*5e7646d2SAndroid Build Coastguard Worker   }
9757*5e7646d2SAndroid Build Coastguard Worker   else if ((default_format = cupsGetOption("document-format",
9758*5e7646d2SAndroid Build Coastguard Worker                                            printer->num_options,
9759*5e7646d2SAndroid Build Coastguard Worker 					   printer->options)) != NULL)
9760*5e7646d2SAndroid Build Coastguard Worker   {
9761*5e7646d2SAndroid Build Coastguard Worker    /*
9762*5e7646d2SAndroid Build Coastguard Worker     * Use default document format...
9763*5e7646d2SAndroid Build Coastguard Worker     */
9764*5e7646d2SAndroid Build Coastguard Worker 
9765*5e7646d2SAndroid Build Coastguard Worker     if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2)
9766*5e7646d2SAndroid Build Coastguard Worker     {
9767*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
9768*5e7646d2SAndroid Build Coastguard Worker                       _("Bad document-format-default \"%s\"."), default_format);
9769*5e7646d2SAndroid Build Coastguard Worker       return;
9770*5e7646d2SAndroid Build Coastguard Worker     }
9771*5e7646d2SAndroid Build Coastguard Worker   }
9772*5e7646d2SAndroid Build Coastguard Worker   else
9773*5e7646d2SAndroid Build Coastguard Worker   {
9774*5e7646d2SAndroid Build Coastguard Worker    /*
9775*5e7646d2SAndroid Build Coastguard Worker     * No document format attribute?  Auto-type it!
9776*5e7646d2SAndroid Build Coastguard Worker     */
9777*5e7646d2SAndroid Build Coastguard Worker 
9778*5e7646d2SAndroid Build Coastguard Worker     strlcpy(super, "application", sizeof(super));
9779*5e7646d2SAndroid Build Coastguard Worker     strlcpy(type, "octet-stream", sizeof(type));
9780*5e7646d2SAndroid Build Coastguard Worker   }
9781*5e7646d2SAndroid Build Coastguard Worker 
9782*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
9783*5e7646d2SAndroid Build Coastguard Worker   {
9784*5e7646d2SAndroid Build Coastguard Worker    /*
9785*5e7646d2SAndroid Build Coastguard Worker     * Auto-type the file...
9786*5e7646d2SAndroid Build Coastguard Worker     */
9787*5e7646d2SAndroid Build Coastguard Worker 
9788*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t	*doc_name;	/* document-name attribute */
9789*5e7646d2SAndroid Build Coastguard Worker 
9790*5e7646d2SAndroid Build Coastguard Worker 
9791*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "Auto-typing file...");
9792*5e7646d2SAndroid Build Coastguard Worker 
9793*5e7646d2SAndroid Build Coastguard Worker     doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
9794*5e7646d2SAndroid Build Coastguard Worker     filetype = mimeFileType(MimeDatabase, con->filename,
9795*5e7646d2SAndroid Build Coastguard Worker                             doc_name ? doc_name->values[0].string.text : NULL,
9796*5e7646d2SAndroid Build Coastguard Worker 			    &compression);
9797*5e7646d2SAndroid Build Coastguard Worker 
9798*5e7646d2SAndroid Build Coastguard Worker     if (!filetype)
9799*5e7646d2SAndroid Build Coastguard Worker       filetype = mimeType(MimeDatabase, super, type);
9800*5e7646d2SAndroid Build Coastguard Worker 
9801*5e7646d2SAndroid Build Coastguard Worker     if (filetype)
9802*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "Request file type is %s/%s.",
9803*5e7646d2SAndroid Build Coastguard Worker 		  filetype->super, filetype->type);
9804*5e7646d2SAndroid Build Coastguard Worker 
9805*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type);
9806*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype);
9807*5e7646d2SAndroid Build Coastguard Worker   }
9808*5e7646d2SAndroid Build Coastguard Worker   else
9809*5e7646d2SAndroid Build Coastguard Worker     filetype = mimeType(MimeDatabase, super, type);
9810*5e7646d2SAndroid Build Coastguard Worker 
9811*5e7646d2SAndroid Build Coastguard Worker   if (filetype)
9812*5e7646d2SAndroid Build Coastguard Worker   {
9813*5e7646d2SAndroid Build Coastguard Worker    /*
9814*5e7646d2SAndroid Build Coastguard Worker     * Replace the document-format attribute value with the auto-typed or
9815*5e7646d2SAndroid Build Coastguard Worker     * default one.
9816*5e7646d2SAndroid Build Coastguard Worker     */
9817*5e7646d2SAndroid Build Coastguard Worker 
9818*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
9819*5e7646d2SAndroid Build Coastguard Worker              filetype->type);
9820*5e7646d2SAndroid Build Coastguard Worker 
9821*5e7646d2SAndroid Build Coastguard Worker     if ((jformat = ippFindAttribute(job->attrs, "document-format",
9822*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_MIMETYPE)) != NULL)
9823*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &jformat, 0, mimetype);
9824*5e7646d2SAndroid Build Coastguard Worker     else
9825*5e7646d2SAndroid Build Coastguard Worker       ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
9826*5e7646d2SAndroid Build Coastguard Worker 	           "document-format", NULL, mimetype);
9827*5e7646d2SAndroid Build Coastguard Worker   }
9828*5e7646d2SAndroid Build Coastguard Worker   else if (!filetype)
9829*5e7646d2SAndroid Build Coastguard Worker   {
9830*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_DOCUMENT_FORMAT,
9831*5e7646d2SAndroid Build Coastguard Worker                     _("Unsupported document-format \"%s/%s\"."), super, type);
9832*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
9833*5e7646d2SAndroid Build Coastguard Worker                     "Hint: Do you have the raw file printing rules enabled?");
9834*5e7646d2SAndroid Build Coastguard Worker 
9835*5e7646d2SAndroid Build Coastguard Worker     if (format)
9836*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
9837*5e7646d2SAndroid Build Coastguard Worker                    "document-format", NULL, format->values[0].string.text);
9838*5e7646d2SAndroid Build Coastguard Worker 
9839*5e7646d2SAndroid Build Coastguard Worker     return;
9840*5e7646d2SAndroid Build Coastguard Worker   }
9841*5e7646d2SAndroid Build Coastguard Worker 
9842*5e7646d2SAndroid Build Coastguard Worker   if (printer->filetypes && !cupsArrayFind(printer->filetypes, filetype))
9843*5e7646d2SAndroid Build Coastguard Worker   {
9844*5e7646d2SAndroid Build Coastguard Worker     snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
9845*5e7646d2SAndroid Build Coastguard Worker              filetype->type);
9846*5e7646d2SAndroid Build Coastguard Worker 
9847*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_DOCUMENT_FORMAT,
9848*5e7646d2SAndroid Build Coastguard Worker                     _("Unsupported document-format \"%s\"."), mimetype);
9849*5e7646d2SAndroid Build Coastguard Worker 
9850*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
9851*5e7646d2SAndroid Build Coastguard Worker                  "document-format", NULL, mimetype);
9852*5e7646d2SAndroid Build Coastguard Worker 
9853*5e7646d2SAndroid Build Coastguard Worker     return;
9854*5e7646d2SAndroid Build Coastguard Worker   }
9855*5e7646d2SAndroid Build Coastguard Worker 
9856*5e7646d2SAndroid Build Coastguard Worker  /*
9857*5e7646d2SAndroid Build Coastguard Worker   * Add the file to the job...
9858*5e7646d2SAndroid Build Coastguard Worker   */
9859*5e7646d2SAndroid Build Coastguard Worker 
9860*5e7646d2SAndroid Build Coastguard Worker   if (add_file(con, job, filetype, compression))
9861*5e7646d2SAndroid Build Coastguard Worker     return;
9862*5e7646d2SAndroid Build Coastguard Worker 
9863*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME)) != NULL)
9864*5e7646d2SAndroid Build Coastguard Worker     ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL));
9865*5e7646d2SAndroid Build Coastguard Worker 
9866*5e7646d2SAndroid Build Coastguard Worker   if (stat(con->filename, &fileinfo))
9867*5e7646d2SAndroid Build Coastguard Worker     kbytes = 0;
9868*5e7646d2SAndroid Build Coastguard Worker   else
9869*5e7646d2SAndroid Build Coastguard Worker     kbytes = (fileinfo.st_size + 1023) / 1024;
9870*5e7646d2SAndroid Build Coastguard Worker 
9871*5e7646d2SAndroid Build Coastguard Worker   cupsdUpdateQuota(printer, job->username, 0, kbytes);
9872*5e7646d2SAndroid Build Coastguard Worker 
9873*5e7646d2SAndroid Build Coastguard Worker   job->koctets += kbytes;
9874*5e7646d2SAndroid Build Coastguard Worker 
9875*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
9876*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer += kbytes;
9877*5e7646d2SAndroid Build Coastguard Worker 
9878*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files);
9879*5e7646d2SAndroid Build Coastguard Worker   if (rename(con->filename, filename))
9880*5e7646d2SAndroid Build Coastguard Worker   {
9881*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno));
9882*5e7646d2SAndroid Build Coastguard Worker 
9883*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file."));
9884*5e7646d2SAndroid Build Coastguard Worker     return;
9885*5e7646d2SAndroid Build Coastguard Worker   }
9886*5e7646d2SAndroid Build Coastguard Worker 
9887*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&con->filename);
9888*5e7646d2SAndroid Build Coastguard Worker 
9889*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_INFO, "File of type %s/%s queued by \"%s\".",
9890*5e7646d2SAndroid Build Coastguard Worker 	      filetype->super, filetype->type, job->username);
9891*5e7646d2SAndroid Build Coastguard Worker 
9892*5e7646d2SAndroid Build Coastguard Worker  /*
9893*5e7646d2SAndroid Build Coastguard Worker   * Start the job if this is the last document...
9894*5e7646d2SAndroid Build Coastguard Worker   */
9895*5e7646d2SAndroid Build Coastguard Worker 
9896*5e7646d2SAndroid Build Coastguard Worker   last_document:
9897*5e7646d2SAndroid Build Coastguard Worker 
9898*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "last-document",
9899*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_BOOLEAN)) != NULL &&
9900*5e7646d2SAndroid Build Coastguard Worker       attr->values[0].boolean)
9901*5e7646d2SAndroid Build Coastguard Worker   {
9902*5e7646d2SAndroid Build Coastguard Worker    /*
9903*5e7646d2SAndroid Build Coastguard Worker     * See if we need to add the ending sheet...
9904*5e7646d2SAndroid Build Coastguard Worker     */
9905*5e7646d2SAndroid Build Coastguard Worker 
9906*5e7646d2SAndroid Build Coastguard Worker     if (cupsdTimeoutJob(job))
9907*5e7646d2SAndroid Build Coastguard Worker       return;
9908*5e7646d2SAndroid Build Coastguard Worker 
9909*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value == IPP_JOB_STOPPED)
9910*5e7646d2SAndroid Build Coastguard Worker     {
9911*5e7646d2SAndroid Build Coastguard Worker       job->state->values[0].integer = IPP_JOB_PENDING;
9912*5e7646d2SAndroid Build Coastguard Worker       job->state_value              = IPP_JOB_PENDING;
9913*5e7646d2SAndroid Build Coastguard Worker 
9914*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "none");
9915*5e7646d2SAndroid Build Coastguard Worker     }
9916*5e7646d2SAndroid Build Coastguard Worker     else if (job->state_value == IPP_JOB_HELD)
9917*5e7646d2SAndroid Build Coastguard Worker     {
9918*5e7646d2SAndroid Build Coastguard Worker       if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
9919*5e7646d2SAndroid Build Coastguard Worker                                    IPP_TAG_KEYWORD)) == NULL)
9920*5e7646d2SAndroid Build Coastguard Worker 	attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
9921*5e7646d2SAndroid Build Coastguard Worker 
9922*5e7646d2SAndroid Build Coastguard Worker       if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
9923*5e7646d2SAndroid Build Coastguard Worker       {
9924*5e7646d2SAndroid Build Coastguard Worker 	job->state->values[0].integer = IPP_JOB_PENDING;
9925*5e7646d2SAndroid Build Coastguard Worker 	job->state_value              = IPP_JOB_PENDING;
9926*5e7646d2SAndroid Build Coastguard Worker 
9927*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "none");
9928*5e7646d2SAndroid Build Coastguard Worker       }
9929*5e7646d2SAndroid Build Coastguard Worker       else
9930*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified");
9931*5e7646d2SAndroid Build Coastguard Worker     }
9932*5e7646d2SAndroid Build Coastguard Worker 
9933*5e7646d2SAndroid Build Coastguard Worker     job->dirty = 1;
9934*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_JOBS);
9935*5e7646d2SAndroid Build Coastguard Worker 
9936*5e7646d2SAndroid Build Coastguard Worker     start_job = 1;
9937*5e7646d2SAndroid Build Coastguard Worker   }
9938*5e7646d2SAndroid Build Coastguard Worker   else
9939*5e7646d2SAndroid Build Coastguard Worker   {
9940*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
9941*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_KEYWORD)) == NULL)
9942*5e7646d2SAndroid Build Coastguard Worker       attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
9943*5e7646d2SAndroid Build Coastguard Worker 
9944*5e7646d2SAndroid Build Coastguard Worker     if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
9945*5e7646d2SAndroid Build Coastguard Worker     {
9946*5e7646d2SAndroid Build Coastguard Worker       job->state->values[0].integer = IPP_JOB_HELD;
9947*5e7646d2SAndroid Build Coastguard Worker       job->state_value              = IPP_JOB_HELD;
9948*5e7646d2SAndroid Build Coastguard Worker       job->hold_until               = time(NULL) + MultipleOperationTimeout;
9949*5e7646d2SAndroid Build Coastguard Worker 
9950*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "job-incoming");
9951*5e7646d2SAndroid Build Coastguard Worker 
9952*5e7646d2SAndroid Build Coastguard Worker       job->dirty = 1;
9953*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_JOBS);
9954*5e7646d2SAndroid Build Coastguard Worker     }
9955*5e7646d2SAndroid Build Coastguard Worker 
9956*5e7646d2SAndroid Build Coastguard Worker     start_job = 0;
9957*5e7646d2SAndroid Build Coastguard Worker   }
9958*5e7646d2SAndroid Build Coastguard Worker 
9959*5e7646d2SAndroid Build Coastguard Worker  /*
9960*5e7646d2SAndroid Build Coastguard Worker   * Fill in the response info...
9961*5e7646d2SAndroid Build Coastguard Worker   */
9962*5e7646d2SAndroid Build Coastguard Worker 
9963*5e7646d2SAndroid Build Coastguard Worker   httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, con->clientname, con->clientport, "/jobs/%d", jobid);
9964*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
9965*5e7646d2SAndroid Build Coastguard Worker 
9966*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", jobid);
9967*5e7646d2SAndroid Build Coastguard Worker 
9968*5e7646d2SAndroid Build Coastguard Worker   ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value);
9969*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, job->reasons->values[0].string.text);
9970*5e7646d2SAndroid Build Coastguard Worker 
9971*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
9972*5e7646d2SAndroid Build Coastguard Worker 
9973*5e7646d2SAndroid Build Coastguard Worker  /*
9974*5e7646d2SAndroid Build Coastguard Worker   * Start the job if necessary...
9975*5e7646d2SAndroid Build Coastguard Worker   */
9976*5e7646d2SAndroid Build Coastguard Worker 
9977*5e7646d2SAndroid Build Coastguard Worker   if (start_job)
9978*5e7646d2SAndroid Build Coastguard Worker     cupsdCheckJobs();
9979*5e7646d2SAndroid Build Coastguard Worker }
9980*5e7646d2SAndroid Build Coastguard Worker 
9981*5e7646d2SAndroid Build Coastguard Worker 
9982*5e7646d2SAndroid Build Coastguard Worker /*
9983*5e7646d2SAndroid Build Coastguard Worker  * 'send_http_error()' - Send a HTTP error back to the IPP client.
9984*5e7646d2SAndroid Build Coastguard Worker  */
9985*5e7646d2SAndroid Build Coastguard Worker 
9986*5e7646d2SAndroid Build Coastguard Worker static void
send_http_error(cupsd_client_t * con,http_status_t status,cupsd_printer_t * printer)9987*5e7646d2SAndroid Build Coastguard Worker send_http_error(
9988*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
9989*5e7646d2SAndroid Build Coastguard Worker     http_status_t   status,		/* I - HTTP status code */
9990*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *printer)		/* I - Printer, if any */
9991*5e7646d2SAndroid Build Coastguard Worker {
9992*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*uri;		/* Request URI, if any */
9993*5e7646d2SAndroid Build Coastguard Worker 
9994*5e7646d2SAndroid Build Coastguard Worker 
9995*5e7646d2SAndroid Build Coastguard Worker   if ((uri = ippFindAttribute(con->request, "printer-uri",
9996*5e7646d2SAndroid Build Coastguard Worker                               IPP_TAG_URI)) == NULL)
9997*5e7646d2SAndroid Build Coastguard Worker     uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI);
9998*5e7646d2SAndroid Build Coastguard Worker 
9999*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(status == HTTP_FORBIDDEN ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG,
10000*5e7646d2SAndroid Build Coastguard Worker                   "[Client %d] Returning HTTP %s for %s (%s) from %s",
10001*5e7646d2SAndroid Build Coastguard Worker                   con->number, httpStatus(status),
10002*5e7646d2SAndroid Build Coastguard Worker 		  con->request ?
10003*5e7646d2SAndroid Build Coastguard Worker 		      ippOpString(con->request->request.op.operation_id) :
10004*5e7646d2SAndroid Build Coastguard Worker 		      "no operation-id",
10005*5e7646d2SAndroid Build Coastguard Worker 		  uri ? uri->values[0].string.text : "no URI",
10006*5e7646d2SAndroid Build Coastguard Worker 		  con->http->hostname);
10007*5e7646d2SAndroid Build Coastguard Worker 
10008*5e7646d2SAndroid Build Coastguard Worker   if (printer)
10009*5e7646d2SAndroid Build Coastguard Worker   {
10010*5e7646d2SAndroid Build Coastguard Worker     int		auth_type;		/* Type of authentication required */
10011*5e7646d2SAndroid Build Coastguard Worker 
10012*5e7646d2SAndroid Build Coastguard Worker 
10013*5e7646d2SAndroid Build Coastguard Worker     auth_type = CUPSD_AUTH_NONE;
10014*5e7646d2SAndroid Build Coastguard Worker 
10015*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_UNAUTHORIZED &&
10016*5e7646d2SAndroid Build Coastguard Worker         printer->num_auth_info_required > 0 &&
10017*5e7646d2SAndroid Build Coastguard Worker         !strcmp(printer->auth_info_required[0], "negotiate") &&
10018*5e7646d2SAndroid Build Coastguard Worker 	con->request &&
10019*5e7646d2SAndroid Build Coastguard Worker 	(con->request->request.op.operation_id == IPP_PRINT_JOB ||
10020*5e7646d2SAndroid Build Coastguard Worker 	 con->request->request.op.operation_id == IPP_CREATE_JOB ||
10021*5e7646d2SAndroid Build Coastguard Worker 	 con->request->request.op.operation_id == CUPS_AUTHENTICATE_JOB))
10022*5e7646d2SAndroid Build Coastguard Worker     {
10023*5e7646d2SAndroid Build Coastguard Worker      /*
10024*5e7646d2SAndroid Build Coastguard Worker       * Creating and authenticating jobs requires Kerberos...
10025*5e7646d2SAndroid Build Coastguard Worker       */
10026*5e7646d2SAndroid Build Coastguard Worker 
10027*5e7646d2SAndroid Build Coastguard Worker       auth_type = CUPSD_AUTH_NEGOTIATE;
10028*5e7646d2SAndroid Build Coastguard Worker     }
10029*5e7646d2SAndroid Build Coastguard Worker     else
10030*5e7646d2SAndroid Build Coastguard Worker     {
10031*5e7646d2SAndroid Build Coastguard Worker      /*
10032*5e7646d2SAndroid Build Coastguard Worker       * Use policy/location-defined authentication requirements...
10033*5e7646d2SAndroid Build Coastguard Worker       */
10034*5e7646d2SAndroid Build Coastguard Worker 
10035*5e7646d2SAndroid Build Coastguard Worker       char	resource[HTTP_MAX_URI];	/* Resource portion of URI */
10036*5e7646d2SAndroid Build Coastguard Worker       cupsd_location_t *auth;		/* Pointer to authentication element */
10037*5e7646d2SAndroid Build Coastguard Worker 
10038*5e7646d2SAndroid Build Coastguard Worker 
10039*5e7646d2SAndroid Build Coastguard Worker       if (printer->type & CUPS_PRINTER_CLASS)
10040*5e7646d2SAndroid Build Coastguard Worker 	snprintf(resource, sizeof(resource), "/classes/%s", printer->name);
10041*5e7646d2SAndroid Build Coastguard Worker       else
10042*5e7646d2SAndroid Build Coastguard Worker 	snprintf(resource, sizeof(resource), "/printers/%s", printer->name);
10043*5e7646d2SAndroid Build Coastguard Worker 
10044*5e7646d2SAndroid Build Coastguard Worker       if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
10045*5e7646d2SAndroid Build Coastguard Worker 	  auth->type == CUPSD_AUTH_NONE)
10046*5e7646d2SAndroid Build Coastguard Worker 	auth = cupsdFindPolicyOp(printer->op_policy_ptr,
10047*5e7646d2SAndroid Build Coastguard Worker 				 con->request ?
10048*5e7646d2SAndroid Build Coastguard Worker 				     con->request->request.op.operation_id :
10049*5e7646d2SAndroid Build Coastguard Worker 				     IPP_PRINT_JOB);
10050*5e7646d2SAndroid Build Coastguard Worker 
10051*5e7646d2SAndroid Build Coastguard Worker       if (auth)
10052*5e7646d2SAndroid Build Coastguard Worker       {
10053*5e7646d2SAndroid Build Coastguard Worker         if (auth->type == CUPSD_AUTH_DEFAULT)
10054*5e7646d2SAndroid Build Coastguard Worker 	  auth_type = cupsdDefaultAuthType();
10055*5e7646d2SAndroid Build Coastguard Worker 	else
10056*5e7646d2SAndroid Build Coastguard Worker 	  auth_type = auth->type;
10057*5e7646d2SAndroid Build Coastguard Worker       }
10058*5e7646d2SAndroid Build Coastguard Worker     }
10059*5e7646d2SAndroid Build Coastguard Worker 
10060*5e7646d2SAndroid Build Coastguard Worker     cupsdSendError(con, status, auth_type);
10061*5e7646d2SAndroid Build Coastguard Worker   }
10062*5e7646d2SAndroid Build Coastguard Worker   else
10063*5e7646d2SAndroid Build Coastguard Worker     cupsdSendError(con, status, CUPSD_AUTH_NONE);
10064*5e7646d2SAndroid Build Coastguard Worker 
10065*5e7646d2SAndroid Build Coastguard Worker   ippDelete(con->response);
10066*5e7646d2SAndroid Build Coastguard Worker   con->response = NULL;
10067*5e7646d2SAndroid Build Coastguard Worker 
10068*5e7646d2SAndroid Build Coastguard Worker   return;
10069*5e7646d2SAndroid Build Coastguard Worker }
10070*5e7646d2SAndroid Build Coastguard Worker 
10071*5e7646d2SAndroid Build Coastguard Worker 
10072*5e7646d2SAndroid Build Coastguard Worker /*
10073*5e7646d2SAndroid Build Coastguard Worker  * 'send_ipp_status()' - Send a status back to the IPP client.
10074*5e7646d2SAndroid Build Coastguard Worker  */
10075*5e7646d2SAndroid Build Coastguard Worker 
10076*5e7646d2SAndroid Build Coastguard Worker static void
send_ipp_status(cupsd_client_t * con,ipp_status_t status,const char * message,...)10077*5e7646d2SAndroid Build Coastguard Worker send_ipp_status(cupsd_client_t *con,	/* I - Client connection */
10078*5e7646d2SAndroid Build Coastguard Worker                 ipp_status_t   status,	/* I - IPP status code */
10079*5e7646d2SAndroid Build Coastguard Worker 	        const char     *message,/* I - Status message */
10080*5e7646d2SAndroid Build Coastguard Worker 	        ...)			/* I - Additional args as needed */
10081*5e7646d2SAndroid Build Coastguard Worker {
10082*5e7646d2SAndroid Build Coastguard Worker   va_list	ap;			/* Pointer to additional args */
10083*5e7646d2SAndroid Build Coastguard Worker   char		formatted[1024];	/* Formatted errror message */
10084*5e7646d2SAndroid Build Coastguard Worker 
10085*5e7646d2SAndroid Build Coastguard Worker 
10086*5e7646d2SAndroid Build Coastguard Worker   va_start(ap, message);
10087*5e7646d2SAndroid Build Coastguard Worker   vsnprintf(formatted, sizeof(formatted),
10088*5e7646d2SAndroid Build Coastguard Worker             _cupsLangString(con->language, message), ap);
10089*5e7646d2SAndroid Build Coastguard Worker   va_end(ap);
10090*5e7646d2SAndroid Build Coastguard Worker 
10091*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
10092*5e7646d2SAndroid Build Coastguard Worker 		  ippOpString(con->request->request.op.operation_id),
10093*5e7646d2SAndroid Build Coastguard Worker 		  ippErrorString(status), formatted);
10094*5e7646d2SAndroid Build Coastguard Worker 
10095*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = status;
10096*5e7646d2SAndroid Build Coastguard Worker 
10097*5e7646d2SAndroid Build Coastguard Worker   if (ippFindAttribute(con->response, "attributes-charset",
10098*5e7646d2SAndroid Build Coastguard Worker                        IPP_TAG_ZERO) == NULL)
10099*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
10100*5e7646d2SAndroid Build Coastguard Worker                  "attributes-charset", NULL, "utf-8");
10101*5e7646d2SAndroid Build Coastguard Worker 
10102*5e7646d2SAndroid Build Coastguard Worker   if (ippFindAttribute(con->response, "attributes-natural-language",
10103*5e7646d2SAndroid Build Coastguard Worker                        IPP_TAG_ZERO) == NULL)
10104*5e7646d2SAndroid Build Coastguard Worker     ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
10105*5e7646d2SAndroid Build Coastguard Worker                  "attributes-natural-language", NULL, DefaultLanguage);
10106*5e7646d2SAndroid Build Coastguard Worker 
10107*5e7646d2SAndroid Build Coastguard Worker   ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
10108*5e7646d2SAndroid Build Coastguard Worker                "status-message", NULL, formatted);
10109*5e7646d2SAndroid Build Coastguard Worker }
10110*5e7646d2SAndroid Build Coastguard Worker 
10111*5e7646d2SAndroid Build Coastguard Worker 
10112*5e7646d2SAndroid Build Coastguard Worker /*
10113*5e7646d2SAndroid Build Coastguard Worker  * 'set_default()' - Set the default destination...
10114*5e7646d2SAndroid Build Coastguard Worker  */
10115*5e7646d2SAndroid Build Coastguard Worker 
10116*5e7646d2SAndroid Build Coastguard Worker static void
set_default(cupsd_client_t * con,ipp_attribute_t * uri)10117*5e7646d2SAndroid Build Coastguard Worker set_default(cupsd_client_t  *con,	/* I - Client connection */
10118*5e7646d2SAndroid Build Coastguard Worker             ipp_attribute_t *uri)	/* I - Printer URI */
10119*5e7646d2SAndroid Build Coastguard Worker {
10120*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
10121*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
10122*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer,	/* Printer */
10123*5e7646d2SAndroid Build Coastguard Worker 			*oldprinter;	/* Old default printer */
10124*5e7646d2SAndroid Build Coastguard Worker 
10125*5e7646d2SAndroid Build Coastguard Worker 
10126*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con,
10127*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
10128*5e7646d2SAndroid Build Coastguard Worker 
10129*5e7646d2SAndroid Build Coastguard Worker  /*
10130*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
10131*5e7646d2SAndroid Build Coastguard Worker   */
10132*5e7646d2SAndroid Build Coastguard Worker 
10133*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
10134*5e7646d2SAndroid Build Coastguard Worker   {
10135*5e7646d2SAndroid Build Coastguard Worker    /*
10136*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
10137*5e7646d2SAndroid Build Coastguard Worker     */
10138*5e7646d2SAndroid Build Coastguard Worker 
10139*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
10140*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
10141*5e7646d2SAndroid Build Coastguard Worker     return;
10142*5e7646d2SAndroid Build Coastguard Worker   }
10143*5e7646d2SAndroid Build Coastguard Worker 
10144*5e7646d2SAndroid Build Coastguard Worker  /*
10145*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
10146*5e7646d2SAndroid Build Coastguard Worker   */
10147*5e7646d2SAndroid Build Coastguard Worker 
10148*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
10149*5e7646d2SAndroid Build Coastguard Worker   {
10150*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, NULL);
10151*5e7646d2SAndroid Build Coastguard Worker     return;
10152*5e7646d2SAndroid Build Coastguard Worker   }
10153*5e7646d2SAndroid Build Coastguard Worker 
10154*5e7646d2SAndroid Build Coastguard Worker  /*
10155*5e7646d2SAndroid Build Coastguard Worker   * Set it as the default...
10156*5e7646d2SAndroid Build Coastguard Worker   */
10157*5e7646d2SAndroid Build Coastguard Worker 
10158*5e7646d2SAndroid Build Coastguard Worker   oldprinter     = DefaultPrinter;
10159*5e7646d2SAndroid Build Coastguard Worker   DefaultPrinter = printer;
10160*5e7646d2SAndroid Build Coastguard Worker 
10161*5e7646d2SAndroid Build Coastguard Worker   if (oldprinter)
10162*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, oldprinter, NULL,
10163*5e7646d2SAndroid Build Coastguard Worker                   "%s is no longer the default printer.", oldprinter->name);
10164*5e7646d2SAndroid Build Coastguard Worker 
10165*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
10166*5e7646d2SAndroid Build Coastguard Worker 		"%s is now the default printer.", printer->name);
10167*5e7646d2SAndroid Build Coastguard Worker 
10168*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES |
10169*5e7646d2SAndroid Build Coastguard Worker                  CUPSD_DIRTY_PRINTCAP);
10170*5e7646d2SAndroid Build Coastguard Worker 
10171*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_INFO,
10172*5e7646d2SAndroid Build Coastguard Worker                   "Default destination set to \"%s\" by \"%s\".",
10173*5e7646d2SAndroid Build Coastguard Worker 		  printer->name, get_username(con));
10174*5e7646d2SAndroid Build Coastguard Worker 
10175*5e7646d2SAndroid Build Coastguard Worker  /*
10176*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
10177*5e7646d2SAndroid Build Coastguard Worker   */
10178*5e7646d2SAndroid Build Coastguard Worker 
10179*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
10180*5e7646d2SAndroid Build Coastguard Worker }
10181*5e7646d2SAndroid Build Coastguard Worker 
10182*5e7646d2SAndroid Build Coastguard Worker 
10183*5e7646d2SAndroid Build Coastguard Worker /*
10184*5e7646d2SAndroid Build Coastguard Worker  * 'set_job_attrs()' - Set job attributes.
10185*5e7646d2SAndroid Build Coastguard Worker  */
10186*5e7646d2SAndroid Build Coastguard Worker 
10187*5e7646d2SAndroid Build Coastguard Worker static void
set_job_attrs(cupsd_client_t * con,ipp_attribute_t * uri)10188*5e7646d2SAndroid Build Coastguard Worker set_job_attrs(cupsd_client_t  *con,	/* I - Client connection */
10189*5e7646d2SAndroid Build Coastguard Worker 	      ipp_attribute_t *uri)	/* I - Job URI */
10190*5e7646d2SAndroid Build Coastguard Worker {
10191*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr,		/* Current attribute */
10192*5e7646d2SAndroid Build Coastguard Worker 			*attr2;		/* Job attribute */
10193*5e7646d2SAndroid Build Coastguard Worker   int			jobid;		/* Job ID */
10194*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Current job */
10195*5e7646d2SAndroid Build Coastguard Worker   char			scheme[HTTP_MAX_URI],
10196*5e7646d2SAndroid Build Coastguard Worker 					/* Method portion of URI */
10197*5e7646d2SAndroid Build Coastguard Worker 			username[HTTP_MAX_URI],
10198*5e7646d2SAndroid Build Coastguard Worker 					/* Username portion of URI */
10199*5e7646d2SAndroid Build Coastguard Worker 			host[HTTP_MAX_URI],
10200*5e7646d2SAndroid Build Coastguard Worker 					/* Host portion of URI */
10201*5e7646d2SAndroid Build Coastguard Worker 			resource[HTTP_MAX_URI];
10202*5e7646d2SAndroid Build Coastguard Worker 					/* Resource portion of URI */
10203*5e7646d2SAndroid Build Coastguard Worker   int			port;		/* Port portion of URI */
10204*5e7646d2SAndroid Build Coastguard Worker   int			event;		/* Events? */
10205*5e7646d2SAndroid Build Coastguard Worker   int			check_jobs;	/* Check jobs? */
10206*5e7646d2SAndroid Build Coastguard Worker 
10207*5e7646d2SAndroid Build Coastguard Worker 
10208*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
10209*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
10210*5e7646d2SAndroid Build Coastguard Worker 
10211*5e7646d2SAndroid Build Coastguard Worker  /*
10212*5e7646d2SAndroid Build Coastguard Worker   * Start with "everything is OK" status...
10213*5e7646d2SAndroid Build Coastguard Worker   */
10214*5e7646d2SAndroid Build Coastguard Worker 
10215*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
10216*5e7646d2SAndroid Build Coastguard Worker 
10217*5e7646d2SAndroid Build Coastguard Worker  /*
10218*5e7646d2SAndroid Build Coastguard Worker   * See if we have a job URI or a printer URI...
10219*5e7646d2SAndroid Build Coastguard Worker   */
10220*5e7646d2SAndroid Build Coastguard Worker 
10221*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(uri->name, "printer-uri"))
10222*5e7646d2SAndroid Build Coastguard Worker   {
10223*5e7646d2SAndroid Build Coastguard Worker    /*
10224*5e7646d2SAndroid Build Coastguard Worker     * Got a printer URI; see if we also have a job-id attribute...
10225*5e7646d2SAndroid Build Coastguard Worker     */
10226*5e7646d2SAndroid Build Coastguard Worker 
10227*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(con->request, "job-id",
10228*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) == NULL)
10229*5e7646d2SAndroid Build Coastguard Worker     {
10230*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
10231*5e7646d2SAndroid Build Coastguard Worker                       _("Got a printer-uri attribute but no job-id."));
10232*5e7646d2SAndroid Build Coastguard Worker       return;
10233*5e7646d2SAndroid Build Coastguard Worker     }
10234*5e7646d2SAndroid Build Coastguard Worker 
10235*5e7646d2SAndroid Build Coastguard Worker     jobid = attr->values[0].integer;
10236*5e7646d2SAndroid Build Coastguard Worker   }
10237*5e7646d2SAndroid Build Coastguard Worker   else
10238*5e7646d2SAndroid Build Coastguard Worker   {
10239*5e7646d2SAndroid Build Coastguard Worker    /*
10240*5e7646d2SAndroid Build Coastguard Worker     * Got a job URI; parse it to get the job ID...
10241*5e7646d2SAndroid Build Coastguard Worker     */
10242*5e7646d2SAndroid Build Coastguard Worker 
10243*5e7646d2SAndroid Build Coastguard Worker     httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
10244*5e7646d2SAndroid Build Coastguard Worker                     sizeof(scheme), username, sizeof(username), host,
10245*5e7646d2SAndroid Build Coastguard Worker 		    sizeof(host), &port, resource, sizeof(resource));
10246*5e7646d2SAndroid Build Coastguard Worker 
10247*5e7646d2SAndroid Build Coastguard Worker     if (strncmp(resource, "/jobs/", 6))
10248*5e7646d2SAndroid Build Coastguard Worker     {
10249*5e7646d2SAndroid Build Coastguard Worker      /*
10250*5e7646d2SAndroid Build Coastguard Worker       * Not a valid URI!
10251*5e7646d2SAndroid Build Coastguard Worker       */
10252*5e7646d2SAndroid Build Coastguard Worker 
10253*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
10254*5e7646d2SAndroid Build Coastguard Worker                       uri->values[0].string.text);
10255*5e7646d2SAndroid Build Coastguard Worker       return;
10256*5e7646d2SAndroid Build Coastguard Worker     }
10257*5e7646d2SAndroid Build Coastguard Worker 
10258*5e7646d2SAndroid Build Coastguard Worker     jobid = atoi(resource + 6);
10259*5e7646d2SAndroid Build Coastguard Worker   }
10260*5e7646d2SAndroid Build Coastguard Worker 
10261*5e7646d2SAndroid Build Coastguard Worker  /*
10262*5e7646d2SAndroid Build Coastguard Worker   * See if the job exists...
10263*5e7646d2SAndroid Build Coastguard Worker   */
10264*5e7646d2SAndroid Build Coastguard Worker 
10265*5e7646d2SAndroid Build Coastguard Worker   if ((job = cupsdFindJob(jobid)) == NULL)
10266*5e7646d2SAndroid Build Coastguard Worker   {
10267*5e7646d2SAndroid Build Coastguard Worker    /*
10268*5e7646d2SAndroid Build Coastguard Worker     * Nope - return a "not found" error...
10269*5e7646d2SAndroid Build Coastguard Worker     */
10270*5e7646d2SAndroid Build Coastguard Worker 
10271*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
10272*5e7646d2SAndroid Build Coastguard Worker     return;
10273*5e7646d2SAndroid Build Coastguard Worker   }
10274*5e7646d2SAndroid Build Coastguard Worker 
10275*5e7646d2SAndroid Build Coastguard Worker  /*
10276*5e7646d2SAndroid Build Coastguard Worker   * See if the job has been completed...
10277*5e7646d2SAndroid Build Coastguard Worker   */
10278*5e7646d2SAndroid Build Coastguard Worker 
10279*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value > IPP_JOB_STOPPED)
10280*5e7646d2SAndroid Build Coastguard Worker   {
10281*5e7646d2SAndroid Build Coastguard Worker    /*
10282*5e7646d2SAndroid Build Coastguard Worker     * Return a "not-possible" error...
10283*5e7646d2SAndroid Build Coastguard Worker     */
10284*5e7646d2SAndroid Build Coastguard Worker 
10285*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE,
10286*5e7646d2SAndroid Build Coastguard Worker                     _("Job #%d is finished and cannot be altered."), jobid);
10287*5e7646d2SAndroid Build Coastguard Worker     return;
10288*5e7646d2SAndroid Build Coastguard Worker   }
10289*5e7646d2SAndroid Build Coastguard Worker 
10290*5e7646d2SAndroid Build Coastguard Worker  /*
10291*5e7646d2SAndroid Build Coastguard Worker   * See if the job is owned by the requesting user...
10292*5e7646d2SAndroid Build Coastguard Worker   */
10293*5e7646d2SAndroid Build Coastguard Worker 
10294*5e7646d2SAndroid Build Coastguard Worker   if (!validate_user(job, con, job->username, username, sizeof(username)))
10295*5e7646d2SAndroid Build Coastguard Worker   {
10296*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
10297*5e7646d2SAndroid Build Coastguard Worker                     cupsdFindDest(job->dest));
10298*5e7646d2SAndroid Build Coastguard Worker     return;
10299*5e7646d2SAndroid Build Coastguard Worker   }
10300*5e7646d2SAndroid Build Coastguard Worker 
10301*5e7646d2SAndroid Build Coastguard Worker  /*
10302*5e7646d2SAndroid Build Coastguard Worker   * See what the user wants to change.
10303*5e7646d2SAndroid Build Coastguard Worker   */
10304*5e7646d2SAndroid Build Coastguard Worker 
10305*5e7646d2SAndroid Build Coastguard Worker   cupsdLoadJob(job);
10306*5e7646d2SAndroid Build Coastguard Worker 
10307*5e7646d2SAndroid Build Coastguard Worker   check_jobs = 0;
10308*5e7646d2SAndroid Build Coastguard Worker   event      = 0;
10309*5e7646d2SAndroid Build Coastguard Worker 
10310*5e7646d2SAndroid Build Coastguard Worker   for (attr = con->request->attrs; attr; attr = attr->next)
10311*5e7646d2SAndroid Build Coastguard Worker   {
10312*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag != IPP_TAG_JOB || !attr->name)
10313*5e7646d2SAndroid Build Coastguard Worker       continue;
10314*5e7646d2SAndroid Build Coastguard Worker 
10315*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->name, "attributes-charset") ||
10316*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "attributes-natural-language") ||
10317*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "date-time-at-", 13) ||
10318*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "document-compression", 20) ||
10319*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "document-format", 15) ||
10320*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-detailed-status-messages") ||
10321*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-document-access-errors") ||
10322*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-id") ||
10323*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-impressions-completed") ||
10324*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-k-octets-completed") ||
10325*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-media-sheets-completed") ||
10326*5e7646d2SAndroid Build Coastguard Worker         !strcmp(attr->name, "job-originating-host-name") ||
10327*5e7646d2SAndroid Build Coastguard Worker         !strcmp(attr->name, "job-originating-user-name") ||
10328*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-pages-completed") ||
10329*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-printer-up-time") ||
10330*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-printer-uri") ||
10331*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-sheets") ||
10332*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-state-message") ||
10333*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-state-reasons") ||
10334*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "job-uri") ||
10335*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "number-of-documents") ||
10336*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "number-of-intervening-jobs") ||
10337*5e7646d2SAndroid Build Coastguard Worker 	!strcmp(attr->name, "output-device-assigned") ||
10338*5e7646d2SAndroid Build Coastguard Worker 	!strncmp(attr->name, "time-at-", 8))
10339*5e7646d2SAndroid Build Coastguard Worker     {
10340*5e7646d2SAndroid Build Coastguard Worker      /*
10341*5e7646d2SAndroid Build Coastguard Worker       * Read-only attrs!
10342*5e7646d2SAndroid Build Coastguard Worker       */
10343*5e7646d2SAndroid Build Coastguard Worker 
10344*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE,
10345*5e7646d2SAndroid Build Coastguard Worker                       _("%s cannot be changed."), attr->name);
10346*5e7646d2SAndroid Build Coastguard Worker 
10347*5e7646d2SAndroid Build Coastguard Worker       attr2 = ippCopyAttribute(con->response, attr, 0);
10348*5e7646d2SAndroid Build Coastguard Worker       ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10349*5e7646d2SAndroid Build Coastguard Worker       continue;
10350*5e7646d2SAndroid Build Coastguard Worker     }
10351*5e7646d2SAndroid Build Coastguard Worker 
10352*5e7646d2SAndroid Build Coastguard Worker     if (!ippValidateAttribute(attr))
10353*5e7646d2SAndroid Build Coastguard Worker     {
10354*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad '%s' value."), attr->name);
10355*5e7646d2SAndroid Build Coastguard Worker       ippCopyAttribute(con->response, attr, 0);
10356*5e7646d2SAndroid Build Coastguard Worker       return;
10357*5e7646d2SAndroid Build Coastguard Worker     }
10358*5e7646d2SAndroid Build Coastguard Worker 
10359*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->name, "job-hold-until"))
10360*5e7646d2SAndroid Build Coastguard Worker     {
10361*5e7646d2SAndroid Build Coastguard Worker       const char *when = ippGetString(attr, 0, NULL);
10362*5e7646d2SAndroid Build Coastguard Worker 					/* job-hold-until value */
10363*5e7646d2SAndroid Build Coastguard Worker 
10364*5e7646d2SAndroid Build Coastguard Worker       if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1)
10365*5e7646d2SAndroid Build Coastguard Worker       {
10366*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
10367*5e7646d2SAndroid Build Coastguard Worker 	ippCopyAttribute(con->response, attr, 0);
10368*5e7646d2SAndroid Build Coastguard Worker 	return;
10369*5e7646d2SAndroid Build Coastguard Worker       }
10370*5e7646d2SAndroid Build Coastguard Worker 
10371*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", when);
10372*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobHoldUntil(job, when, 0);
10373*5e7646d2SAndroid Build Coastguard Worker 
10374*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(when, "no-hold"))
10375*5e7646d2SAndroid Build Coastguard Worker       {
10376*5e7646d2SAndroid Build Coastguard Worker 	cupsdReleaseJob(job);
10377*5e7646d2SAndroid Build Coastguard Worker 	check_jobs = 1;
10378*5e7646d2SAndroid Build Coastguard Worker       }
10379*5e7646d2SAndroid Build Coastguard Worker       else
10380*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", username);
10381*5e7646d2SAndroid Build Coastguard Worker 
10382*5e7646d2SAndroid Build Coastguard Worker       event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
10383*5e7646d2SAndroid Build Coastguard Worker     }
10384*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-priority"))
10385*5e7646d2SAndroid Build Coastguard Worker     {
10386*5e7646d2SAndroid Build Coastguard Worker      /*
10387*5e7646d2SAndroid Build Coastguard Worker       * Change the job priority...
10388*5e7646d2SAndroid Build Coastguard Worker       */
10389*5e7646d2SAndroid Build Coastguard Worker 
10390*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_INTEGER)
10391*5e7646d2SAndroid Build Coastguard Worker       {
10392*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value."));
10393*5e7646d2SAndroid Build Coastguard Worker 
10394*5e7646d2SAndroid Build Coastguard Worker 	attr2 = ippCopyAttribute(con->response, attr, 0);
10395*5e7646d2SAndroid Build Coastguard Worker 	ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10396*5e7646d2SAndroid Build Coastguard Worker       }
10397*5e7646d2SAndroid Build Coastguard Worker       else if (job->state_value >= IPP_JOB_PROCESSING)
10398*5e7646d2SAndroid Build Coastguard Worker       {
10399*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_POSSIBLE,
10400*5e7646d2SAndroid Build Coastguard Worker 	                _("Job is completed and cannot be changed."));
10401*5e7646d2SAndroid Build Coastguard Worker 	return;
10402*5e7646d2SAndroid Build Coastguard Worker       }
10403*5e7646d2SAndroid Build Coastguard Worker       else if (con->response->request.status.status_code == IPP_OK)
10404*5e7646d2SAndroid Build Coastguard Worker       {
10405*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d",
10406*5e7646d2SAndroid Build Coastguard Worker 	            attr->values[0].integer);
10407*5e7646d2SAndroid Build Coastguard Worker         cupsdSetJobPriority(job, attr->values[0].integer);
10408*5e7646d2SAndroid Build Coastguard Worker 
10409*5e7646d2SAndroid Build Coastguard Worker 	check_jobs = 1;
10410*5e7646d2SAndroid Build Coastguard Worker         event      |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
10411*5e7646d2SAndroid Build Coastguard Worker 	              CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
10412*5e7646d2SAndroid Build Coastguard Worker       }
10413*5e7646d2SAndroid Build Coastguard Worker     }
10414*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-state"))
10415*5e7646d2SAndroid Build Coastguard Worker     {
10416*5e7646d2SAndroid Build Coastguard Worker      /*
10417*5e7646d2SAndroid Build Coastguard Worker       * Change the job state...
10418*5e7646d2SAndroid Build Coastguard Worker       */
10419*5e7646d2SAndroid Build Coastguard Worker 
10420*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_ENUM)
10421*5e7646d2SAndroid Build Coastguard Worker       {
10422*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value."));
10423*5e7646d2SAndroid Build Coastguard Worker 
10424*5e7646d2SAndroid Build Coastguard Worker 	attr2 = ippCopyAttribute(con->response, attr, 0);
10425*5e7646d2SAndroid Build Coastguard Worker 	ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP);
10426*5e7646d2SAndroid Build Coastguard Worker       }
10427*5e7646d2SAndroid Build Coastguard Worker       else
10428*5e7646d2SAndroid Build Coastguard Worker       {
10429*5e7646d2SAndroid Build Coastguard Worker         switch (attr->values[0].integer)
10430*5e7646d2SAndroid Build Coastguard Worker 	{
10431*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_PENDING :
10432*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_HELD :
10433*5e7646d2SAndroid Build Coastguard Worker 	      if (job->state_value > IPP_JOB_HELD)
10434*5e7646d2SAndroid Build Coastguard Worker 	      {
10435*5e7646d2SAndroid Build Coastguard Worker 		send_ipp_status(con, IPP_NOT_POSSIBLE,
10436*5e7646d2SAndroid Build Coastguard Worker 		                _("Job state cannot be changed."));
10437*5e7646d2SAndroid Build Coastguard Worker 		return;
10438*5e7646d2SAndroid Build Coastguard Worker 	      }
10439*5e7646d2SAndroid Build Coastguard Worker               else if (con->response->request.status.status_code == IPP_OK)
10440*5e7646d2SAndroid Build Coastguard Worker 	      {
10441*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
10442*5e7646d2SAndroid Build Coastguard Worker 			    attr->values[0].integer);
10443*5e7646d2SAndroid Build Coastguard Worker                 cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer, CUPSD_JOB_DEFAULT, "Job state changed by \"%s\"", username);
10444*5e7646d2SAndroid Build Coastguard Worker 		check_jobs = 1;
10445*5e7646d2SAndroid Build Coastguard Worker 	      }
10446*5e7646d2SAndroid Build Coastguard Worker 	      break;
10447*5e7646d2SAndroid Build Coastguard Worker 
10448*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_PROCESSING :
10449*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_STOPPED :
10450*5e7646d2SAndroid Build Coastguard Worker 	      if (job->state_value != (ipp_jstate_t)attr->values[0].integer)
10451*5e7646d2SAndroid Build Coastguard Worker 	      {
10452*5e7646d2SAndroid Build Coastguard Worker 		send_ipp_status(con, IPP_NOT_POSSIBLE,
10453*5e7646d2SAndroid Build Coastguard Worker 		                _("Job state cannot be changed."));
10454*5e7646d2SAndroid Build Coastguard Worker 		return;
10455*5e7646d2SAndroid Build Coastguard Worker 	      }
10456*5e7646d2SAndroid Build Coastguard Worker 	      break;
10457*5e7646d2SAndroid Build Coastguard Worker 
10458*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_CANCELED :
10459*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_ABORTED :
10460*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_JOB_COMPLETED :
10461*5e7646d2SAndroid Build Coastguard Worker 	      if (job->state_value > IPP_JOB_PROCESSING)
10462*5e7646d2SAndroid Build Coastguard Worker 	      {
10463*5e7646d2SAndroid Build Coastguard Worker 		send_ipp_status(con, IPP_NOT_POSSIBLE,
10464*5e7646d2SAndroid Build Coastguard Worker 		                _("Job state cannot be changed."));
10465*5e7646d2SAndroid Build Coastguard Worker 		return;
10466*5e7646d2SAndroid Build Coastguard Worker 	      }
10467*5e7646d2SAndroid Build Coastguard Worker               else if (con->response->request.status.status_code == IPP_OK)
10468*5e7646d2SAndroid Build Coastguard Worker 	      {
10469*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
10470*5e7646d2SAndroid Build Coastguard Worker 			    attr->values[0].integer);
10471*5e7646d2SAndroid Build Coastguard Worker                 cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer,
10472*5e7646d2SAndroid Build Coastguard Worker 		                 CUPSD_JOB_DEFAULT,
10473*5e7646d2SAndroid Build Coastguard Worker 				 "Job state changed by \"%s\"", username);
10474*5e7646d2SAndroid Build Coastguard Worker                 check_jobs = 1;
10475*5e7646d2SAndroid Build Coastguard Worker 	      }
10476*5e7646d2SAndroid Build Coastguard Worker 	      break;
10477*5e7646d2SAndroid Build Coastguard Worker 	}
10478*5e7646d2SAndroid Build Coastguard Worker       }
10479*5e7646d2SAndroid Build Coastguard Worker     }
10480*5e7646d2SAndroid Build Coastguard Worker     else if (con->response->request.status.status_code != IPP_OK)
10481*5e7646d2SAndroid Build Coastguard Worker       continue;
10482*5e7646d2SAndroid Build Coastguard Worker     else if ((attr2 = ippFindAttribute(job->attrs, attr->name,
10483*5e7646d2SAndroid Build Coastguard Worker                                        IPP_TAG_ZERO)) != NULL)
10484*5e7646d2SAndroid Build Coastguard Worker     {
10485*5e7646d2SAndroid Build Coastguard Worker      /*
10486*5e7646d2SAndroid Build Coastguard Worker       * Some other value; first free the old value...
10487*5e7646d2SAndroid Build Coastguard Worker       */
10488*5e7646d2SAndroid Build Coastguard Worker 
10489*5e7646d2SAndroid Build Coastguard Worker       if (job->attrs->prev)
10490*5e7646d2SAndroid Build Coastguard Worker         job->attrs->prev->next = attr2->next;
10491*5e7646d2SAndroid Build Coastguard Worker       else
10492*5e7646d2SAndroid Build Coastguard Worker         job->attrs->attrs = attr2->next;
10493*5e7646d2SAndroid Build Coastguard Worker 
10494*5e7646d2SAndroid Build Coastguard Worker       if (job->attrs->last == attr2)
10495*5e7646d2SAndroid Build Coastguard Worker         job->attrs->last = job->attrs->prev;
10496*5e7646d2SAndroid Build Coastguard Worker 
10497*5e7646d2SAndroid Build Coastguard Worker       ippDeleteAttribute(NULL, attr2);
10498*5e7646d2SAndroid Build Coastguard Worker 
10499*5e7646d2SAndroid Build Coastguard Worker      /*
10500*5e7646d2SAndroid Build Coastguard Worker       * Then copy the attribute...
10501*5e7646d2SAndroid Build Coastguard Worker       */
10502*5e7646d2SAndroid Build Coastguard Worker 
10503*5e7646d2SAndroid Build Coastguard Worker       ippCopyAttribute(job->attrs, attr, 0);
10504*5e7646d2SAndroid Build Coastguard Worker     }
10505*5e7646d2SAndroid Build Coastguard Worker     else if (attr->value_tag == IPP_TAG_DELETEATTR)
10506*5e7646d2SAndroid Build Coastguard Worker     {
10507*5e7646d2SAndroid Build Coastguard Worker      /*
10508*5e7646d2SAndroid Build Coastguard Worker       * Delete the attribute...
10509*5e7646d2SAndroid Build Coastguard Worker       */
10510*5e7646d2SAndroid Build Coastguard Worker 
10511*5e7646d2SAndroid Build Coastguard Worker       if ((attr2 = ippFindAttribute(job->attrs, attr->name,
10512*5e7646d2SAndroid Build Coastguard Worker                                     IPP_TAG_ZERO)) != NULL)
10513*5e7646d2SAndroid Build Coastguard Worker       {
10514*5e7646d2SAndroid Build Coastguard Worker         if (job->attrs->prev)
10515*5e7646d2SAndroid Build Coastguard Worker 	  job->attrs->prev->next = attr2->next;
10516*5e7646d2SAndroid Build Coastguard Worker 	else
10517*5e7646d2SAndroid Build Coastguard Worker 	  job->attrs->attrs = attr2->next;
10518*5e7646d2SAndroid Build Coastguard Worker 
10519*5e7646d2SAndroid Build Coastguard Worker         if (attr2 == job->attrs->last)
10520*5e7646d2SAndroid Build Coastguard Worker 	  job->attrs->last = job->attrs->prev;
10521*5e7646d2SAndroid Build Coastguard Worker 
10522*5e7646d2SAndroid Build Coastguard Worker         ippDeleteAttribute(NULL, attr2);
10523*5e7646d2SAndroid Build Coastguard Worker 
10524*5e7646d2SAndroid Build Coastguard Worker         event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
10525*5e7646d2SAndroid Build Coastguard Worker       }
10526*5e7646d2SAndroid Build Coastguard Worker     }
10527*5e7646d2SAndroid Build Coastguard Worker     else
10528*5e7646d2SAndroid Build Coastguard Worker     {
10529*5e7646d2SAndroid Build Coastguard Worker      /*
10530*5e7646d2SAndroid Build Coastguard Worker       * Add new option by copying it...
10531*5e7646d2SAndroid Build Coastguard Worker       */
10532*5e7646d2SAndroid Build Coastguard Worker 
10533*5e7646d2SAndroid Build Coastguard Worker       ippCopyAttribute(job->attrs, attr, 0);
10534*5e7646d2SAndroid Build Coastguard Worker 
10535*5e7646d2SAndroid Build Coastguard Worker       event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
10536*5e7646d2SAndroid Build Coastguard Worker     }
10537*5e7646d2SAndroid Build Coastguard Worker   }
10538*5e7646d2SAndroid Build Coastguard Worker 
10539*5e7646d2SAndroid Build Coastguard Worker  /*
10540*5e7646d2SAndroid Build Coastguard Worker   * Save the job...
10541*5e7646d2SAndroid Build Coastguard Worker   */
10542*5e7646d2SAndroid Build Coastguard Worker 
10543*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
10544*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
10545*5e7646d2SAndroid Build Coastguard Worker 
10546*5e7646d2SAndroid Build Coastguard Worker  /*
10547*5e7646d2SAndroid Build Coastguard Worker   * Send events as needed...
10548*5e7646d2SAndroid Build Coastguard Worker   */
10549*5e7646d2SAndroid Build Coastguard Worker 
10550*5e7646d2SAndroid Build Coastguard Worker   if (event & CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED)
10551*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED,
10552*5e7646d2SAndroid Build Coastguard Worker                   cupsdFindDest(job->dest), job,
10553*5e7646d2SAndroid Build Coastguard Worker                   "Job priority changed by user.");
10554*5e7646d2SAndroid Build Coastguard Worker 
10555*5e7646d2SAndroid Build Coastguard Worker   if (event & CUPSD_EVENT_JOB_STATE)
10556*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
10557*5e7646d2SAndroid Build Coastguard Worker                   job->state_value == IPP_JOB_HELD ?
10558*5e7646d2SAndroid Build Coastguard Worker 		      "Job held by user." : "Job restarted by user.");
10559*5e7646d2SAndroid Build Coastguard Worker 
10560*5e7646d2SAndroid Build Coastguard Worker   if (event & CUPSD_EVENT_JOB_CONFIG_CHANGED)
10561*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
10562*5e7646d2SAndroid Build Coastguard Worker                   "Job options changed by user.");
10563*5e7646d2SAndroid Build Coastguard Worker 
10564*5e7646d2SAndroid Build Coastguard Worker  /*
10565*5e7646d2SAndroid Build Coastguard Worker   * Start jobs if possible...
10566*5e7646d2SAndroid Build Coastguard Worker   */
10567*5e7646d2SAndroid Build Coastguard Worker 
10568*5e7646d2SAndroid Build Coastguard Worker   if (check_jobs)
10569*5e7646d2SAndroid Build Coastguard Worker     cupsdCheckJobs();
10570*5e7646d2SAndroid Build Coastguard Worker }
10571*5e7646d2SAndroid Build Coastguard Worker 
10572*5e7646d2SAndroid Build Coastguard Worker 
10573*5e7646d2SAndroid Build Coastguard Worker /*
10574*5e7646d2SAndroid Build Coastguard Worker  * 'set_printer_attrs()' - Set printer attributes.
10575*5e7646d2SAndroid Build Coastguard Worker  */
10576*5e7646d2SAndroid Build Coastguard Worker 
10577*5e7646d2SAndroid Build Coastguard Worker static void
set_printer_attrs(cupsd_client_t * con,ipp_attribute_t * uri)10578*5e7646d2SAndroid Build Coastguard Worker set_printer_attrs(cupsd_client_t  *con,	/* I - Client connection */
10579*5e7646d2SAndroid Build Coastguard Worker                   ipp_attribute_t *uri)	/* I - Printer */
10580*5e7646d2SAndroid Build Coastguard Worker {
10581*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
10582*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
10583*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer/class */
10584*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Printer attribute */
10585*5e7646d2SAndroid Build Coastguard Worker   int			changed = 0;	/* Was anything changed? */
10586*5e7646d2SAndroid Build Coastguard Worker 
10587*5e7646d2SAndroid Build Coastguard Worker 
10588*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con,
10589*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
10590*5e7646d2SAndroid Build Coastguard Worker 
10591*5e7646d2SAndroid Build Coastguard Worker  /*
10592*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
10593*5e7646d2SAndroid Build Coastguard Worker   */
10594*5e7646d2SAndroid Build Coastguard Worker 
10595*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
10596*5e7646d2SAndroid Build Coastguard Worker   {
10597*5e7646d2SAndroid Build Coastguard Worker    /*
10598*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
10599*5e7646d2SAndroid Build Coastguard Worker     */
10600*5e7646d2SAndroid Build Coastguard Worker 
10601*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
10602*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
10603*5e7646d2SAndroid Build Coastguard Worker     return;
10604*5e7646d2SAndroid Build Coastguard Worker   }
10605*5e7646d2SAndroid Build Coastguard Worker 
10606*5e7646d2SAndroid Build Coastguard Worker  /*
10607*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
10608*5e7646d2SAndroid Build Coastguard Worker   */
10609*5e7646d2SAndroid Build Coastguard Worker 
10610*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
10611*5e7646d2SAndroid Build Coastguard Worker   {
10612*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
10613*5e7646d2SAndroid Build Coastguard Worker     return;
10614*5e7646d2SAndroid Build Coastguard Worker   }
10615*5e7646d2SAndroid Build Coastguard Worker 
10616*5e7646d2SAndroid Build Coastguard Worker  /*
10617*5e7646d2SAndroid Build Coastguard Worker   * Return a list of attributes that can be set via Set-Printer-Attributes.
10618*5e7646d2SAndroid Build Coastguard Worker   */
10619*5e7646d2SAndroid Build Coastguard Worker 
10620*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-location",
10621*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
10622*5e7646d2SAndroid Build Coastguard Worker   {
10623*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->location, attr->values[0].string.text);
10624*5e7646d2SAndroid Build Coastguard Worker     changed = 1;
10625*5e7646d2SAndroid Build Coastguard Worker   }
10626*5e7646d2SAndroid Build Coastguard Worker 
10627*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4))
10628*5e7646d2SAndroid Build Coastguard Worker   {
10629*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->geo_location, attr->values[0].string.text);
10630*5e7646d2SAndroid Build Coastguard Worker     changed = 1;
10631*5e7646d2SAndroid Build Coastguard Worker   }
10632*5e7646d2SAndroid Build Coastguard Worker 
10633*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL)
10634*5e7646d2SAndroid Build Coastguard Worker   {
10635*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->organization, attr->values[0].string.text);
10636*5e7646d2SAndroid Build Coastguard Worker     changed = 1;
10637*5e7646d2SAndroid Build Coastguard Worker   }
10638*5e7646d2SAndroid Build Coastguard Worker 
10639*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL)
10640*5e7646d2SAndroid Build Coastguard Worker   {
10641*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->organizational_unit, attr->values[0].string.text);
10642*5e7646d2SAndroid Build Coastguard Worker     changed = 1;
10643*5e7646d2SAndroid Build Coastguard Worker   }
10644*5e7646d2SAndroid Build Coastguard Worker 
10645*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-info",
10646*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) != NULL)
10647*5e7646d2SAndroid Build Coastguard Worker   {
10648*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&printer->info, attr->values[0].string.text);
10649*5e7646d2SAndroid Build Coastguard Worker     changed = 1;
10650*5e7646d2SAndroid Build Coastguard Worker   }
10651*5e7646d2SAndroid Build Coastguard Worker 
10652*5e7646d2SAndroid Build Coastguard Worker  /*
10653*5e7646d2SAndroid Build Coastguard Worker   * Update the printer attributes and return...
10654*5e7646d2SAndroid Build Coastguard Worker   */
10655*5e7646d2SAndroid Build Coastguard Worker 
10656*5e7646d2SAndroid Build Coastguard Worker   if (changed)
10657*5e7646d2SAndroid Build Coastguard Worker   {
10658*5e7646d2SAndroid Build Coastguard Worker     printer->config_time = time(NULL);
10659*5e7646d2SAndroid Build Coastguard Worker 
10660*5e7646d2SAndroid Build Coastguard Worker     cupsdSetPrinterAttrs(printer);
10661*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
10662*5e7646d2SAndroid Build Coastguard Worker 
10663*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL,
10664*5e7646d2SAndroid Build Coastguard Worker                   "Printer \"%s\" description or location changed by \"%s\".",
10665*5e7646d2SAndroid Build Coastguard Worker 		  printer->name, get_username(con));
10666*5e7646d2SAndroid Build Coastguard Worker 
10667*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO,
10668*5e7646d2SAndroid Build Coastguard Worker                     "Printer \"%s\" description or location changed by \"%s\".",
10669*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
10670*5e7646d2SAndroid Build Coastguard Worker   }
10671*5e7646d2SAndroid Build Coastguard Worker 
10672*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
10673*5e7646d2SAndroid Build Coastguard Worker }
10674*5e7646d2SAndroid Build Coastguard Worker 
10675*5e7646d2SAndroid Build Coastguard Worker 
10676*5e7646d2SAndroid Build Coastguard Worker /*
10677*5e7646d2SAndroid Build Coastguard Worker  * 'set_printer_defaults()' - Set printer default options from a request.
10678*5e7646d2SAndroid Build Coastguard Worker  */
10679*5e7646d2SAndroid Build Coastguard Worker 
10680*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 on success, 0 on failure */
set_printer_defaults(cupsd_client_t * con,cupsd_printer_t * printer)10681*5e7646d2SAndroid Build Coastguard Worker set_printer_defaults(
10682*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t  *con,		/* I - Client connection */
10683*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *printer)		/* I - Printer */
10684*5e7646d2SAndroid Build Coastguard Worker {
10685*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
10686*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t 	*attr;		/* Current attribute */
10687*5e7646d2SAndroid Build Coastguard Worker   size_t		namelen;	/* Length of attribute name */
10688*5e7646d2SAndroid Build Coastguard Worker   char			name[256],	/* New attribute name */
10689*5e7646d2SAndroid Build Coastguard Worker 			value[256];	/* String version of integer attrs */
10690*5e7646d2SAndroid Build Coastguard Worker 
10691*5e7646d2SAndroid Build Coastguard Worker 
10692*5e7646d2SAndroid Build Coastguard Worker   for (attr = con->request->attrs; attr; attr = attr->next)
10693*5e7646d2SAndroid Build Coastguard Worker   {
10694*5e7646d2SAndroid Build Coastguard Worker    /*
10695*5e7646d2SAndroid Build Coastguard Worker     * Skip non-printer attributes...
10696*5e7646d2SAndroid Build Coastguard Worker     */
10697*5e7646d2SAndroid Build Coastguard Worker 
10698*5e7646d2SAndroid Build Coastguard Worker     if (attr->group_tag != IPP_TAG_PRINTER || !attr->name)
10699*5e7646d2SAndroid Build Coastguard Worker       continue;
10700*5e7646d2SAndroid Build Coastguard Worker 
10701*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_defaults: %s", attr->name);
10702*5e7646d2SAndroid Build Coastguard Worker 
10703*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->name, "job-sheets-default"))
10704*5e7646d2SAndroid Build Coastguard Worker     {
10705*5e7646d2SAndroid Build Coastguard Worker      /*
10706*5e7646d2SAndroid Build Coastguard Worker       * Only allow keywords and names...
10707*5e7646d2SAndroid Build Coastguard Worker       */
10708*5e7646d2SAndroid Build Coastguard Worker 
10709*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
10710*5e7646d2SAndroid Build Coastguard Worker         continue;
10711*5e7646d2SAndroid Build Coastguard Worker 
10712*5e7646d2SAndroid Build Coastguard Worker      /*
10713*5e7646d2SAndroid Build Coastguard Worker       * Only allow job-sheets-default to be set when running without a
10714*5e7646d2SAndroid Build Coastguard Worker       * system high classification level...
10715*5e7646d2SAndroid Build Coastguard Worker       */
10716*5e7646d2SAndroid Build Coastguard Worker 
10717*5e7646d2SAndroid Build Coastguard Worker       if (Classification)
10718*5e7646d2SAndroid Build Coastguard Worker         continue;
10719*5e7646d2SAndroid Build Coastguard Worker 
10720*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->job_sheets[0], attr->values[0].string.text);
10721*5e7646d2SAndroid Build Coastguard Worker 
10722*5e7646d2SAndroid Build Coastguard Worker       if (attr->num_values > 1)
10723*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetString(&printer->job_sheets[1], attr->values[1].string.text);
10724*5e7646d2SAndroid Build Coastguard Worker       else
10725*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetString(&printer->job_sheets[1], "none");
10726*5e7646d2SAndroid Build Coastguard Worker     }
10727*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "requesting-user-name-allowed"))
10728*5e7646d2SAndroid Build Coastguard Worker     {
10729*5e7646d2SAndroid Build Coastguard Worker       cupsdFreeStrings(&(printer->users));
10730*5e7646d2SAndroid Build Coastguard Worker 
10731*5e7646d2SAndroid Build Coastguard Worker       printer->deny_users = 0;
10732*5e7646d2SAndroid Build Coastguard Worker 
10733*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag == IPP_TAG_NAME &&
10734*5e7646d2SAndroid Build Coastguard Worker           (attr->num_values > 1 ||
10735*5e7646d2SAndroid Build Coastguard Worker 	   strcmp(attr->values[0].string.text, "all")))
10736*5e7646d2SAndroid Build Coastguard Worker       {
10737*5e7646d2SAndroid Build Coastguard Worker 	for (i = 0; i < attr->num_values; i ++)
10738*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAddString(&(printer->users), attr->values[i].string.text);
10739*5e7646d2SAndroid Build Coastguard Worker       }
10740*5e7646d2SAndroid Build Coastguard Worker     }
10741*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "requesting-user-name-denied"))
10742*5e7646d2SAndroid Build Coastguard Worker     {
10743*5e7646d2SAndroid Build Coastguard Worker       cupsdFreeStrings(&(printer->users));
10744*5e7646d2SAndroid Build Coastguard Worker 
10745*5e7646d2SAndroid Build Coastguard Worker       printer->deny_users = 1;
10746*5e7646d2SAndroid Build Coastguard Worker 
10747*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag == IPP_TAG_NAME &&
10748*5e7646d2SAndroid Build Coastguard Worker           (attr->num_values > 1 ||
10749*5e7646d2SAndroid Build Coastguard Worker 	   strcmp(attr->values[0].string.text, "none")))
10750*5e7646d2SAndroid Build Coastguard Worker       {
10751*5e7646d2SAndroid Build Coastguard Worker 	for (i = 0; i < attr->num_values; i ++)
10752*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAddString(&(printer->users), attr->values[i].string.text);
10753*5e7646d2SAndroid Build Coastguard Worker       }
10754*5e7646d2SAndroid Build Coastguard Worker     }
10755*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-quota-period"))
10756*5e7646d2SAndroid Build Coastguard Worker     {
10757*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_INTEGER)
10758*5e7646d2SAndroid Build Coastguard Worker         continue;
10759*5e7646d2SAndroid Build Coastguard Worker 
10760*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-quota-period to %d...",
10761*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].integer);
10762*5e7646d2SAndroid Build Coastguard Worker       cupsdFreeQuotas(printer);
10763*5e7646d2SAndroid Build Coastguard Worker 
10764*5e7646d2SAndroid Build Coastguard Worker       printer->quota_period = attr->values[0].integer;
10765*5e7646d2SAndroid Build Coastguard Worker     }
10766*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-k-limit"))
10767*5e7646d2SAndroid Build Coastguard Worker     {
10768*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_INTEGER)
10769*5e7646d2SAndroid Build Coastguard Worker         continue;
10770*5e7646d2SAndroid Build Coastguard Worker 
10771*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-k-limit to %d...",
10772*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].integer);
10773*5e7646d2SAndroid Build Coastguard Worker       cupsdFreeQuotas(printer);
10774*5e7646d2SAndroid Build Coastguard Worker 
10775*5e7646d2SAndroid Build Coastguard Worker       printer->k_limit = attr->values[0].integer;
10776*5e7646d2SAndroid Build Coastguard Worker     }
10777*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-page-limit"))
10778*5e7646d2SAndroid Build Coastguard Worker     {
10779*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_INTEGER)
10780*5e7646d2SAndroid Build Coastguard Worker         continue;
10781*5e7646d2SAndroid Build Coastguard Worker 
10782*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-page-limit to %d...",
10783*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].integer);
10784*5e7646d2SAndroid Build Coastguard Worker       cupsdFreeQuotas(printer);
10785*5e7646d2SAndroid Build Coastguard Worker 
10786*5e7646d2SAndroid Build Coastguard Worker       printer->page_limit = attr->values[0].integer;
10787*5e7646d2SAndroid Build Coastguard Worker     }
10788*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "printer-op-policy"))
10789*5e7646d2SAndroid Build Coastguard Worker     {
10790*5e7646d2SAndroid Build Coastguard Worker       cupsd_policy_t *p;		/* Policy */
10791*5e7646d2SAndroid Build Coastguard Worker 
10792*5e7646d2SAndroid Build Coastguard Worker 
10793*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_NAME)
10794*5e7646d2SAndroid Build Coastguard Worker         continue;
10795*5e7646d2SAndroid Build Coastguard Worker 
10796*5e7646d2SAndroid Build Coastguard Worker       if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL)
10797*5e7646d2SAndroid Build Coastguard Worker       {
10798*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogMessage(CUPSD_LOG_DEBUG,
10799*5e7646d2SAndroid Build Coastguard Worker                 	"Setting printer-op-policy to \"%s\"...",
10800*5e7646d2SAndroid Build Coastguard Worker                 	attr->values[0].string.text);
10801*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetString(&printer->op_policy, attr->values[0].string.text);
10802*5e7646d2SAndroid Build Coastguard Worker 	printer->op_policy_ptr = p;
10803*5e7646d2SAndroid Build Coastguard Worker       }
10804*5e7646d2SAndroid Build Coastguard Worker       else
10805*5e7646d2SAndroid Build Coastguard Worker       {
10806*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_POSSIBLE,
10807*5e7646d2SAndroid Build Coastguard Worker                 	_("Unknown printer-op-policy \"%s\"."),
10808*5e7646d2SAndroid Build Coastguard Worker                 	attr->values[0].string.text);
10809*5e7646d2SAndroid Build Coastguard Worker 	return (0);
10810*5e7646d2SAndroid Build Coastguard Worker       }
10811*5e7646d2SAndroid Build Coastguard Worker     }
10812*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "printer-error-policy"))
10813*5e7646d2SAndroid Build Coastguard Worker     {
10814*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
10815*5e7646d2SAndroid Build Coastguard Worker         continue;
10816*5e7646d2SAndroid Build Coastguard Worker 
10817*5e7646d2SAndroid Build Coastguard Worker       if (strcmp(attr->values[0].string.text, "retry-current-job") &&
10818*5e7646d2SAndroid Build Coastguard Worker           ((printer->type & CUPS_PRINTER_CLASS) ||
10819*5e7646d2SAndroid Build Coastguard Worker 	   (strcmp(attr->values[0].string.text, "abort-job") &&
10820*5e7646d2SAndroid Build Coastguard Worker 	    strcmp(attr->values[0].string.text, "retry-job") &&
10821*5e7646d2SAndroid Build Coastguard Worker 	    strcmp(attr->values[0].string.text, "stop-printer"))))
10822*5e7646d2SAndroid Build Coastguard Worker       {
10823*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_NOT_POSSIBLE,
10824*5e7646d2SAndroid Build Coastguard Worker                 	_("Unknown printer-error-policy \"%s\"."),
10825*5e7646d2SAndroid Build Coastguard Worker                 	attr->values[0].string.text);
10826*5e7646d2SAndroid Build Coastguard Worker 	return (0);
10827*5e7646d2SAndroid Build Coastguard Worker       }
10828*5e7646d2SAndroid Build Coastguard Worker 
10829*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
10830*5e7646d2SAndroid Build Coastguard Worker                       "Setting printer-error-policy to \"%s\"...",
10831*5e7646d2SAndroid Build Coastguard Worker                       attr->values[0].string.text);
10832*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&printer->error_policy, attr->values[0].string.text);
10833*5e7646d2SAndroid Build Coastguard Worker     }
10834*5e7646d2SAndroid Build Coastguard Worker 
10835*5e7646d2SAndroid Build Coastguard Worker    /*
10836*5e7646d2SAndroid Build Coastguard Worker     * Skip any other non-default attributes...
10837*5e7646d2SAndroid Build Coastguard Worker     */
10838*5e7646d2SAndroid Build Coastguard Worker 
10839*5e7646d2SAndroid Build Coastguard Worker     namelen = strlen(attr->name);
10840*5e7646d2SAndroid Build Coastguard Worker     if (namelen < 9 || strcmp(attr->name + namelen - 8, "-default") ||
10841*5e7646d2SAndroid Build Coastguard Worker         namelen > (sizeof(name) - 1) || attr->num_values != 1)
10842*5e7646d2SAndroid Build Coastguard Worker       continue;
10843*5e7646d2SAndroid Build Coastguard Worker 
10844*5e7646d2SAndroid Build Coastguard Worker    /*
10845*5e7646d2SAndroid Build Coastguard Worker     * OK, anything else must be a user-defined default...
10846*5e7646d2SAndroid Build Coastguard Worker     */
10847*5e7646d2SAndroid Build Coastguard Worker 
10848*5e7646d2SAndroid Build Coastguard Worker     strlcpy(name, attr->name, sizeof(name));
10849*5e7646d2SAndroid Build Coastguard Worker     name[namelen - 8] = '\0';		/* Strip "-default" */
10850*5e7646d2SAndroid Build Coastguard Worker 
10851*5e7646d2SAndroid Build Coastguard Worker     switch (attr->value_tag)
10852*5e7646d2SAndroid Build Coastguard Worker     {
10853*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_DELETEATTR :
10854*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsRemoveOption(name,
10855*5e7646d2SAndroid Build Coastguard Worker 						  printer->num_options,
10856*5e7646d2SAndroid Build Coastguard Worker 						  &(printer->options));
10857*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10858*5e7646d2SAndroid Build Coastguard Worker 	                  "Deleting %s", attr->name);
10859*5e7646d2SAndroid Build Coastguard Worker           break;
10860*5e7646d2SAndroid Build Coastguard Worker 
10861*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_NAME :
10862*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_TEXT :
10863*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_KEYWORD :
10864*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_URI :
10865*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsAddOption(name,
10866*5e7646d2SAndroid Build Coastguard Worker 	                                       attr->values[0].string.text,
10867*5e7646d2SAndroid Build Coastguard Worker 					       printer->num_options,
10868*5e7646d2SAndroid Build Coastguard Worker 					       &(printer->options));
10869*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10870*5e7646d2SAndroid Build Coastguard Worker 	                  "Setting %s to \"%s\"...", attr->name,
10871*5e7646d2SAndroid Build Coastguard Worker 			  attr->values[0].string.text);
10872*5e7646d2SAndroid Build Coastguard Worker           break;
10873*5e7646d2SAndroid Build Coastguard Worker 
10874*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_BOOLEAN :
10875*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsAddOption(name,
10876*5e7646d2SAndroid Build Coastguard Worker 	                                       attr->values[0].boolean ?
10877*5e7646d2SAndroid Build Coastguard Worker 					           "true" : "false",
10878*5e7646d2SAndroid Build Coastguard Worker 					       printer->num_options,
10879*5e7646d2SAndroid Build Coastguard Worker 					       &(printer->options));
10880*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10881*5e7646d2SAndroid Build Coastguard Worker 	                  "Setting %s to %s...", attr->name,
10882*5e7646d2SAndroid Build Coastguard Worker 			  attr->values[0].boolean ? "true" : "false");
10883*5e7646d2SAndroid Build Coastguard Worker           break;
10884*5e7646d2SAndroid Build Coastguard Worker 
10885*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_INTEGER :
10886*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_ENUM :
10887*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsAddIntegerOption(name, attr->values[0].integer, printer->num_options, &(printer->options));
10888*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10889*5e7646d2SAndroid Build Coastguard Worker 	                  "Setting %s to %s...", attr->name, value);
10890*5e7646d2SAndroid Build Coastguard Worker           break;
10891*5e7646d2SAndroid Build Coastguard Worker 
10892*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_RANGE :
10893*5e7646d2SAndroid Build Coastguard Worker           snprintf(value, sizeof(value), "%d-%d", attr->values[0].range.lower, attr->values[0].range.upper);
10894*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsAddOption(name, value,
10895*5e7646d2SAndroid Build Coastguard Worker 					       printer->num_options,
10896*5e7646d2SAndroid Build Coastguard Worker 					       &(printer->options));
10897*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10898*5e7646d2SAndroid Build Coastguard Worker 	                  "Setting %s to %s...", attr->name, value);
10899*5e7646d2SAndroid Build Coastguard Worker           break;
10900*5e7646d2SAndroid Build Coastguard Worker 
10901*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_RESOLUTION :
10902*5e7646d2SAndroid Build Coastguard Worker           snprintf(value, sizeof(value), "%dx%d%s", attr->values[0].resolution.xres, attr->values[0].resolution.yres, attr->values[0].resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
10903*5e7646d2SAndroid Build Coastguard Worker           printer->num_options = cupsAddOption(name, value,
10904*5e7646d2SAndroid Build Coastguard Worker 					       printer->num_options,
10905*5e7646d2SAndroid Build Coastguard Worker 					       &(printer->options));
10906*5e7646d2SAndroid Build Coastguard Worker           cupsdLogMessage(CUPSD_LOG_DEBUG,
10907*5e7646d2SAndroid Build Coastguard Worker 	                  "Setting %s to %s...", attr->name, value);
10908*5e7646d2SAndroid Build Coastguard Worker           break;
10909*5e7646d2SAndroid Build Coastguard Worker 
10910*5e7646d2SAndroid Build Coastguard Worker       default :
10911*5e7646d2SAndroid Build Coastguard Worker           /* Do nothing for other values */
10912*5e7646d2SAndroid Build Coastguard Worker 	  break;
10913*5e7646d2SAndroid Build Coastguard Worker     }
10914*5e7646d2SAndroid Build Coastguard Worker   }
10915*5e7646d2SAndroid Build Coastguard Worker 
10916*5e7646d2SAndroid Build Coastguard Worker   return (1);
10917*5e7646d2SAndroid Build Coastguard Worker }
10918*5e7646d2SAndroid Build Coastguard Worker 
10919*5e7646d2SAndroid Build Coastguard Worker 
10920*5e7646d2SAndroid Build Coastguard Worker /*
10921*5e7646d2SAndroid Build Coastguard Worker  * 'start_printer()' - Start a printer.
10922*5e7646d2SAndroid Build Coastguard Worker  */
10923*5e7646d2SAndroid Build Coastguard Worker 
10924*5e7646d2SAndroid Build Coastguard Worker static void
start_printer(cupsd_client_t * con,ipp_attribute_t * uri)10925*5e7646d2SAndroid Build Coastguard Worker start_printer(cupsd_client_t  *con,	/* I - Client connection */
10926*5e7646d2SAndroid Build Coastguard Worker               ipp_attribute_t *uri)	/* I - Printer URI */
10927*5e7646d2SAndroid Build Coastguard Worker {
10928*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Temporary variable */
10929*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
10930*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
10931*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer data */
10932*5e7646d2SAndroid Build Coastguard Worker 
10933*5e7646d2SAndroid Build Coastguard Worker 
10934*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con,
10935*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
10936*5e7646d2SAndroid Build Coastguard Worker 
10937*5e7646d2SAndroid Build Coastguard Worker  /*
10938*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
10939*5e7646d2SAndroid Build Coastguard Worker   */
10940*5e7646d2SAndroid Build Coastguard Worker 
10941*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
10942*5e7646d2SAndroid Build Coastguard Worker   {
10943*5e7646d2SAndroid Build Coastguard Worker    /*
10944*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
10945*5e7646d2SAndroid Build Coastguard Worker     */
10946*5e7646d2SAndroid Build Coastguard Worker 
10947*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
10948*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
10949*5e7646d2SAndroid Build Coastguard Worker     return;
10950*5e7646d2SAndroid Build Coastguard Worker   }
10951*5e7646d2SAndroid Build Coastguard Worker 
10952*5e7646d2SAndroid Build Coastguard Worker  /*
10953*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
10954*5e7646d2SAndroid Build Coastguard Worker   */
10955*5e7646d2SAndroid Build Coastguard Worker 
10956*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
10957*5e7646d2SAndroid Build Coastguard Worker   {
10958*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
10959*5e7646d2SAndroid Build Coastguard Worker     return;
10960*5e7646d2SAndroid Build Coastguard Worker   }
10961*5e7646d2SAndroid Build Coastguard Worker 
10962*5e7646d2SAndroid Build Coastguard Worker  /*
10963*5e7646d2SAndroid Build Coastguard Worker   * Start the printer...
10964*5e7646d2SAndroid Build Coastguard Worker   */
10965*5e7646d2SAndroid Build Coastguard Worker 
10966*5e7646d2SAndroid Build Coastguard Worker   printer->state_message[0] = '\0';
10967*5e7646d2SAndroid Build Coastguard Worker 
10968*5e7646d2SAndroid Build Coastguard Worker   cupsdStartPrinter(printer, 1);
10969*5e7646d2SAndroid Build Coastguard Worker 
10970*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
10971*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".",
10972*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
10973*5e7646d2SAndroid Build Coastguard Worker   else
10974*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".",
10975*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
10976*5e7646d2SAndroid Build Coastguard Worker 
10977*5e7646d2SAndroid Build Coastguard Worker   cupsdCheckJobs();
10978*5e7646d2SAndroid Build Coastguard Worker 
10979*5e7646d2SAndroid Build Coastguard Worker  /*
10980*5e7646d2SAndroid Build Coastguard Worker   * Check quotas...
10981*5e7646d2SAndroid Build Coastguard Worker   */
10982*5e7646d2SAndroid Build Coastguard Worker 
10983*5e7646d2SAndroid Build Coastguard Worker   if ((i = check_quotas(con, printer)) < 0)
10984*5e7646d2SAndroid Build Coastguard Worker   {
10985*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
10986*5e7646d2SAndroid Build Coastguard Worker     return;
10987*5e7646d2SAndroid Build Coastguard Worker   }
10988*5e7646d2SAndroid Build Coastguard Worker   else if (i == 0)
10989*5e7646d2SAndroid Build Coastguard Worker   {
10990*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
10991*5e7646d2SAndroid Build Coastguard Worker     return;
10992*5e7646d2SAndroid Build Coastguard Worker   }
10993*5e7646d2SAndroid Build Coastguard Worker 
10994*5e7646d2SAndroid Build Coastguard Worker  /*
10995*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
10996*5e7646d2SAndroid Build Coastguard Worker   */
10997*5e7646d2SAndroid Build Coastguard Worker 
10998*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
10999*5e7646d2SAndroid Build Coastguard Worker }
11000*5e7646d2SAndroid Build Coastguard Worker 
11001*5e7646d2SAndroid Build Coastguard Worker 
11002*5e7646d2SAndroid Build Coastguard Worker /*
11003*5e7646d2SAndroid Build Coastguard Worker  * 'stop_printer()' - Stop a printer.
11004*5e7646d2SAndroid Build Coastguard Worker  */
11005*5e7646d2SAndroid Build Coastguard Worker 
11006*5e7646d2SAndroid Build Coastguard Worker static void
stop_printer(cupsd_client_t * con,ipp_attribute_t * uri)11007*5e7646d2SAndroid Build Coastguard Worker stop_printer(cupsd_client_t  *con,	/* I - Client connection */
11008*5e7646d2SAndroid Build Coastguard Worker              ipp_attribute_t *uri)	/* I - Printer URI */
11009*5e7646d2SAndroid Build Coastguard Worker {
11010*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
11011*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
11012*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer data */
11013*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* printer-state-message attribute */
11014*5e7646d2SAndroid Build Coastguard Worker 
11015*5e7646d2SAndroid Build Coastguard Worker 
11016*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con,
11017*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
11018*5e7646d2SAndroid Build Coastguard Worker 
11019*5e7646d2SAndroid Build Coastguard Worker  /*
11020*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
11021*5e7646d2SAndroid Build Coastguard Worker   */
11022*5e7646d2SAndroid Build Coastguard Worker 
11023*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
11024*5e7646d2SAndroid Build Coastguard Worker   {
11025*5e7646d2SAndroid Build Coastguard Worker    /*
11026*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
11027*5e7646d2SAndroid Build Coastguard Worker     */
11028*5e7646d2SAndroid Build Coastguard Worker 
11029*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
11030*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
11031*5e7646d2SAndroid Build Coastguard Worker     return;
11032*5e7646d2SAndroid Build Coastguard Worker   }
11033*5e7646d2SAndroid Build Coastguard Worker 
11034*5e7646d2SAndroid Build Coastguard Worker  /*
11035*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
11036*5e7646d2SAndroid Build Coastguard Worker   */
11037*5e7646d2SAndroid Build Coastguard Worker 
11038*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
11039*5e7646d2SAndroid Build Coastguard Worker   {
11040*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
11041*5e7646d2SAndroid Build Coastguard Worker     return;
11042*5e7646d2SAndroid Build Coastguard Worker   }
11043*5e7646d2SAndroid Build Coastguard Worker 
11044*5e7646d2SAndroid Build Coastguard Worker  /*
11045*5e7646d2SAndroid Build Coastguard Worker   * Stop the printer...
11046*5e7646d2SAndroid Build Coastguard Worker   */
11047*5e7646d2SAndroid Build Coastguard Worker 
11048*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "printer-state-message",
11049*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_TEXT)) == NULL)
11050*5e7646d2SAndroid Build Coastguard Worker     strlcpy(printer->state_message, "Paused", sizeof(printer->state_message));
11051*5e7646d2SAndroid Build Coastguard Worker   else
11052*5e7646d2SAndroid Build Coastguard Worker   {
11053*5e7646d2SAndroid Build Coastguard Worker     strlcpy(printer->state_message, attr->values[0].string.text,
11054*5e7646d2SAndroid Build Coastguard Worker             sizeof(printer->state_message));
11055*5e7646d2SAndroid Build Coastguard Worker   }
11056*5e7646d2SAndroid Build Coastguard Worker 
11057*5e7646d2SAndroid Build Coastguard Worker   cupsdStopPrinter(printer, 1);
11058*5e7646d2SAndroid Build Coastguard Worker 
11059*5e7646d2SAndroid Build Coastguard Worker   if (dtype & CUPS_PRINTER_CLASS)
11060*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".",
11061*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
11062*5e7646d2SAndroid Build Coastguard Worker   else
11063*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".",
11064*5e7646d2SAndroid Build Coastguard Worker                     printer->name, get_username(con));
11065*5e7646d2SAndroid Build Coastguard Worker 
11066*5e7646d2SAndroid Build Coastguard Worker  /*
11067*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
11068*5e7646d2SAndroid Build Coastguard Worker   */
11069*5e7646d2SAndroid Build Coastguard Worker 
11070*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
11071*5e7646d2SAndroid Build Coastguard Worker }
11072*5e7646d2SAndroid Build Coastguard Worker 
11073*5e7646d2SAndroid Build Coastguard Worker 
11074*5e7646d2SAndroid Build Coastguard Worker /*
11075*5e7646d2SAndroid Build Coastguard Worker  * 'url_encode_attr()' - URL-encode a string attribute.
11076*5e7646d2SAndroid Build Coastguard Worker  */
11077*5e7646d2SAndroid Build Coastguard Worker 
11078*5e7646d2SAndroid Build Coastguard Worker static void
url_encode_attr(ipp_attribute_t * attr,char * buffer,size_t bufsize)11079*5e7646d2SAndroid Build Coastguard Worker url_encode_attr(ipp_attribute_t *attr,	/* I - Attribute */
11080*5e7646d2SAndroid Build Coastguard Worker                 char            *buffer,/* I - String buffer */
11081*5e7646d2SAndroid Build Coastguard Worker 		size_t          bufsize)/* I - Size of buffer */
11082*5e7646d2SAndroid Build Coastguard Worker {
11083*5e7646d2SAndroid Build Coastguard Worker   int	i;				/* Looping var */
11084*5e7646d2SAndroid Build Coastguard Worker   char	*bufptr,			/* Pointer into buffer */
11085*5e7646d2SAndroid Build Coastguard Worker 	*bufend;			/* End of buffer */
11086*5e7646d2SAndroid Build Coastguard Worker 
11087*5e7646d2SAndroid Build Coastguard Worker 
11088*5e7646d2SAndroid Build Coastguard Worker   strlcpy(buffer, attr->name, bufsize);
11089*5e7646d2SAndroid Build Coastguard Worker   bufptr = buffer + strlen(buffer);
11090*5e7646d2SAndroid Build Coastguard Worker   bufend = buffer + bufsize - 1;
11091*5e7646d2SAndroid Build Coastguard Worker 
11092*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < attr->num_values; i ++)
11093*5e7646d2SAndroid Build Coastguard Worker   {
11094*5e7646d2SAndroid Build Coastguard Worker     if (bufptr >= bufend)
11095*5e7646d2SAndroid Build Coastguard Worker       break;
11096*5e7646d2SAndroid Build Coastguard Worker 
11097*5e7646d2SAndroid Build Coastguard Worker     if (i)
11098*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = ',';
11099*5e7646d2SAndroid Build Coastguard Worker     else
11100*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = '=';
11101*5e7646d2SAndroid Build Coastguard Worker 
11102*5e7646d2SAndroid Build Coastguard Worker     if (bufptr >= bufend)
11103*5e7646d2SAndroid Build Coastguard Worker       break;
11104*5e7646d2SAndroid Build Coastguard Worker 
11105*5e7646d2SAndroid Build Coastguard Worker     *bufptr++ = '\'';
11106*5e7646d2SAndroid Build Coastguard Worker 
11107*5e7646d2SAndroid Build Coastguard Worker     bufptr = url_encode_string(attr->values[i].string.text, bufptr, (size_t)(bufend - bufptr + 1));
11108*5e7646d2SAndroid Build Coastguard Worker 
11109*5e7646d2SAndroid Build Coastguard Worker     if (bufptr >= bufend)
11110*5e7646d2SAndroid Build Coastguard Worker       break;
11111*5e7646d2SAndroid Build Coastguard Worker 
11112*5e7646d2SAndroid Build Coastguard Worker     *bufptr++ = '\'';
11113*5e7646d2SAndroid Build Coastguard Worker   }
11114*5e7646d2SAndroid Build Coastguard Worker 
11115*5e7646d2SAndroid Build Coastguard Worker   *bufptr = '\0';
11116*5e7646d2SAndroid Build Coastguard Worker }
11117*5e7646d2SAndroid Build Coastguard Worker 
11118*5e7646d2SAndroid Build Coastguard Worker 
11119*5e7646d2SAndroid Build Coastguard Worker /*
11120*5e7646d2SAndroid Build Coastguard Worker  * 'url_encode_string()' - URL-encode a string.
11121*5e7646d2SAndroid Build Coastguard Worker  */
11122*5e7646d2SAndroid Build Coastguard Worker 
11123*5e7646d2SAndroid Build Coastguard Worker static char *				/* O - End of string */
url_encode_string(const char * s,char * buffer,size_t bufsize)11124*5e7646d2SAndroid Build Coastguard Worker url_encode_string(const char *s,	/* I - String */
11125*5e7646d2SAndroid Build Coastguard Worker                   char       *buffer,	/* I - String buffer */
11126*5e7646d2SAndroid Build Coastguard Worker 		  size_t     bufsize)	/* I - Size of buffer */
11127*5e7646d2SAndroid Build Coastguard Worker {
11128*5e7646d2SAndroid Build Coastguard Worker   char	*bufptr,			/* Pointer into buffer */
11129*5e7646d2SAndroid Build Coastguard Worker 	*bufend;			/* End of buffer */
11130*5e7646d2SAndroid Build Coastguard Worker   static const char *hex = "0123456789ABCDEF";
11131*5e7646d2SAndroid Build Coastguard Worker 					/* Hex digits */
11132*5e7646d2SAndroid Build Coastguard Worker 
11133*5e7646d2SAndroid Build Coastguard Worker 
11134*5e7646d2SAndroid Build Coastguard Worker   bufptr = buffer;
11135*5e7646d2SAndroid Build Coastguard Worker   bufend = buffer + bufsize - 1;
11136*5e7646d2SAndroid Build Coastguard Worker 
11137*5e7646d2SAndroid Build Coastguard Worker   while (*s && bufptr < bufend)
11138*5e7646d2SAndroid Build Coastguard Worker   {
11139*5e7646d2SAndroid Build Coastguard Worker     if (*s == ' ' || *s == '%' || *s == '+')
11140*5e7646d2SAndroid Build Coastguard Worker     {
11141*5e7646d2SAndroid Build Coastguard Worker       if (bufptr >= (bufend - 2))
11142*5e7646d2SAndroid Build Coastguard Worker 	break;
11143*5e7646d2SAndroid Build Coastguard Worker 
11144*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = '%';
11145*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = hex[(*s >> 4) & 15];
11146*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = hex[*s & 15];
11147*5e7646d2SAndroid Build Coastguard Worker 
11148*5e7646d2SAndroid Build Coastguard Worker       s ++;
11149*5e7646d2SAndroid Build Coastguard Worker     }
11150*5e7646d2SAndroid Build Coastguard Worker     else if (*s == '\'' || *s == '\\')
11151*5e7646d2SAndroid Build Coastguard Worker     {
11152*5e7646d2SAndroid Build Coastguard Worker       if (bufptr >= (bufend - 1))
11153*5e7646d2SAndroid Build Coastguard Worker 	break;
11154*5e7646d2SAndroid Build Coastguard Worker 
11155*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = '\\';
11156*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = *s++;
11157*5e7646d2SAndroid Build Coastguard Worker     }
11158*5e7646d2SAndroid Build Coastguard Worker     else
11159*5e7646d2SAndroid Build Coastguard Worker       *bufptr++ = *s++;
11160*5e7646d2SAndroid Build Coastguard Worker   }
11161*5e7646d2SAndroid Build Coastguard Worker 
11162*5e7646d2SAndroid Build Coastguard Worker   *bufptr = '\0';
11163*5e7646d2SAndroid Build Coastguard Worker 
11164*5e7646d2SAndroid Build Coastguard Worker   return (bufptr);
11165*5e7646d2SAndroid Build Coastguard Worker }
11166*5e7646d2SAndroid Build Coastguard Worker 
11167*5e7646d2SAndroid Build Coastguard Worker 
11168*5e7646d2SAndroid Build Coastguard Worker /*
11169*5e7646d2SAndroid Build Coastguard Worker  * 'user_allowed()' - See if a user is allowed to print to a queue.
11170*5e7646d2SAndroid Build Coastguard Worker  */
11171*5e7646d2SAndroid Build Coastguard Worker 
11172*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 if not allowed, 1 if allowed */
user_allowed(cupsd_printer_t * p,const char * username)11173*5e7646d2SAndroid Build Coastguard Worker user_allowed(cupsd_printer_t *p,	/* I - Printer or class */
11174*5e7646d2SAndroid Build Coastguard Worker              const char      *username)	/* I - Username */
11175*5e7646d2SAndroid Build Coastguard Worker {
11176*5e7646d2SAndroid Build Coastguard Worker   struct passwd	*pw;			/* User password data */
11177*5e7646d2SAndroid Build Coastguard Worker   char		baseuser[256],		/* Base username */
11178*5e7646d2SAndroid Build Coastguard Worker 		*baseptr,		/* Pointer to "@" in base username */
11179*5e7646d2SAndroid Build Coastguard Worker 		*name;			/* Current user name */
11180*5e7646d2SAndroid Build Coastguard Worker 
11181*5e7646d2SAndroid Build Coastguard Worker 
11182*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(p->users) == 0)
11183*5e7646d2SAndroid Build Coastguard Worker     return (1);
11184*5e7646d2SAndroid Build Coastguard Worker 
11185*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(username, "root"))
11186*5e7646d2SAndroid Build Coastguard Worker     return (1);
11187*5e7646d2SAndroid Build Coastguard Worker 
11188*5e7646d2SAndroid Build Coastguard Worker   if (strchr(username, '@'))
11189*5e7646d2SAndroid Build Coastguard Worker   {
11190*5e7646d2SAndroid Build Coastguard Worker    /*
11191*5e7646d2SAndroid Build Coastguard Worker     * Strip @REALM for username check...
11192*5e7646d2SAndroid Build Coastguard Worker     */
11193*5e7646d2SAndroid Build Coastguard Worker 
11194*5e7646d2SAndroid Build Coastguard Worker     strlcpy(baseuser, username, sizeof(baseuser));
11195*5e7646d2SAndroid Build Coastguard Worker 
11196*5e7646d2SAndroid Build Coastguard Worker     if ((baseptr = strchr(baseuser, '@')) != NULL)
11197*5e7646d2SAndroid Build Coastguard Worker       *baseptr = '\0';
11198*5e7646d2SAndroid Build Coastguard Worker 
11199*5e7646d2SAndroid Build Coastguard Worker     username = baseuser;
11200*5e7646d2SAndroid Build Coastguard Worker   }
11201*5e7646d2SAndroid Build Coastguard Worker 
11202*5e7646d2SAndroid Build Coastguard Worker   pw = getpwnam(username);
11203*5e7646d2SAndroid Build Coastguard Worker   endpwent();
11204*5e7646d2SAndroid Build Coastguard Worker 
11205*5e7646d2SAndroid Build Coastguard Worker   for (name = (char *)cupsArrayFirst(p->users);
11206*5e7646d2SAndroid Build Coastguard Worker        name;
11207*5e7646d2SAndroid Build Coastguard Worker        name = (char *)cupsArrayNext(p->users))
11208*5e7646d2SAndroid Build Coastguard Worker   {
11209*5e7646d2SAndroid Build Coastguard Worker     if (name[0] == '@')
11210*5e7646d2SAndroid Build Coastguard Worker     {
11211*5e7646d2SAndroid Build Coastguard Worker      /*
11212*5e7646d2SAndroid Build Coastguard Worker       * Check group membership...
11213*5e7646d2SAndroid Build Coastguard Worker       */
11214*5e7646d2SAndroid Build Coastguard Worker 
11215*5e7646d2SAndroid Build Coastguard Worker       if (cupsdCheckGroup(username, pw, name + 1))
11216*5e7646d2SAndroid Build Coastguard Worker         break;
11217*5e7646d2SAndroid Build Coastguard Worker     }
11218*5e7646d2SAndroid Build Coastguard Worker     else if (name[0] == '#')
11219*5e7646d2SAndroid Build Coastguard Worker     {
11220*5e7646d2SAndroid Build Coastguard Worker      /*
11221*5e7646d2SAndroid Build Coastguard Worker       * Check UUID...
11222*5e7646d2SAndroid Build Coastguard Worker       */
11223*5e7646d2SAndroid Build Coastguard Worker 
11224*5e7646d2SAndroid Build Coastguard Worker       if (cupsdCheckGroup(username, pw, name))
11225*5e7646d2SAndroid Build Coastguard Worker         break;
11226*5e7646d2SAndroid Build Coastguard Worker     }
11227*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(username, name))
11228*5e7646d2SAndroid Build Coastguard Worker       break;
11229*5e7646d2SAndroid Build Coastguard Worker   }
11230*5e7646d2SAndroid Build Coastguard Worker 
11231*5e7646d2SAndroid Build Coastguard Worker   return ((name != NULL) != p->deny_users);
11232*5e7646d2SAndroid Build Coastguard Worker }
11233*5e7646d2SAndroid Build Coastguard Worker 
11234*5e7646d2SAndroid Build Coastguard Worker 
11235*5e7646d2SAndroid Build Coastguard Worker /*
11236*5e7646d2SAndroid Build Coastguard Worker  * 'validate_job()' - Validate printer options and destination.
11237*5e7646d2SAndroid Build Coastguard Worker  */
11238*5e7646d2SAndroid Build Coastguard Worker 
11239*5e7646d2SAndroid Build Coastguard Worker static void
validate_job(cupsd_client_t * con,ipp_attribute_t * uri)11240*5e7646d2SAndroid Build Coastguard Worker validate_job(cupsd_client_t  *con,	/* I - Client connection */
11241*5e7646d2SAndroid Build Coastguard Worker 	     ipp_attribute_t *uri)	/* I - Printer URI */
11242*5e7646d2SAndroid Build Coastguard Worker {
11243*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Policy status */
11244*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
11245*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
11246*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*auth_info;	/* auth-info attribute */
11247*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
11248*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*format,	/* Document-format attribute */
11249*5e7646d2SAndroid Build Coastguard Worker 			*name;		/* Job-name attribute */
11250*5e7646d2SAndroid Build Coastguard Worker   cups_ptype_t		dtype;		/* Destination type (printer/class) */
11251*5e7646d2SAndroid Build Coastguard Worker   char			super[MIME_MAX_SUPER],
11252*5e7646d2SAndroid Build Coastguard Worker 					/* Supertype of file */
11253*5e7646d2SAndroid Build Coastguard Worker 			type[MIME_MAX_TYPE];
11254*5e7646d2SAndroid Build Coastguard Worker 					/* Subtype of file */
11255*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer */
11256*5e7646d2SAndroid Build Coastguard Worker 
11257*5e7646d2SAndroid Build Coastguard Worker 
11258*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con,
11259*5e7646d2SAndroid Build Coastguard Worker                   con->number, uri->values[0].string.text);
11260*5e7646d2SAndroid Build Coastguard Worker 
11261*5e7646d2SAndroid Build Coastguard Worker  /*
11262*5e7646d2SAndroid Build Coastguard Worker   * OK, see if the client is sending the document compressed - CUPS
11263*5e7646d2SAndroid Build Coastguard Worker   * doesn't support compression yet...
11264*5e7646d2SAndroid Build Coastguard Worker   */
11265*5e7646d2SAndroid Build Coastguard Worker 
11266*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "compression",
11267*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_KEYWORD)) != NULL)
11268*5e7646d2SAndroid Build Coastguard Worker   {
11269*5e7646d2SAndroid Build Coastguard Worker     if (strcmp(attr->values[0].string.text, "none")
11270*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LIBZ
11271*5e7646d2SAndroid Build Coastguard Worker         && strcmp(attr->values[0].string.text, "gzip")
11272*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LIBZ */
11273*5e7646d2SAndroid Build Coastguard Worker       )
11274*5e7646d2SAndroid Build Coastguard Worker     {
11275*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_ATTRIBUTES,
11276*5e7646d2SAndroid Build Coastguard Worker                       _("Unsupported 'compression' value \"%s\"."),
11277*5e7646d2SAndroid Build Coastguard Worker         	      attr->values[0].string.text);
11278*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
11279*5e7646d2SAndroid Build Coastguard Worker 	           "compression", NULL, attr->values[0].string.text);
11280*5e7646d2SAndroid Build Coastguard Worker       return;
11281*5e7646d2SAndroid Build Coastguard Worker     }
11282*5e7646d2SAndroid Build Coastguard Worker   }
11283*5e7646d2SAndroid Build Coastguard Worker 
11284*5e7646d2SAndroid Build Coastguard Worker  /*
11285*5e7646d2SAndroid Build Coastguard Worker   * Is it a format we support?
11286*5e7646d2SAndroid Build Coastguard Worker   */
11287*5e7646d2SAndroid Build Coastguard Worker 
11288*5e7646d2SAndroid Build Coastguard Worker   if ((format = ippFindAttribute(con->request, "document-format",
11289*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_MIMETYPE)) != NULL)
11290*5e7646d2SAndroid Build Coastguard Worker   {
11291*5e7646d2SAndroid Build Coastguard Worker     if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]",
11292*5e7646d2SAndroid Build Coastguard Worker                super, type) != 2)
11293*5e7646d2SAndroid Build Coastguard Worker     {
11294*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_BAD_REQUEST,
11295*5e7646d2SAndroid Build Coastguard Worker                       _("Bad 'document-format' value \"%s\"."),
11296*5e7646d2SAndroid Build Coastguard Worker 		      format->values[0].string.text);
11297*5e7646d2SAndroid Build Coastguard Worker       return;
11298*5e7646d2SAndroid Build Coastguard Worker     }
11299*5e7646d2SAndroid Build Coastguard Worker 
11300*5e7646d2SAndroid Build Coastguard Worker     if ((strcmp(super, "application") || strcmp(type, "octet-stream")) &&
11301*5e7646d2SAndroid Build Coastguard Worker 	!mimeType(MimeDatabase, super, type))
11302*5e7646d2SAndroid Build Coastguard Worker     {
11303*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO,
11304*5e7646d2SAndroid Build Coastguard Worker                       "Hint: Do you have the raw file printing rules enabled?");
11305*5e7646d2SAndroid Build Coastguard Worker       send_ipp_status(con, IPP_DOCUMENT_FORMAT,
11306*5e7646d2SAndroid Build Coastguard Worker                       _("Unsupported 'document-format' value \"%s\"."),
11307*5e7646d2SAndroid Build Coastguard Worker 		      format->values[0].string.text);
11308*5e7646d2SAndroid Build Coastguard Worker       ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
11309*5e7646d2SAndroid Build Coastguard Worker                    "document-format", NULL, format->values[0].string.text);
11310*5e7646d2SAndroid Build Coastguard Worker       return;
11311*5e7646d2SAndroid Build Coastguard Worker     }
11312*5e7646d2SAndroid Build Coastguard Worker   }
11313*5e7646d2SAndroid Build Coastguard Worker 
11314*5e7646d2SAndroid Build Coastguard Worker  /*
11315*5e7646d2SAndroid Build Coastguard Worker   * Is the job-hold-until value valid?
11316*5e7646d2SAndroid Build Coastguard Worker   */
11317*5e7646d2SAndroid Build Coastguard Worker 
11318*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL && ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr)))
11319*5e7646d2SAndroid Build Coastguard Worker   {
11320*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value."));
11321*5e7646d2SAndroid Build Coastguard Worker     ippCopyAttribute(con->response, attr, 0);
11322*5e7646d2SAndroid Build Coastguard Worker     return;
11323*5e7646d2SAndroid Build Coastguard Worker   }
11324*5e7646d2SAndroid Build Coastguard Worker 
11325*5e7646d2SAndroid Build Coastguard Worker  /*
11326*5e7646d2SAndroid Build Coastguard Worker   * Is the job-name valid?
11327*5e7646d2SAndroid Build Coastguard Worker   */
11328*5e7646d2SAndroid Build Coastguard Worker 
11329*5e7646d2SAndroid Build Coastguard Worker   if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL)
11330*5e7646d2SAndroid Build Coastguard Worker   {
11331*5e7646d2SAndroid Build Coastguard Worker     if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) ||
11332*5e7646d2SAndroid Build Coastguard Worker         name->num_values != 1 || !ippValidateAttribute(name))
11333*5e7646d2SAndroid Build Coastguard Worker     {
11334*5e7646d2SAndroid Build Coastguard Worker       if (StrictConformance)
11335*5e7646d2SAndroid Build Coastguard Worker       {
11336*5e7646d2SAndroid Build Coastguard Worker 	send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-name' value."));
11337*5e7646d2SAndroid Build Coastguard Worker 	ippCopyAttribute(con->response, name, 0);
11338*5e7646d2SAndroid Build Coastguard Worker 	return;
11339*5e7646d2SAndroid Build Coastguard Worker       }
11340*5e7646d2SAndroid Build Coastguard Worker       else
11341*5e7646d2SAndroid Build Coastguard Worker       {
11342*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_WARN, "Unsupported 'job-name' value, deleting from request.");
11343*5e7646d2SAndroid Build Coastguard Worker         ippDeleteAttribute(con->request, name);
11344*5e7646d2SAndroid Build Coastguard Worker       }
11345*5e7646d2SAndroid Build Coastguard Worker     }
11346*5e7646d2SAndroid Build Coastguard Worker   }
11347*5e7646d2SAndroid Build Coastguard Worker 
11348*5e7646d2SAndroid Build Coastguard Worker  /*
11349*5e7646d2SAndroid Build Coastguard Worker   * Is the destination valid?
11350*5e7646d2SAndroid Build Coastguard Worker   */
11351*5e7646d2SAndroid Build Coastguard Worker 
11352*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
11353*5e7646d2SAndroid Build Coastguard Worker   {
11354*5e7646d2SAndroid Build Coastguard Worker    /*
11355*5e7646d2SAndroid Build Coastguard Worker     * Bad URI...
11356*5e7646d2SAndroid Build Coastguard Worker     */
11357*5e7646d2SAndroid Build Coastguard Worker 
11358*5e7646d2SAndroid Build Coastguard Worker     send_ipp_status(con, IPP_NOT_FOUND,
11359*5e7646d2SAndroid Build Coastguard Worker                     _("The printer or class does not exist."));
11360*5e7646d2SAndroid Build Coastguard Worker     return;
11361*5e7646d2SAndroid Build Coastguard Worker   }
11362*5e7646d2SAndroid Build Coastguard Worker 
11363*5e7646d2SAndroid Build Coastguard Worker  /*
11364*5e7646d2SAndroid Build Coastguard Worker   * Check policy...
11365*5e7646d2SAndroid Build Coastguard Worker   */
11366*5e7646d2SAndroid Build Coastguard Worker 
11367*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
11368*5e7646d2SAndroid Build Coastguard Worker   auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
11369*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
11370*5e7646d2SAndroid Build Coastguard Worker 
11371*5e7646d2SAndroid Build Coastguard Worker   if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
11372*5e7646d2SAndroid Build Coastguard Worker   {
11373*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, status, printer);
11374*5e7646d2SAndroid Build Coastguard Worker     return;
11375*5e7646d2SAndroid Build Coastguard Worker   }
11376*5e7646d2SAndroid Build Coastguard Worker   else if (printer->num_auth_info_required == 1 &&
11377*5e7646d2SAndroid Build Coastguard Worker            !strcmp(printer->auth_info_required[0], "negotiate") &&
11378*5e7646d2SAndroid Build Coastguard Worker            !con->username[0])
11379*5e7646d2SAndroid Build Coastguard Worker   {
11380*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, HTTP_UNAUTHORIZED, printer);
11381*5e7646d2SAndroid Build Coastguard Worker     return;
11382*5e7646d2SAndroid Build Coastguard Worker   }
11383*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
11384*5e7646d2SAndroid Build Coastguard Worker   else if (auth_info && !con->http->tls &&
11385*5e7646d2SAndroid Build Coastguard Worker            !httpAddrLocalhost(con->http->hostaddr))
11386*5e7646d2SAndroid Build Coastguard Worker   {
11387*5e7646d2SAndroid Build Coastguard Worker    /*
11388*5e7646d2SAndroid Build Coastguard Worker     * Require encryption of auth-info over non-local connections...
11389*5e7646d2SAndroid Build Coastguard Worker     */
11390*5e7646d2SAndroid Build Coastguard Worker 
11391*5e7646d2SAndroid Build Coastguard Worker     send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
11392*5e7646d2SAndroid Build Coastguard Worker     return;
11393*5e7646d2SAndroid Build Coastguard Worker   }
11394*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
11395*5e7646d2SAndroid Build Coastguard Worker 
11396*5e7646d2SAndroid Build Coastguard Worker  /*
11397*5e7646d2SAndroid Build Coastguard Worker   * Everything was ok, so return OK status...
11398*5e7646d2SAndroid Build Coastguard Worker   */
11399*5e7646d2SAndroid Build Coastguard Worker 
11400*5e7646d2SAndroid Build Coastguard Worker   con->response->request.status.status_code = IPP_OK;
11401*5e7646d2SAndroid Build Coastguard Worker }
11402*5e7646d2SAndroid Build Coastguard Worker 
11403*5e7646d2SAndroid Build Coastguard Worker 
11404*5e7646d2SAndroid Build Coastguard Worker /*
11405*5e7646d2SAndroid Build Coastguard Worker  * 'validate_name()' - Make sure the printer name only contains valid chars.
11406*5e7646d2SAndroid Build Coastguard Worker  */
11407*5e7646d2SAndroid Build Coastguard Worker 
11408*5e7646d2SAndroid Build Coastguard Worker static int			/* O - 0 if name is no good, 1 if good */
validate_name(const char * name)11409*5e7646d2SAndroid Build Coastguard Worker validate_name(const char *name)	/* I - Name to check */
11410*5e7646d2SAndroid Build Coastguard Worker {
11411*5e7646d2SAndroid Build Coastguard Worker   const char	*ptr;		/* Pointer into name */
11412*5e7646d2SAndroid Build Coastguard Worker 
11413*5e7646d2SAndroid Build Coastguard Worker 
11414*5e7646d2SAndroid Build Coastguard Worker  /*
11415*5e7646d2SAndroid Build Coastguard Worker   * Scan the whole name...
11416*5e7646d2SAndroid Build Coastguard Worker   */
11417*5e7646d2SAndroid Build Coastguard Worker 
11418*5e7646d2SAndroid Build Coastguard Worker   for (ptr = name; *ptr; ptr ++)
11419*5e7646d2SAndroid Build Coastguard Worker     if ((*ptr > 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
11420*5e7646d2SAndroid Build Coastguard Worker       return (0);
11421*5e7646d2SAndroid Build Coastguard Worker 
11422*5e7646d2SAndroid Build Coastguard Worker  /*
11423*5e7646d2SAndroid Build Coastguard Worker   * All the characters are good; validate the length, too...
11424*5e7646d2SAndroid Build Coastguard Worker   */
11425*5e7646d2SAndroid Build Coastguard Worker 
11426*5e7646d2SAndroid Build Coastguard Worker   return ((ptr - name) < 128);
11427*5e7646d2SAndroid Build Coastguard Worker }
11428*5e7646d2SAndroid Build Coastguard Worker 
11429*5e7646d2SAndroid Build Coastguard Worker 
11430*5e7646d2SAndroid Build Coastguard Worker /*
11431*5e7646d2SAndroid Build Coastguard Worker  * 'validate_user()' - Validate the user for the request.
11432*5e7646d2SAndroid Build Coastguard Worker  */
11433*5e7646d2SAndroid Build Coastguard Worker 
11434*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 if permitted, 0 otherwise */
validate_user(cupsd_job_t * job,cupsd_client_t * con,const char * owner,char * username,size_t userlen)11435*5e7646d2SAndroid Build Coastguard Worker validate_user(cupsd_job_t    *job,	/* I - Job */
11436*5e7646d2SAndroid Build Coastguard Worker               cupsd_client_t *con,	/* I - Client connection */
11437*5e7646d2SAndroid Build Coastguard Worker               const char     *owner,	/* I - Owner of job/resource */
11438*5e7646d2SAndroid Build Coastguard Worker               char           *username,	/* O - Authenticated username */
11439*5e7646d2SAndroid Build Coastguard Worker 	      size_t         userlen)	/* I - Length of username */
11440*5e7646d2SAndroid Build Coastguard Worker {
11441*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer for job */
11442*5e7646d2SAndroid Build Coastguard Worker 
11443*5e7646d2SAndroid Build Coastguard Worker 
11444*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=" CUPS_LLFMT ")", job->id, con ? con->number : 0, owner ? owner : "(null)", username, CUPS_LLCAST userlen);
11445*5e7646d2SAndroid Build Coastguard Worker 
11446*5e7646d2SAndroid Build Coastguard Worker  /*
11447*5e7646d2SAndroid Build Coastguard Worker   * Validate input...
11448*5e7646d2SAndroid Build Coastguard Worker   */
11449*5e7646d2SAndroid Build Coastguard Worker 
11450*5e7646d2SAndroid Build Coastguard Worker   if (!con || !owner || !username || userlen <= 0)
11451*5e7646d2SAndroid Build Coastguard Worker     return (0);
11452*5e7646d2SAndroid Build Coastguard Worker 
11453*5e7646d2SAndroid Build Coastguard Worker  /*
11454*5e7646d2SAndroid Build Coastguard Worker   * Get the best authenticated username that is available.
11455*5e7646d2SAndroid Build Coastguard Worker   */
11456*5e7646d2SAndroid Build Coastguard Worker 
11457*5e7646d2SAndroid Build Coastguard Worker   strlcpy(username, get_username(con), userlen);
11458*5e7646d2SAndroid Build Coastguard Worker 
11459*5e7646d2SAndroid Build Coastguard Worker  /*
11460*5e7646d2SAndroid Build Coastguard Worker   * Check the username against the owner...
11461*5e7646d2SAndroid Build Coastguard Worker   */
11462*5e7646d2SAndroid Build Coastguard Worker 
11463*5e7646d2SAndroid Build Coastguard Worker   printer = cupsdFindDest(job->dest);
11464*5e7646d2SAndroid Build Coastguard Worker 
11465*5e7646d2SAndroid Build Coastguard Worker   return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
11466*5e7646d2SAndroid Build Coastguard Worker                            con, owner) == HTTP_OK);
11467*5e7646d2SAndroid Build Coastguard Worker }
11468