]>
Commit | Line | Data |
---|---|---|
e31bfb6e | 1 | /* |
71fe22b7 | 2 | * "$Id: ipp.c,v 1.41 2000/01/04 13:46:09 mike Exp $" |
e31bfb6e | 3 | * |
4 | * IPP routines for the Common UNIX Printing System (CUPS) scheduler. | |
5 | * | |
71fe22b7 | 6 | * Copyright 1997-2000 by Easy Software Products, all rights reserved. |
e31bfb6e | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
e31bfb6e | 18 | * Hollywood, Maryland 20636-3111 USA |
19 | * | |
20 | * Voice: (301) 373-9603 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
cbbfcc63 | 26 | * ProcessIPPRequest() - Process an incoming IPP request... |
27 | * accept_jobs() - Accept print jobs to a printer. | |
28 | * add_class() - Add a class to the system. | |
29 | * add_printer() - Add a printer to the system. | |
30 | * cancel_all_jobs() - Cancel all print jobs. | |
31 | * cancel_job() - Cancel a print job. | |
32 | * copy_attrs() - Copy attributes from one request to another. | |
c7fa9d06 | 33 | * delete_printer() - Remove a printer or class from the system. |
cbbfcc63 | 34 | * get_default() - Get the default destination. |
35 | * get_jobs() - Get a list of jobs for the specified printer. | |
36 | * get_job_attrs() - Get job attributes. | |
37 | * get_printers() - Get a list of printers. | |
38 | * get_printer_attrs() - Get printer attributes. | |
39 | * print_job() - Print a file to a printer or class. | |
40 | * reject_jobs() - Reject print jobs to a printer. | |
41 | * send_ipp_error() - Send an error status back to the IPP client. | |
42 | * start_printer() - Start a printer. | |
43 | * stop_printer() - Stop a printer. | |
cbbfcc63 | 44 | * validate_job() - Validate printer options and destination. |
e31bfb6e | 45 | */ |
46 | ||
47 | /* | |
48 | * Include necessary headers... | |
49 | */ | |
50 | ||
51 | #include "cupsd.h" | |
6bc08d08 | 52 | #include <pwd.h> |
53 | #include <grp.h> | |
e31bfb6e | 54 | |
55 | ||
56 | /* | |
57 | * Local functions... | |
58 | */ | |
59 | ||
f3d580b9 | 60 | static void accept_jobs(client_t *con, ipp_attribute_t *uri); |
c7fa9d06 | 61 | static void add_class(client_t *con, ipp_attribute_t *uri); |
62 | static void add_printer(client_t *con, ipp_attribute_t *uri); | |
f3d580b9 | 63 | static void cancel_all_jobs(client_t *con, ipp_attribute_t *uri); |
1d2c70a6 | 64 | static void cancel_job(client_t *con, ipp_attribute_t *uri); |
d6de4648 | 65 | static void copy_attrs(ipp_t *to, ipp_t *from, ipp_attribute_t *req); |
bd84e0d1 | 66 | static void create_job(client_t *con, ipp_attribute_t *uri); |
c7fa9d06 | 67 | static void delete_printer(client_t *con, ipp_attribute_t *uri); |
1d2c70a6 | 68 | static void get_default(client_t *con); |
bd84e0d1 | 69 | static void get_devices(client_t *con); |
1d2c70a6 | 70 | static void get_jobs(client_t *con, ipp_attribute_t *uri); |
71 | static void get_job_attrs(client_t *con, ipp_attribute_t *uri); | |
bd84e0d1 | 72 | static void get_ppds(client_t *con); |
cbbfcc63 | 73 | static void get_printers(client_t *con, int type); |
1d2c70a6 | 74 | static void get_printer_attrs(client_t *con, ipp_attribute_t *uri); |
bd84e0d1 | 75 | static void hold_job(client_t *con, ipp_attribute_t *uri); |
1d2c70a6 | 76 | static void print_job(client_t *con, ipp_attribute_t *uri); |
f3d580b9 | 77 | static void reject_jobs(client_t *con, ipp_attribute_t *uri); |
bd84e0d1 | 78 | static void restart_job(client_t *con, ipp_attribute_t *uri); |
79 | static void send_document(client_t *con, ipp_attribute_t *uri); | |
e31bfb6e | 80 | static void send_ipp_error(client_t *con, ipp_status_t status); |
3270670b | 81 | static void set_default(client_t *con, ipp_attribute_t *uri); |
f3d580b9 | 82 | static void start_printer(client_t *con, ipp_attribute_t *uri); |
83 | static void stop_printer(client_t *con, ipp_attribute_t *uri); | |
1d2c70a6 | 84 | static void validate_job(client_t *con, ipp_attribute_t *uri); |
e31bfb6e | 85 | |
86 | ||
87 | /* | |
88 | * 'ProcessIPPRequest()' - Process an incoming IPP request... | |
89 | */ | |
90 | ||
91 | void | |
92 | ProcessIPPRequest(client_t *con) /* I - Client connection */ | |
93 | { | |
94 | ipp_tag_t group; /* Current group tag */ | |
95 | ipp_attribute_t *attr; /* Current attribute */ | |
96 | ipp_attribute_t *charset; /* Character set attribute */ | |
97 | ipp_attribute_t *language; /* Language attribute */ | |
98 | ipp_attribute_t *uri; /* Printer URI attribute */ | |
99 | ||
100 | ||
101 | DEBUG_printf(("ProcessIPPRequest(%08x)\n", con)); | |
102 | DEBUG_printf(("ProcessIPPRequest: operation_id = %04x\n", | |
103 | con->request->request.op.operation_id)); | |
104 | ||
105 | /* | |
106 | * First build an empty response message for this request... | |
107 | */ | |
108 | ||
109 | con->response = ippNew(); | |
110 | ||
111 | con->response->request.status.version[0] = 1; | |
112 | con->response->request.status.version[1] = 0; | |
113 | con->response->request.status.request_id = con->request->request.op.request_id; | |
114 | ||
115 | /* | |
116 | * Then validate the request header and required attributes... | |
117 | */ | |
118 | ||
119 | if (con->request->request.any.version[0] != 1) | |
120 | { | |
121 | /* | |
122 | * Return an error, since we only support IPP 1.x. | |
123 | */ | |
124 | ||
125 | send_ipp_error(con, IPP_VERSION_NOT_SUPPORTED); | |
e31bfb6e | 126 | } |
e31bfb6e | 127 | else |
e31bfb6e | 128 | { |
129 | /* | |
27b6a264 | 130 | * Make sure that the attributes are provided in the correct order and |
131 | * don't repeat groups... | |
e31bfb6e | 132 | */ |
133 | ||
27b6a264 | 134 | for (attr = con->request->attrs, group = attr->group_tag; |
135 | attr != NULL; | |
136 | attr = attr->next) | |
137 | if (attr->group_tag < group) | |
138 | { | |
139 | /* | |
140 | * Out of order; return an error... | |
141 | */ | |
142 | ||
bd84e0d1 | 143 | LogMessage(LOG_ERROR, "ProcessIPPRequest: attribute groups are out of order!"); |
27b6a264 | 144 | send_ipp_error(con, IPP_BAD_REQUEST); |
f3d580b9 | 145 | break; |
27b6a264 | 146 | } |
147 | else | |
148 | group = attr->group_tag; | |
f3d580b9 | 149 | |
27b6a264 | 150 | if (attr == NULL) |
151 | { | |
152 | /* | |
153 | * Then make sure that the first three attributes are: | |
154 | * | |
155 | * attributes-charset | |
156 | * attributes-natural-language | |
157 | * printer-uri | |
158 | */ | |
e31bfb6e | 159 | |
27b6a264 | 160 | attr = con->request->attrs; |
161 | if (attr != NULL && strcmp(attr->name, "attributes-charset") == 0 && | |
162 | attr->value_tag == IPP_TAG_CHARSET) | |
163 | charset = attr; | |
164 | else | |
165 | charset = NULL; | |
166 | ||
167 | attr = attr->next; | |
168 | if (attr != NULL && strcmp(attr->name, "attributes-natural-language") == 0 && | |
169 | attr->value_tag == IPP_TAG_LANGUAGE) | |
170 | language = attr; | |
171 | else | |
172 | language = NULL; | |
173 | ||
174 | attr = attr->next; | |
175 | if (attr != NULL && strcmp(attr->name, "printer-uri") == 0 && | |
176 | attr->value_tag == IPP_TAG_URI) | |
177 | uri = attr; | |
178 | else if (attr != NULL && strcmp(attr->name, "job-uri") == 0 && | |
179 | attr->value_tag == IPP_TAG_URI) | |
180 | uri = attr; | |
181 | else | |
182 | uri = NULL; | |
183 | ||
b9e6b836 | 184 | ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
185 | "attributes-charset", NULL, charset->values[0].string.text); | |
186 | ||
187 | ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
188 | "attributes-natural-language", NULL, | |
189 | language->values[0].string.text); | |
190 | ||
27b6a264 | 191 | if (charset == NULL || language == NULL || |
192 | (uri == NULL && con->request->request.op.operation_id < IPP_PRIVATE)) | |
193 | { | |
194 | /* | |
195 | * Return an error, since attributes-charset, | |
196 | * attributes-natural-language, and printer-uri/job-uri are required | |
197 | * for all operations. | |
198 | */ | |
199 | ||
bd84e0d1 | 200 | if (charset == NULL) |
201 | LogMessage(LOG_ERROR, "ProcessIPPRequest: missing attributes-charset attribute!"); | |
202 | ||
203 | if (language == NULL) | |
204 | LogMessage(LOG_ERROR, "ProcessIPPRequest: missing attributes-natural-language attribute!"); | |
205 | ||
206 | if (uri == NULL) | |
207 | LogMessage(LOG_ERROR, "ProcessIPPRequest: missing printer-uri or job-uri attribute!"); | |
208 | ||
27b6a264 | 209 | send_ipp_error(con, IPP_BAD_REQUEST); |
210 | } | |
211 | else | |
212 | { | |
27b6a264 | 213 | /* |
214 | * OK, all the checks pass so far; try processing the operation... | |
215 | */ | |
216 | ||
217 | switch (con->request->request.op.operation_id) | |
218 | { | |
219 | case IPP_PRINT_JOB : | |
220 | print_job(con, uri); | |
221 | break; | |
222 | ||
223 | case IPP_VALIDATE_JOB : | |
224 | validate_job(con, uri); | |
225 | break; | |
226 | ||
bd84e0d1 | 227 | case IPP_CREATE_JOB : |
228 | create_job(con, uri); | |
229 | break; | |
230 | ||
231 | case IPP_SEND_DOCUMENT : | |
232 | send_document(con, uri); | |
233 | break; | |
234 | ||
27b6a264 | 235 | case IPP_CANCEL_JOB : |
236 | cancel_job(con, uri); | |
237 | break; | |
238 | ||
239 | case IPP_GET_JOB_ATTRIBUTES : | |
240 | get_job_attrs(con, uri); | |
241 | break; | |
242 | ||
243 | case IPP_GET_JOBS : | |
244 | get_jobs(con, uri); | |
245 | break; | |
246 | ||
247 | case IPP_GET_PRINTER_ATTRIBUTES : | |
248 | get_printer_attrs(con, uri); | |
249 | break; | |
250 | ||
bd84e0d1 | 251 | case IPP_HOLD_JOB : |
252 | hold_job(con, uri); | |
253 | break; | |
254 | ||
255 | case IPP_RESTART_JOB : | |
256 | restart_job(con, uri); | |
257 | break; | |
258 | ||
27b6a264 | 259 | case IPP_PAUSE_PRINTER : |
260 | stop_printer(con, uri); | |
261 | break; | |
262 | ||
263 | case IPP_RESUME_PRINTER : | |
264 | start_printer(con, uri); | |
265 | break; | |
266 | ||
267 | case IPP_PURGE_JOBS : | |
268 | cancel_all_jobs(con, uri); | |
269 | break; | |
270 | ||
271 | case CUPS_GET_DEFAULT : | |
272 | get_default(con); | |
273 | break; | |
274 | ||
275 | case CUPS_GET_PRINTERS : | |
cbbfcc63 | 276 | get_printers(con, 0); |
277 | break; | |
278 | ||
279 | case CUPS_GET_CLASSES : | |
280 | get_printers(con, CUPS_PRINTER_CLASS); | |
27b6a264 | 281 | break; |
e31bfb6e | 282 | |
27b6a264 | 283 | case CUPS_ADD_PRINTER : |
c7fa9d06 | 284 | add_printer(con, uri); |
27b6a264 | 285 | break; |
e31bfb6e | 286 | |
27b6a264 | 287 | case CUPS_DELETE_PRINTER : |
c7fa9d06 | 288 | delete_printer(con, uri); |
27b6a264 | 289 | break; |
e31bfb6e | 290 | |
27b6a264 | 291 | case CUPS_ADD_CLASS : |
c7fa9d06 | 292 | add_class(con, uri); |
27b6a264 | 293 | break; |
e31bfb6e | 294 | |
27b6a264 | 295 | case CUPS_DELETE_CLASS : |
c7fa9d06 | 296 | delete_printer(con, uri); |
27b6a264 | 297 | break; |
e31bfb6e | 298 | |
27b6a264 | 299 | case CUPS_ACCEPT_JOBS : |
300 | accept_jobs(con, uri); | |
301 | break; | |
f3d580b9 | 302 | |
27b6a264 | 303 | case CUPS_REJECT_JOBS : |
304 | reject_jobs(con, uri); | |
305 | break; | |
f3d580b9 | 306 | |
3270670b | 307 | case CUPS_SET_DEFAULT : |
308 | set_default(con, uri); | |
309 | break; | |
310 | ||
bd84e0d1 | 311 | case CUPS_GET_DEVICES : |
312 | get_devices(con); | |
313 | break; | |
314 | ||
315 | case CUPS_GET_PPDS : | |
316 | get_ppds(con); | |
317 | break; | |
318 | ||
27b6a264 | 319 | default : |
320 | send_ipp_error(con, IPP_OPERATION_NOT_SUPPORTED); | |
321 | } | |
322 | } | |
323 | } | |
e31bfb6e | 324 | } |
325 | ||
1d2c70a6 | 326 | SendHeader(con, HTTP_OK, "application/ipp"); |
f937f199 | 327 | |
328 | con->http.data_encoding = HTTP_ENCODE_LENGTH; | |
329 | con->http.data_remaining = ippLength(con->response); | |
330 | ||
331 | httpPrintf(HTTP(con), "Content-Length: %d\r\n\r\n", | |
332 | con->http.data_remaining); | |
1d2c70a6 | 333 | |
e31bfb6e | 334 | FD_SET(con->http.fd, &OutputSet); |
335 | } | |
336 | ||
337 | ||
f3d580b9 | 338 | /* |
339 | * 'accept_jobs()' - Accept print jobs to a printer. | |
340 | */ | |
341 | ||
342 | static void | |
343 | accept_jobs(client_t *con, /* I - Client connection */ | |
344 | ipp_attribute_t *uri) /* I - Printer or class URI */ | |
345 | { | |
346 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
347 | char method[HTTP_MAX_URI], | |
348 | /* Method portion of URI */ | |
349 | username[HTTP_MAX_URI], | |
350 | /* Username portion of URI */ | |
351 | host[HTTP_MAX_URI], | |
352 | /* Host portion of URI */ | |
353 | resource[HTTP_MAX_URI]; | |
354 | /* Resource portion of URI */ | |
355 | int port; /* Port portion of URI */ | |
1049abbe | 356 | const char *name; /* Printer name */ |
f3d580b9 | 357 | printer_t *printer; /* Printer data */ |
358 | ||
359 | ||
360 | DEBUG_printf(("accept_jobs(%08x, %08x)\n", con, uri)); | |
361 | ||
362 | /* | |
363 | * Was this operation called from the correct URI? | |
364 | */ | |
365 | ||
366 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
367 | { | |
1917e0e9 | 368 | LogMessage(LOG_ERROR, "accept_jobs: admin request on bad resource \'%s\'!", |
1124e9ec | 369 | con->uri); |
f3d580b9 | 370 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
371 | return; | |
372 | } | |
373 | ||
374 | /* | |
375 | * Is the destination valid? | |
376 | */ | |
377 | ||
378 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
379 | ||
1049abbe | 380 | if ((name = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 381 | { |
382 | /* | |
383 | * Bad URI... | |
384 | */ | |
385 | ||
1917e0e9 | 386 | LogMessage(LOG_ERROR, "accept_jobs: resource name \'%s\' no good!", resource); |
f3d580b9 | 387 | send_ipp_error(con, IPP_NOT_FOUND); |
388 | return; | |
389 | } | |
390 | ||
391 | /* | |
392 | * Accept jobs sent to the printer... | |
393 | */ | |
394 | ||
395 | printer = FindPrinter(name); | |
396 | printer->accepting = 1; | |
397 | printer->state_message[0] = '\0'; | |
398 | ||
cc0561c6 | 399 | LogMessage(LOG_INFO, "Printer \'%s\' now accepting jobs (\'%s\').", name, |
400 | con->username); | |
401 | ||
f3d580b9 | 402 | /* |
403 | * Everything was ok, so return OK status... | |
404 | */ | |
405 | ||
406 | con->response->request.status.status_code = IPP_OK; | |
407 | } | |
408 | ||
409 | ||
1d2c70a6 | 410 | /* |
411 | * 'add_class()' - Add a class to the system. | |
412 | */ | |
413 | ||
e31bfb6e | 414 | static void |
c7fa9d06 | 415 | add_class(client_t *con, /* I - Client connection */ |
416 | ipp_attribute_t *uri) /* I - URI of class */ | |
e31bfb6e | 417 | { |
3270670b | 418 | int i; /* Looping var */ |
419 | char method[HTTP_MAX_URI], | |
420 | /* Method portion of URI */ | |
421 | username[HTTP_MAX_URI], | |
422 | /* Username portion of URI */ | |
423 | host[HTTP_MAX_URI], | |
424 | /* Host portion of URI */ | |
425 | resource[HTTP_MAX_URI]; | |
426 | /* Resource portion of URI */ | |
427 | int port; /* Port portion of URI */ | |
428 | printer_t *pclass; /* Class */ | |
429 | cups_ptype_t dtype; /* Destination type */ | |
1049abbe | 430 | const char *dest; /* Printer or class name */ |
3270670b | 431 | ipp_attribute_t *attr; /* Printer attribute */ |
432 | ||
433 | ||
f3d580b9 | 434 | /* |
435 | * Was this operation called from the correct URI? | |
436 | */ | |
437 | ||
438 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
439 | { | |
1917e0e9 | 440 | LogMessage(LOG_ERROR, "add_class: admin request on bad resource \'%s\'!", |
1124e9ec | 441 | con->uri); |
f3d580b9 | 442 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
443 | return; | |
444 | } | |
445 | ||
3270670b | 446 | DEBUG_printf(("add_class(%08x, %08x)\n", con, uri)); |
447 | ||
448 | /* | |
449 | * Do we have a valid URI? | |
450 | */ | |
451 | ||
452 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
453 | ||
454 | if (strncmp(resource, "/classes/", 9) != 0) | |
455 | { | |
456 | /* | |
457 | * No, return an error... | |
458 | */ | |
459 | ||
460 | send_ipp_error(con, IPP_BAD_REQUEST); | |
461 | return; | |
462 | } | |
463 | ||
464 | /* | |
465 | * See if the class already exists; if not, create a new class... | |
466 | */ | |
467 | ||
468 | if ((pclass = FindClass(resource + 9)) == NULL) | |
4621b86f | 469 | { |
470 | /* | |
471 | * Class doesn't exist; see if we have a printer of the same name... | |
472 | */ | |
473 | ||
e29fa28a | 474 | if ((pclass = FindPrinter(resource + 9)) != NULL && |
475 | !(pclass->type & CUPS_PRINTER_REMOTE)) | |
4621b86f | 476 | { |
477 | /* | |
478 | * Yes, return an error... | |
479 | */ | |
480 | ||
481 | send_ipp_error(con, IPP_NOT_POSSIBLE); | |
482 | return; | |
483 | } | |
4621b86f | 484 | |
e29fa28a | 485 | /* |
486 | * If we found a printer but didn't error out, then rename the printer to | |
487 | * printer@host... | |
488 | */ | |
489 | ||
490 | if (pclass != NULL) | |
491 | { | |
492 | strcat(pclass->name, "@"); | |
493 | strcat(pclass->name, pclass->hostname); | |
494 | SetPrinterAttrs(pclass); | |
495 | SortPrinters(); | |
4621b86f | 496 | } |
e29fa28a | 497 | |
498 | /* | |
499 | * No, add the pclass... | |
500 | */ | |
501 | ||
502 | pclass = AddClass(resource + 9); | |
4621b86f | 503 | } |
504 | else if (pclass->type & CUPS_PRINTER_REMOTE) | |
505 | { | |
506 | /* | |
507 | * We found a remote class; rename it and then add the pclass. | |
508 | */ | |
509 | ||
510 | strcat(pclass->name, "@"); | |
511 | strcat(pclass->name, pclass->hostname); | |
512 | SetPrinterAttrs(pclass); | |
513 | SortPrinters(); | |
514 | ||
3270670b | 515 | pclass = AddClass(resource + 9); |
4621b86f | 516 | } |
3270670b | 517 | |
518 | /* | |
519 | * Look for attributes and copy them over as needed... | |
520 | */ | |
521 | ||
522 | if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) | |
970017a4 | 523 | { |
524 | strncpy(pclass->location, attr->values[0].string.text, sizeof(pclass->location) - 1); | |
525 | pclass->location[sizeof(pclass->location) - 1] = '\0'; | |
526 | } | |
527 | ||
3270670b | 528 | if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) |
970017a4 | 529 | { |
530 | strncpy(pclass->info, attr->values[0].string.text, sizeof(pclass->info) - 1); | |
531 | pclass->info[sizeof(pclass->info) - 1] = '\0'; | |
532 | } | |
533 | ||
3270670b | 534 | if ((attr = ippFindAttribute(con->request, "printer-more-info", IPP_TAG_URI)) != NULL) |
970017a4 | 535 | { |
536 | strncpy(pclass->more_info, attr->values[0].string.text, sizeof(pclass->more_info) - 1); | |
537 | pclass->more_info[sizeof(pclass->more_info) - 1] = '\0'; | |
538 | } | |
539 | ||
4621b86f | 540 | if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL) |
541 | { | |
542 | LogMessage(LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", | |
543 | pclass->name, attr->values[0].boolean, pclass->accepting); | |
544 | ||
545 | pclass->accepting = attr->values[0].boolean; | |
546 | } | |
547 | if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL) | |
548 | { | |
549 | LogMessage(LOG_INFO, "Setting %s printer-state to %d (was %d.)", pclass->name, | |
550 | attr->values[0].integer, pclass->state); | |
551 | ||
552 | if (pclass->state == IPP_PRINTER_STOPPED && | |
553 | attr->values[0].integer != IPP_PRINTER_STOPPED) | |
554 | pclass->state = IPP_PRINTER_IDLE; | |
555 | else if (pclass->state != IPP_PRINTER_STOPPED && | |
556 | attr->values[0].integer == IPP_PRINTER_STOPPED) | |
557 | { | |
558 | if (pclass->state == IPP_PRINTER_PROCESSING) | |
559 | StopJob(((job_t *)pclass->job)->id); | |
560 | ||
561 | pclass->state = IPP_PRINTER_STOPPED; | |
562 | } | |
563 | ||
564 | pclass->browse_time = 0; | |
565 | } | |
566 | if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL) | |
567 | { | |
568 | strncpy(pclass->state_message, attr->values[0].string.text, | |
569 | sizeof(pclass->state_message) - 1); | |
570 | pclass->state_message[sizeof(pclass->state_message) - 1] = '\0'; | |
571 | } | |
3270670b | 572 | |
573 | if ((attr = ippFindAttribute(con->request, "member-uris", IPP_TAG_URI)) != NULL) | |
574 | { | |
575 | /* | |
576 | * Clear the printer array as needed... | |
577 | */ | |
578 | ||
579 | if (pclass->num_printers > 0) | |
580 | { | |
581 | free(pclass->printers); | |
582 | pclass->num_printers = 0; | |
583 | } | |
584 | ||
585 | /* | |
586 | * Add each printer or class that is listed... | |
587 | */ | |
588 | ||
589 | for (i = 0; i < attr->num_values; i ++) | |
590 | { | |
591 | /* | |
592 | * Search for the printer or class URI... | |
593 | */ | |
594 | ||
595 | httpSeparate(attr->values[i].string.text, method, username, host, | |
596 | &port, resource); | |
597 | ||
1049abbe | 598 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
3270670b | 599 | { |
600 | /* | |
601 | * Bad URI... | |
602 | */ | |
603 | ||
1917e0e9 | 604 | LogMessage(LOG_ERROR, "add_class: resource name \'%s\' no good!", resource); |
3270670b | 605 | send_ipp_error(con, IPP_NOT_FOUND); |
606 | return; | |
607 | } | |
608 | ||
609 | /* | |
610 | * Add it to the class... | |
611 | */ | |
612 | ||
613 | if (dtype == CUPS_PRINTER_CLASS) | |
614 | AddPrinterToClass(pclass, FindClass(dest)); | |
615 | else | |
616 | AddPrinterToClass(pclass, FindPrinter(dest)); | |
617 | } | |
618 | } | |
619 | ||
3270670b | 620 | /* |
621 | * Update the printer class attributes and return... | |
622 | */ | |
623 | ||
624 | SetPrinterAttrs(pclass); | |
cc0561c6 | 625 | SaveAllClasses(); |
47afc1d2 | 626 | CheckJobs(); |
cc0561c6 | 627 | |
628 | LogMessage(LOG_INFO, "New class \'%s\' added by \'%s\'.", pclass->name, | |
629 | con->username); | |
3270670b | 630 | |
631 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 632 | } |
633 | ||
634 | ||
1d2c70a6 | 635 | /* |
636 | * 'add_printer()' - Add a printer to the system. | |
637 | */ | |
638 | ||
e31bfb6e | 639 | static void |
3270670b | 640 | add_printer(client_t *con, /* I - Client connection */ |
641 | ipp_attribute_t *uri) /* I - URI of printer */ | |
e31bfb6e | 642 | { |
c7fa9d06 | 643 | char method[HTTP_MAX_URI], |
644 | /* Method portion of URI */ | |
645 | username[HTTP_MAX_URI], | |
646 | /* Username portion of URI */ | |
647 | host[HTTP_MAX_URI], | |
648 | /* Host portion of URI */ | |
649 | resource[HTTP_MAX_URI]; | |
650 | /* Resource portion of URI */ | |
651 | int port; /* Port portion of URI */ | |
652 | printer_t *printer; /* Printer/class */ | |
653 | ipp_attribute_t *attr; /* Printer attribute */ | |
654 | FILE *fp; /* Script/PPD file */ | |
655 | char line[1024]; /* Line from file... */ | |
656 | char filename[1024]; /* Script/PPD file */ | |
657 | ||
658 | ||
f3d580b9 | 659 | /* |
660 | * Was this operation called from the correct URI? | |
661 | */ | |
662 | ||
663 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
664 | { | |
1917e0e9 | 665 | LogMessage(LOG_ERROR, "add_printer: admin request on bad resource \'%s\'!", |
1124e9ec | 666 | con->uri); |
f3d580b9 | 667 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
668 | return; | |
669 | } | |
670 | ||
3270670b | 671 | DEBUG_printf(("add_printer(%08x, %08x)\n", con, uri)); |
c7fa9d06 | 672 | |
673 | /* | |
674 | * Do we have a valid URI? | |
675 | */ | |
676 | ||
677 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
678 | ||
679 | if (strncmp(resource, "/printers/", 10) != 0) | |
680 | { | |
681 | /* | |
682 | * No, return an error... | |
683 | */ | |
684 | ||
685 | send_ipp_error(con, IPP_BAD_REQUEST); | |
686 | return; | |
687 | } | |
688 | ||
689 | /* | |
690 | * See if the printer already exists; if not, create a new printer... | |
691 | */ | |
692 | ||
693 | if ((printer = FindPrinter(resource + 10)) == NULL) | |
4621b86f | 694 | { |
695 | /* | |
696 | * Printer doesn't exist; see if we have a class of the same name... | |
697 | */ | |
698 | ||
e29fa28a | 699 | if ((printer = FindClass(resource + 10)) != NULL && |
700 | !(printer->type & CUPS_PRINTER_REMOTE)) | |
4621b86f | 701 | { |
702 | /* | |
703 | * Yes, return an error... | |
704 | */ | |
705 | ||
706 | send_ipp_error(con, IPP_NOT_POSSIBLE); | |
707 | return; | |
708 | } | |
4621b86f | 709 | |
e29fa28a | 710 | /* |
711 | * If we found a class but didn't error out, then rename the class to | |
712 | * class@host... | |
713 | */ | |
714 | ||
715 | if (printer != NULL) | |
716 | { | |
717 | strcat(printer->name, "@"); | |
718 | strcat(printer->name, printer->hostname); | |
719 | SetPrinterAttrs(printer); | |
720 | SortPrinters(); | |
4621b86f | 721 | } |
e29fa28a | 722 | |
723 | /* | |
724 | * No, add the printer... | |
725 | */ | |
726 | ||
727 | printer = AddPrinter(resource + 10); | |
4621b86f | 728 | } |
729 | else if (printer->type & CUPS_PRINTER_REMOTE) | |
730 | { | |
731 | /* | |
732 | * We found a remote printer; rename it and then add the printer. | |
733 | */ | |
734 | ||
735 | strcat(printer->name, "@"); | |
736 | strcat(printer->name, printer->hostname); | |
737 | SetPrinterAttrs(printer); | |
738 | SortPrinters(); | |
739 | ||
c7fa9d06 | 740 | printer = AddPrinter(resource + 10); |
4621b86f | 741 | } |
c7fa9d06 | 742 | |
743 | /* | |
744 | * Look for attributes and copy them over as needed... | |
745 | */ | |
746 | ||
747 | if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) | |
970017a4 | 748 | { |
749 | strncpy(printer->location, attr->values[0].string.text, sizeof(printer->location) - 1); | |
750 | printer->location[sizeof(printer->location) - 1] = '\0'; | |
751 | } | |
752 | ||
c7fa9d06 | 753 | if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) |
970017a4 | 754 | { |
755 | strncpy(printer->info, attr->values[0].string.text, sizeof(printer->info) - 1); | |
756 | printer->info[sizeof(printer->info) - 1] = '\0'; | |
757 | } | |
758 | ||
c7fa9d06 | 759 | if ((attr = ippFindAttribute(con->request, "printer-more-info", IPP_TAG_URI)) != NULL) |
970017a4 | 760 | { |
761 | strncpy(printer->more_info, attr->values[0].string.text, sizeof(printer->more_info) - 1); | |
762 | printer->more_info[sizeof(printer->more_info) - 1] = '\0'; | |
763 | } | |
764 | ||
c7fa9d06 | 765 | if ((attr = ippFindAttribute(con->request, "device-uri", IPP_TAG_URI)) != NULL) |
997edb40 | 766 | { |
767 | LogMessage(LOG_INFO, "Setting %s device-uri to \"%s\" (was \"%s\".)", | |
768 | printer->name, attr->values[0].string.text, printer->device_uri); | |
769 | ||
970017a4 | 770 | strncpy(printer->device_uri, attr->values[0].string.text, |
771 | sizeof(printer->device_uri) - 1); | |
772 | printer->device_uri[sizeof(printer->device_uri) - 1] = '\0'; | |
997edb40 | 773 | } |
970017a4 | 774 | |
251c0599 | 775 | if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL) |
997edb40 | 776 | { |
777 | LogMessage(LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", | |
778 | printer->name, attr->values[0].boolean, printer->accepting); | |
779 | ||
251c0599 | 780 | printer->accepting = attr->values[0].boolean; |
997edb40 | 781 | } |
251c0599 | 782 | if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL) |
783 | { | |
997edb40 | 784 | LogMessage(LOG_INFO, "Setting %s printer-state to %d (was %d.)", printer->name, |
785 | attr->values[0].integer, printer->state); | |
786 | ||
8f137344 | 787 | if (printer->state == IPP_PRINTER_STOPPED && |
788 | attr->values[0].integer != IPP_PRINTER_STOPPED) | |
789 | printer->state = IPP_PRINTER_IDLE; | |
790 | else if (printer->state != IPP_PRINTER_STOPPED && | |
791 | attr->values[0].integer == IPP_PRINTER_STOPPED) | |
792 | { | |
793 | if (printer->state == IPP_PRINTER_PROCESSING) | |
794 | StopJob(((job_t *)printer->job)->id); | |
795 | ||
796 | printer->state = IPP_PRINTER_STOPPED; | |
797 | } | |
798 | ||
251c0599 | 799 | printer->browse_time = 0; |
800 | } | |
801 | if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL) | |
802 | { | |
803 | strncpy(printer->state_message, attr->values[0].string.text, | |
804 | sizeof(printer->state_message) - 1); | |
805 | printer->state_message[sizeof(printer->state_message) - 1] = '\0'; | |
806 | } | |
c7fa9d06 | 807 | |
808 | /* | |
809 | * See if we have all required attributes... | |
810 | */ | |
811 | ||
812 | if (printer->device_uri[0] == '\0') | |
251c0599 | 813 | strcpy(printer->device_uri, "file:/dev/null"); |
c7fa9d06 | 814 | |
815 | /* | |
816 | * See if we have an interface script or PPD file attached to the request... | |
817 | */ | |
818 | ||
3270670b | 819 | if (con->filename[0] && |
820 | (fp = fopen(con->filename, "r")) != NULL) | |
c7fa9d06 | 821 | { |
822 | /* | |
3270670b | 823 | * Yes; get the first line from it... |
c7fa9d06 | 824 | */ |
825 | ||
c7fa9d06 | 826 | line[0] = '\0'; |
827 | fgets(line, sizeof(line), fp); | |
828 | fclose(fp); | |
829 | ||
830 | /* | |
831 | * Then see what kind of file it is... | |
832 | */ | |
833 | ||
834 | sprintf(filename, "%s/interfaces/%s", ServerRoot, printer->name); | |
835 | ||
836 | if (strncmp(line, "*PPD-Adobe", 10) == 0) | |
837 | { | |
838 | /* | |
839 | * The new file is a PPD file, so remove any old interface script | |
840 | * that might be lying around... | |
841 | */ | |
842 | ||
843 | unlink(filename); | |
844 | } | |
845 | else | |
846 | { | |
847 | /* | |
848 | * This must be an interface script, so move the file over to the | |
849 | * interfaces directory and make it executable... | |
850 | */ | |
851 | ||
3b41df31 | 852 | if (rename(con->filename, filename)) |
853 | { | |
854 | LogMessage(LOG_ERROR, "add_printer: Unable to rename interface script - %s!", | |
855 | strerror(errno)); | |
1b918e3a | 856 | send_ipp_error(con, IPP_INTERNAL_ERROR); |
3b41df31 | 857 | return; |
858 | } | |
859 | else | |
860 | chmod(filename, 0755); | |
c7fa9d06 | 861 | } |
862 | ||
863 | sprintf(filename, "%s/ppd/%s.ppd", ServerRoot, printer->name); | |
864 | ||
865 | if (strncmp(line, "*PPD-Adobe", 10) == 0) | |
866 | { | |
867 | /* | |
868 | * The new file is a PPD file, so move the file over to the | |
869 | * ppd directory and make it readable by all... | |
870 | */ | |
871 | ||
3b41df31 | 872 | if (rename(con->filename, filename)) |
873 | { | |
874 | LogMessage(LOG_ERROR, "add_printer: Unable to rename PPD file - %s!", | |
875 | strerror(errno)); | |
1b918e3a | 876 | send_ipp_error(con, IPP_INTERNAL_ERROR); |
3b41df31 | 877 | return; |
878 | } | |
879 | else | |
880 | chmod(filename, 0644); | |
c7fa9d06 | 881 | } |
882 | else | |
883 | { | |
884 | /* | |
885 | * This must be an interface script, so remove any old PPD file that | |
886 | * may be lying around... | |
887 | */ | |
888 | ||
889 | unlink(filename); | |
890 | } | |
891 | } | |
892 | ||
4621b86f | 893 | /* |
894 | * Make this printer the default if there is none... | |
895 | */ | |
896 | ||
897 | if (DefaultPrinter == NULL) | |
898 | DefaultPrinter = printer; | |
899 | ||
c7fa9d06 | 900 | /* |
901 | * Update the printer attributes and return... | |
902 | */ | |
903 | ||
3270670b | 904 | SetPrinterAttrs(printer); |
cc0561c6 | 905 | SaveAllPrinters(); |
ccd04319 | 906 | |
907 | if (printer->job != NULL) | |
908 | { | |
909 | /* | |
910 | * Stop the current job and then restart it below... | |
911 | */ | |
912 | ||
913 | StopJob(((job_t *)printer->job)->id); | |
914 | } | |
915 | ||
47afc1d2 | 916 | CheckJobs(); |
cc0561c6 | 917 | |
918 | LogMessage(LOG_INFO, "New printer \'%s\' added by \'%s\'.", printer->name, | |
919 | con->username); | |
c7fa9d06 | 920 | |
921 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 922 | } |
923 | ||
924 | ||
f3d580b9 | 925 | /* |
926 | * 'cancel_all_jobs()' - Cancel all print jobs. | |
927 | */ | |
928 | ||
929 | static void | |
930 | cancel_all_jobs(client_t *con, /* I - Client connection */ | |
931 | ipp_attribute_t *uri) /* I - Job or Printer URI */ | |
932 | { | |
933 | ipp_attribute_t *attr; /* Current attribute */ | |
1049abbe | 934 | const char *dest; /* Destination */ |
f3d580b9 | 935 | cups_ptype_t dtype; /* Destination type */ |
936 | char method[HTTP_MAX_URI], | |
937 | /* Method portion of URI */ | |
938 | username[HTTP_MAX_URI], | |
939 | /* Username portion of URI */ | |
940 | host[HTTP_MAX_URI], | |
941 | /* Host portion of URI */ | |
942 | resource[HTTP_MAX_URI]; | |
943 | /* Resource portion of URI */ | |
944 | int port; /* Port portion of URI */ | |
945 | ||
946 | ||
947 | DEBUG_printf(("cancel_all_jobs(%08x, %08x)\n", con, uri)); | |
948 | ||
949 | /* | |
950 | * Was this operation called from the correct URI? | |
951 | */ | |
952 | ||
953 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
954 | { | |
1917e0e9 | 955 | LogMessage(LOG_ERROR, "cancel_all_jobs: admin request on bad resource \'%s\'!", |
1124e9ec | 956 | con->uri); |
f3d580b9 | 957 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
958 | return; | |
959 | } | |
960 | ||
961 | /* | |
962 | * See if we have a printer URI... | |
963 | */ | |
964 | ||
965 | if (strcmp(uri->name, "printer-uri") != 0) | |
966 | { | |
bd84e0d1 | 967 | LogMessage(LOG_ERROR, "cancel_all_jobs: bad %s attribute \'%s\'!", |
968 | uri->name, uri->values[0].string.text); | |
f3d580b9 | 969 | send_ipp_error(con, IPP_BAD_REQUEST); |
970 | return; | |
971 | } | |
972 | ||
973 | /* | |
974 | * And if the destination is valid... | |
975 | */ | |
976 | ||
977 | httpSeparate(uri->values[0].string.text, method, username, host, &port, | |
978 | resource); | |
979 | ||
1049abbe | 980 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 981 | { |
982 | /* | |
983 | * Bad URI... | |
984 | */ | |
985 | ||
1917e0e9 | 986 | LogMessage(LOG_ERROR, "cancel_all_jobs: resource name \'%s\' no good!", resource); |
f3d580b9 | 987 | send_ipp_error(con, IPP_NOT_FOUND); |
988 | return; | |
989 | } | |
990 | ||
991 | /* | |
992 | * Cancel all of the jobs and return... | |
993 | */ | |
994 | ||
995 | CancelJobs(dest); | |
cc0561c6 | 996 | LogMessage(LOG_INFO, "All jobs on \'%s\' were cancelled by \'%s\'.", dest, |
997 | con->username); | |
f3d580b9 | 998 | |
999 | con->response->request.status.status_code = IPP_OK; | |
1000 | } | |
1001 | ||
1002 | ||
1d2c70a6 | 1003 | /* |
1004 | * 'cancel_job()' - Cancel a print job. | |
1005 | */ | |
1006 | ||
e31bfb6e | 1007 | static void |
1d2c70a6 | 1008 | cancel_job(client_t *con, /* I - Client connection */ |
1009 | ipp_attribute_t *uri) /* I - Job or Printer URI */ | |
e31bfb6e | 1010 | { |
6bc08d08 | 1011 | int i; /* Looping var */ |
1d2c70a6 | 1012 | ipp_attribute_t *attr; /* Current attribute */ |
1013 | int jobid; /* Job ID */ | |
1014 | char method[HTTP_MAX_URI], | |
1015 | /* Method portion of URI */ | |
1016 | username[HTTP_MAX_URI], | |
1017 | /* Username portion of URI */ | |
1018 | host[HTTP_MAX_URI], | |
1019 | /* Host portion of URI */ | |
1020 | resource[HTTP_MAX_URI]; | |
1021 | /* Resource portion of URI */ | |
1022 | int port; /* Port portion of URI */ | |
3b41df31 | 1023 | job_t *job; /* Job information */ |
6bc08d08 | 1024 | struct passwd *user; /* User info */ |
1025 | struct group *group; /* System group info */ | |
1d2c70a6 | 1026 | |
1027 | ||
1028 | DEBUG_printf(("cancel_job(%08x, %08x)\n", con, uri)); | |
1029 | ||
2aeb2b1d | 1030 | /* |
1031 | * Verify that the POST operation was done to a valid URI. | |
1032 | */ | |
1033 | ||
1034 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
1124e9ec | 1035 | strncmp(con->uri, "/jobs/", 5) != 0 && |
2aeb2b1d | 1036 | strncmp(con->uri, "/printers/", 10) != 0) |
1037 | { | |
1038 | LogMessage(LOG_ERROR, "cancel_job: cancel request on bad resource \'%s\'!", | |
1124e9ec | 1039 | con->uri); |
2aeb2b1d | 1040 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
1041 | return; | |
1042 | } | |
1043 | ||
1d2c70a6 | 1044 | /* |
1045 | * See if we have a job URI or a printer URI... | |
1046 | */ | |
1047 | ||
1048 | if (strcmp(uri->name, "printer-uri") == 0) | |
1049 | { | |
1050 | /* | |
1051 | * Got a printer URI; see if we also have a job-id attribute... | |
1052 | */ | |
1053 | ||
c0341b41 | 1054 | if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) |
1d2c70a6 | 1055 | { |
bd84e0d1 | 1056 | LogMessage(LOG_ERROR, "cancel_job: got a printer-uri attribute but no job-id!"); |
1d2c70a6 | 1057 | send_ipp_error(con, IPP_BAD_REQUEST); |
1058 | return; | |
1059 | } | |
1060 | ||
1061 | jobid = attr->values[0].integer; | |
1062 | } | |
1063 | else | |
1064 | { | |
1065 | /* | |
1066 | * Got a job URI; parse it to get the job ID... | |
1067 | */ | |
1068 | ||
c0341b41 | 1069 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1d2c70a6 | 1070 | |
1071 | if (strncmp(resource, "/jobs/", 6) != 0) | |
1072 | { | |
1073 | /* | |
1074 | * Not a valid URI! | |
1075 | */ | |
1076 | ||
bd84e0d1 | 1077 | LogMessage(LOG_ERROR, "cancel_job: bad job-uri attribute \'%s\'!", |
1078 | uri->values[0].string.text); | |
1d2c70a6 | 1079 | send_ipp_error(con, IPP_BAD_REQUEST); |
1080 | return; | |
1081 | } | |
1082 | ||
1083 | jobid = atoi(resource + 6); | |
1084 | } | |
1085 | ||
1086 | /* | |
1087 | * See if the job exists... | |
1088 | */ | |
1089 | ||
3b41df31 | 1090 | if ((job = FindJob(jobid)) == NULL) |
1d2c70a6 | 1091 | { |
1092 | /* | |
1093 | * Nope - return a "not found" error... | |
1094 | */ | |
1095 | ||
3b41df31 | 1096 | LogMessage(LOG_ERROR, "cancel_job: job #%d doesn't exist!", jobid); |
1d2c70a6 | 1097 | send_ipp_error(con, IPP_NOT_FOUND); |
1098 | return; | |
1099 | } | |
1100 | ||
3b41df31 | 1101 | /* |
1102 | * See if the job is owned by the requesting user... | |
1103 | */ | |
1104 | ||
1b918e3a | 1105 | if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) |
3b41df31 | 1106 | { |
1107 | strncpy(username, attr->values[0].string.text, sizeof(username) - 1); | |
1108 | username[sizeof(username) - 1] = '\0'; | |
1109 | } | |
1110 | else if (con->username[0]) | |
1111 | strcpy(username, con->username); | |
1112 | else | |
1113 | username[0] = '\0'; | |
1114 | ||
1115 | if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) | |
1116 | { | |
6bc08d08 | 1117 | /* |
1118 | * Not the owner or root; check to see if the user is a member of the | |
1119 | * system group... | |
1120 | */ | |
1121 | ||
1122 | user = getpwnam(username); | |
1123 | endpwent(); | |
1124 | ||
1125 | group = getgrnam(SystemGroup); | |
1126 | endgrent(); | |
1127 | ||
1128 | if (group != NULL) | |
1129 | for (i = 0; group->gr_mem[i]; i ++) | |
1130 | if (strcmp(username, group->gr_mem[i]) == 0) | |
1131 | break; | |
1132 | ||
1133 | if (user == NULL || group == NULL || | |
1134 | (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) | |
1135 | { | |
1136 | /* | |
1137 | * Username not found, group not found, or user is not part of the | |
1138 | * system group... | |
1139 | */ | |
1140 | ||
1141 | LogMessage(LOG_ERROR, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!", | |
1142 | username, jobid, job->username); | |
1143 | send_ipp_error(con, IPP_FORBIDDEN); | |
1144 | return; | |
1145 | } | |
3b41df31 | 1146 | } |
1147 | ||
1d2c70a6 | 1148 | /* |
1149 | * Cancel the job and return... | |
1150 | */ | |
1151 | ||
1152 | CancelJob(jobid); | |
96df88bb | 1153 | CheckJobs(); |
1d2c70a6 | 1154 | |
cc0561c6 | 1155 | LogMessage(LOG_INFO, "Job %d was cancelled by \'%s\'.", jobid, |
236ed8b4 | 1156 | con->username[0] ? con->username : "unknown"); |
cc0561c6 | 1157 | |
1d2c70a6 | 1158 | con->response->request.status.status_code = IPP_OK; |
e31bfb6e | 1159 | } |
1160 | ||
1161 | ||
1d2c70a6 | 1162 | /* |
1163 | * 'copy_attrs()' - Copy attributes from one request to another. | |
1164 | */ | |
1165 | ||
e31bfb6e | 1166 | static void |
d6de4648 | 1167 | copy_attrs(ipp_t *to, /* I - Destination request */ |
1168 | ipp_t *from, /* I - Source request */ | |
1169 | ipp_attribute_t *req) /* I - Requested attributes */ | |
e31bfb6e | 1170 | { |
1d2c70a6 | 1171 | int i; /* Looping var */ |
1172 | ipp_attribute_t *toattr, /* Destination attribute */ | |
1173 | *fromattr; /* Source attribute */ | |
1174 | ||
1175 | ||
1176 | DEBUG_printf(("copy_attrs(%08x, %08x)\n", to, from)); | |
1177 | ||
1178 | if (to == NULL || from == NULL) | |
1179 | return; | |
1180 | ||
c7fa9d06 | 1181 | if (req != NULL && strcmp(req->values[0].string.text, "all") == 0) |
1182 | req = NULL; /* "all" means no filter... */ | |
1183 | ||
1d2c70a6 | 1184 | for (fromattr = from->attrs; fromattr != NULL; fromattr = fromattr->next) |
1185 | { | |
d6de4648 | 1186 | /* |
1187 | * Filter attributes as needed... | |
1188 | */ | |
1189 | ||
1190 | if (req != NULL) | |
1191 | { | |
1192 | for (i = 0; i < req->num_values; i ++) | |
1193 | if (strcmp(fromattr->name, req->values[i].string.text) == 0) | |
1194 | break; | |
1195 | ||
1196 | if (i == req->num_values) | |
1197 | continue; | |
1198 | } | |
1199 | ||
1d2c70a6 | 1200 | DEBUG_printf(("copy_attrs: copying attribute \'%s\'...\n", fromattr->name)); |
1201 | ||
1202 | switch (fromattr->value_tag) | |
1203 | { | |
1204 | case IPP_TAG_INTEGER : | |
1205 | case IPP_TAG_ENUM : | |
c0341b41 | 1206 | toattr = ippAddIntegers(to, fromattr->group_tag, fromattr->value_tag, |
1207 | fromattr->name, fromattr->num_values, NULL); | |
1d2c70a6 | 1208 | |
1209 | for (i = 0; i < fromattr->num_values; i ++) | |
1210 | toattr->values[i].integer = fromattr->values[i].integer; | |
1211 | break; | |
1212 | ||
1213 | case IPP_TAG_BOOLEAN : | |
1214 | toattr = ippAddBooleans(to, fromattr->group_tag, fromattr->name, | |
1215 | fromattr->num_values, NULL); | |
1216 | ||
1217 | for (i = 0; i < fromattr->num_values; i ++) | |
1218 | toattr->values[i].boolean = fromattr->values[i].boolean; | |
1219 | break; | |
1220 | ||
1221 | case IPP_TAG_STRING : | |
1222 | case IPP_TAG_TEXT : | |
1223 | case IPP_TAG_NAME : | |
1224 | case IPP_TAG_KEYWORD : | |
1225 | case IPP_TAG_URI : | |
1226 | case IPP_TAG_URISCHEME : | |
1227 | case IPP_TAG_CHARSET : | |
1228 | case IPP_TAG_LANGUAGE : | |
1229 | case IPP_TAG_MIMETYPE : | |
c0341b41 | 1230 | toattr = ippAddStrings(to, fromattr->group_tag, fromattr->value_tag, |
1231 | fromattr->name, fromattr->num_values, NULL, | |
1232 | NULL); | |
1d2c70a6 | 1233 | |
1234 | for (i = 0; i < fromattr->num_values; i ++) | |
c0341b41 | 1235 | toattr->values[i].string.text = strdup(fromattr->values[i].string.text); |
1d2c70a6 | 1236 | break; |
1237 | ||
1238 | case IPP_TAG_DATE : | |
1239 | toattr = ippAddDate(to, fromattr->group_tag, fromattr->name, | |
1240 | fromattr->values[0].date); | |
1241 | break; | |
1242 | ||
1243 | case IPP_TAG_RESOLUTION : | |
1244 | toattr = ippAddResolutions(to, fromattr->group_tag, fromattr->name, | |
1245 | fromattr->num_values, IPP_RES_PER_INCH, | |
1246 | NULL, NULL); | |
1247 | ||
1248 | for (i = 0; i < fromattr->num_values; i ++) | |
1249 | { | |
1250 | toattr->values[i].resolution.xres = fromattr->values[i].resolution.xres; | |
1251 | toattr->values[i].resolution.yres = fromattr->values[i].resolution.yres; | |
1252 | toattr->values[i].resolution.units = fromattr->values[i].resolution.units; | |
1253 | } | |
1254 | break; | |
1255 | ||
1256 | case IPP_TAG_RANGE : | |
1257 | toattr = ippAddRanges(to, fromattr->group_tag, fromattr->name, | |
1258 | fromattr->num_values, NULL, NULL); | |
1259 | ||
1260 | for (i = 0; i < fromattr->num_values; i ++) | |
1261 | { | |
1262 | toattr->values[i].range.lower = fromattr->values[i].range.lower; | |
1263 | toattr->values[i].range.upper = fromattr->values[i].range.upper; | |
1264 | } | |
1265 | break; | |
1266 | ||
1267 | case IPP_TAG_TEXTLANG : | |
1268 | case IPP_TAG_NAMELANG : | |
c0341b41 | 1269 | toattr = ippAddStrings(to, fromattr->group_tag, fromattr->value_tag, |
1270 | fromattr->name, fromattr->num_values, NULL, NULL); | |
1d2c70a6 | 1271 | |
1272 | for (i = 0; i < fromattr->num_values; i ++) | |
1273 | { | |
c0341b41 | 1274 | if (i == 0) |
1275 | toattr->values[0].string.charset = | |
1276 | strdup(fromattr->values[0].string.charset); | |
1277 | else | |
1278 | toattr->values[i].string.charset = | |
1279 | toattr->values[0].string.charset; | |
1280 | ||
1281 | toattr->values[i].string.text = | |
1282 | strdup(fromattr->values[i].string.text); | |
1d2c70a6 | 1283 | } |
1284 | break; | |
1285 | } | |
1286 | } | |
e31bfb6e | 1287 | } |
1288 | ||
1289 | ||
bd84e0d1 | 1290 | /* |
1291 | * 'create_job()' - Print a file to a printer or class. | |
1292 | */ | |
1293 | ||
1294 | static void | |
1295 | create_job(client_t *con, /* I - Client connection */ | |
1296 | ipp_attribute_t *uri) /* I - Printer URI */ | |
1297 | { | |
1298 | ipp_attribute_t *attr; /* Current attribute */ | |
1049abbe | 1299 | const char *dest; /* Destination */ |
bd84e0d1 | 1300 | cups_ptype_t dtype; /* Destination type (printer or class) */ |
1301 | int priority; /* Job priority */ | |
1302 | char *title; /* Job name/title */ | |
1303 | job_t *job; /* Current job */ | |
1304 | char job_uri[HTTP_MAX_URI], | |
1305 | /* Job URI */ | |
1049abbe | 1306 | printer_uri[HTTP_MAX_URI], |
1307 | /* Printer URI */ | |
bd84e0d1 | 1308 | method[HTTP_MAX_URI], |
1309 | /* Method portion of URI */ | |
1310 | username[HTTP_MAX_URI], | |
1311 | /* Username portion of URI */ | |
1312 | host[HTTP_MAX_URI], | |
1313 | /* Host portion of URI */ | |
1314 | resource[HTTP_MAX_URI]; | |
1315 | /* Resource portion of URI */ | |
1316 | int port; /* Port portion of URI */ | |
1317 | printer_t *printer; /* Printer data */ | |
1318 | ||
1319 | ||
1320 | DEBUG_printf(("create_job(%08x, %08x)\n", con, uri)); | |
1321 | ||
1322 | /* | |
1323 | * Verify that the POST operation was done to a valid URI. | |
1324 | */ | |
1325 | ||
1326 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
1327 | strncmp(con->uri, "/printers/", 10) != 0) | |
1328 | { | |
1329 | LogMessage(LOG_ERROR, "create_job: cancel request on bad resource \'%s\'!", | |
1330 | con->uri); | |
1331 | send_ipp_error(con, IPP_NOT_AUTHORIZED); | |
1332 | return; | |
1333 | } | |
1334 | ||
1335 | /* | |
1336 | * Is the destination valid? | |
1337 | */ | |
1338 | ||
1339 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
1340 | ||
1049abbe | 1341 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
bd84e0d1 | 1342 | { |
1343 | /* | |
1344 | * Bad URI... | |
1345 | */ | |
1346 | ||
1347 | LogMessage(LOG_ERROR, "create_job: resource name \'%s\' no good!", resource); | |
1348 | send_ipp_error(con, IPP_NOT_FOUND); | |
1349 | return; | |
1350 | } | |
1351 | ||
1352 | /* | |
1353 | * See if the printer is accepting jobs... | |
1354 | */ | |
1355 | ||
1356 | if (dtype == CUPS_PRINTER_CLASS) | |
1049abbe | 1357 | { |
bd84e0d1 | 1358 | printer = FindClass(dest); |
1049abbe | 1359 | sprintf(printer_uri, "http://%s:%d/classes/%s", ServerName, |
1360 | ntohs(con->http.hostaddr.sin_port), dest); | |
1361 | } | |
bd84e0d1 | 1362 | else |
1049abbe | 1363 | { |
bd84e0d1 | 1364 | printer = FindPrinter(dest); |
1365 | ||
1049abbe | 1366 | sprintf(printer_uri, "http://%s:%d/printers/%s", ServerName, |
1367 | ntohs(con->http.hostaddr.sin_port), dest); | |
1368 | } | |
1369 | ||
bd84e0d1 | 1370 | if (!printer->accepting) |
1371 | { | |
1372 | LogMessage(LOG_INFO, "create_job: destination \'%s\' is not accepting jobs.", | |
1373 | dest); | |
1374 | send_ipp_error(con, IPP_NOT_ACCEPTING); | |
1375 | return; | |
1376 | } | |
1377 | ||
1378 | /* | |
1379 | * Create the job and set things up... | |
1380 | */ | |
1381 | ||
1382 | if ((attr = ippFindAttribute(con->request, "job-priority", IPP_TAG_INTEGER)) != NULL) | |
1383 | priority = attr->values[0].integer; | |
1384 | else | |
1049abbe | 1385 | ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority", |
1386 | priority = 50); | |
bd84e0d1 | 1387 | |
1388 | if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL) | |
1389 | title = attr->values[0].string.text; | |
1390 | else | |
1049abbe | 1391 | ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, |
1392 | title = "Untitled"); | |
bd84e0d1 | 1393 | |
1394 | if ((job = AddJob(priority, printer->name)) == NULL) | |
1395 | { | |
1396 | LogMessage(LOG_ERROR, "create_job: unable to add job for destination \'%s\'!", | |
1397 | dest); | |
1398 | send_ipp_error(con, IPP_INTERNAL_ERROR); | |
1399 | return; | |
1400 | } | |
1401 | ||
1402 | job->dtype = dtype; | |
1403 | job->attrs = con->request; | |
1404 | con->request = NULL; | |
1405 | ||
1406 | strncpy(job->title, title, sizeof(job->title) - 1); | |
1407 | ||
1408 | strcpy(job->username, con->username); | |
1409 | if ((attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME)) != NULL) | |
1410 | { | |
1411 | LogMessage(LOG_DEBUG, "create_job: requesting-user-name = \'%s\'", | |
1412 | attr->values[0].string.text); | |
1413 | ||
1414 | strncpy(job->username, attr->values[0].string.text, sizeof(job->username) - 1); | |
1415 | job->username[sizeof(job->username) - 1] = '\0'; | |
1416 | } | |
1417 | ||
1418 | if (job->username[0] == '\0') | |
1049abbe | 1419 | strcpy(job->username, "anonymous"); |
1420 | ||
1421 | if (attr == NULL) | |
1422 | ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", | |
1423 | NULL, job->username); | |
1424 | else | |
1425 | { | |
1426 | free(attr->name); | |
1427 | attr->name = strdup("job-originating-user-name"); | |
1428 | } | |
bd84e0d1 | 1429 | |
1430 | LogMessage(LOG_INFO, "Job %d created on \'%s\' by \'%s\'.", job->id, | |
1431 | job->dest, job->username); | |
1432 | ||
1049abbe | 1433 | /* |
1434 | * Add remaining job attributes... | |
1435 | */ | |
1436 | ||
1437 | ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); | |
1438 | job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM, | |
1439 | "job->state", IPP_JOB_STOPPED); | |
1440 | ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, | |
1441 | printer_uri); | |
1442 | ||
bd84e0d1 | 1443 | /* |
1444 | * Fill in the response info... | |
1445 | */ | |
1446 | ||
1447 | sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, | |
1448 | ntohs(con->http.hostaddr.sin_port), job->id); | |
1449 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); | |
1450 | ||
1451 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); | |
1452 | ||
1049abbe | 1453 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", |
1454 | job->state->values[0].integer); | |
bd84e0d1 | 1455 | |
1456 | con->response->request.status.status_code = IPP_OK; | |
1457 | } | |
1458 | ||
1459 | ||
1d2c70a6 | 1460 | /* |
c7fa9d06 | 1461 | * 'delete_printer()' - Remove a printer or class from the system. |
1d2c70a6 | 1462 | */ |
1463 | ||
e31bfb6e | 1464 | static void |
c7fa9d06 | 1465 | delete_printer(client_t *con, /* I - Client connection */ |
1466 | ipp_attribute_t *uri) /* I - URI of printer or class */ | |
e31bfb6e | 1467 | { |
1049abbe | 1468 | const char *dest; /* Destination */ |
c7fa9d06 | 1469 | cups_ptype_t dtype; /* Destination type (printer or class) */ |
1470 | char method[HTTP_MAX_URI], | |
1471 | /* Method portion of URI */ | |
1472 | username[HTTP_MAX_URI], | |
1473 | /* Username portion of URI */ | |
1474 | host[HTTP_MAX_URI], | |
1475 | /* Host portion of URI */ | |
1476 | resource[HTTP_MAX_URI]; | |
1477 | /* Resource portion of URI */ | |
1478 | int port; /* Port portion of URI */ | |
1479 | printer_t *printer; /* Printer/class */ | |
1480 | char filename[1024]; /* Script/PPD filename */ | |
1481 | ||
1482 | ||
f3d580b9 | 1483 | /* |
1484 | * Was this operation called from the correct URI? | |
1485 | */ | |
1486 | ||
1487 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
1488 | { | |
1917e0e9 | 1489 | LogMessage(LOG_ERROR, "delete_printer: admin request on bad resource \'%s\'!", |
1124e9ec | 1490 | con->uri); |
f3d580b9 | 1491 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
1492 | return; | |
1493 | } | |
1494 | ||
3270670b | 1495 | DEBUG_printf(("delete_printer(%08x, %08x)\n", con, uri)); |
e31bfb6e | 1496 | |
f3d580b9 | 1497 | /* |
c7fa9d06 | 1498 | * Do we have a valid URI? |
f3d580b9 | 1499 | */ |
1500 | ||
c7fa9d06 | 1501 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1502 | ||
1049abbe | 1503 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 1504 | { |
c7fa9d06 | 1505 | /* |
1506 | * Bad URI... | |
1507 | */ | |
1508 | ||
1917e0e9 | 1509 | LogMessage(LOG_ERROR, "delete_printer: resource name \'%s\' no good!", resource); |
c7fa9d06 | 1510 | send_ipp_error(con, IPP_NOT_FOUND); |
f3d580b9 | 1511 | return; |
1512 | } | |
1513 | ||
c7fa9d06 | 1514 | /* |
1515 | * Find the printer or class and delete it... | |
1516 | */ | |
1517 | ||
1518 | if (dtype == CUPS_PRINTER_CLASS) | |
1519 | printer = FindClass(dest); | |
1520 | else | |
1521 | printer = FindPrinter(dest); | |
1522 | ||
1523 | DeletePrinter(printer); | |
1524 | ||
1525 | /* | |
1526 | * Remove any old PPD or script files... | |
1527 | */ | |
1528 | ||
1529 | sprintf(filename, "%s/interfaces/%s", ServerRoot, dest); | |
1530 | unlink(filename); | |
1531 | ||
1532 | sprintf(filename, "%s/ppd/%s.ppd", ServerRoot, dest); | |
1533 | unlink(filename); | |
1534 | ||
cc0561c6 | 1535 | SaveAllPrinters(); |
1536 | ||
1537 | if (dtype == CUPS_PRINTER_CLASS) | |
1538 | LogMessage(LOG_INFO, "Class \'%s\' deleted by \'%s\'.", dest, | |
1539 | con->username); | |
1540 | else | |
1541 | LogMessage(LOG_INFO, "Printer \'%s\' deleted by \'%s\'.", dest, | |
1542 | con->username); | |
1543 | ||
c7fa9d06 | 1544 | /* |
1545 | * Return with no errors... | |
1546 | */ | |
1547 | ||
1548 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 1549 | } |
1550 | ||
1551 | ||
1d2c70a6 | 1552 | /* |
1553 | * 'get_default()' - Get the default destination. | |
1554 | */ | |
1555 | ||
e31bfb6e | 1556 | static void |
1d2c70a6 | 1557 | get_default(client_t *con) /* I - Client connection */ |
e31bfb6e | 1558 | { |
1d2c70a6 | 1559 | DEBUG_printf(("get_default(%08x)\n", con)); |
1560 | ||
3da4463c | 1561 | if (DefaultPrinter != NULL) |
1562 | { | |
1563 | copy_attrs(con->response, DefaultPrinter->attrs, | |
1564 | ippFindAttribute(con->request, "requested-attributes", | |
1565 | IPP_TAG_KEYWORD)); | |
1d2c70a6 | 1566 | |
3da4463c | 1567 | con->response->request.status.status_code = IPP_OK; |
1568 | } | |
1569 | else | |
1570 | con->response->request.status.status_code = IPP_NOT_FOUND; | |
e31bfb6e | 1571 | } |
1572 | ||
1573 | ||
bd84e0d1 | 1574 | /* |
1575 | * 'get_devices()' - Get the list of available devices on the local system. | |
1576 | */ | |
1577 | ||
1578 | static void | |
1579 | get_devices(client_t *con) /* I - Client connection */ | |
1580 | { | |
1581 | /* | |
1582 | * Copy the device attributes to the response using the requested-attributes | |
1583 | * attribute that may be provided by the client. | |
1584 | */ | |
1585 | ||
1586 | copy_attrs(con->response, Devices, | |
1587 | ippFindAttribute(con->request, "requested-attributes", | |
1588 | IPP_TAG_KEYWORD)); | |
1589 | ||
1590 | con->response->request.status.status_code = IPP_OK; | |
1591 | } | |
1592 | ||
1593 | ||
1d2c70a6 | 1594 | /* |
1595 | * 'get_jobs()' - Get a list of jobs for the specified printer. | |
1596 | */ | |
1597 | ||
e31bfb6e | 1598 | static void |
1d2c70a6 | 1599 | get_jobs(client_t *con, /* I - Client connection */ |
1600 | ipp_attribute_t *uri) /* I - Printer URI */ | |
e31bfb6e | 1601 | { |
e09246c8 | 1602 | int i; /* Looping var */ |
1d2c70a6 | 1603 | ipp_attribute_t *attr; /* Current attribute */ |
1049abbe | 1604 | const char *dest; /* Destination */ |
1d2c70a6 | 1605 | cups_ptype_t dtype; /* Destination type (printer or class) */ |
1606 | char method[HTTP_MAX_URI], | |
1607 | /* Method portion of URI */ | |
1608 | username[HTTP_MAX_URI], | |
1609 | /* Username portion of URI */ | |
1610 | host[HTTP_MAX_URI], | |
1611 | /* Host portion of URI */ | |
1612 | resource[HTTP_MAX_URI]; | |
1613 | /* Resource portion of URI */ | |
1614 | int port; /* Port portion of URI */ | |
bd84e0d1 | 1615 | int completed; /* Completed jobs? */ |
1d2c70a6 | 1616 | int limit; /* Maximum number of jobs to return */ |
1617 | int count; /* Number of jobs that match */ | |
1618 | job_t *job; /* Current job pointer */ | |
1619 | char job_uri[HTTP_MAX_URI], | |
1620 | /* Job URI... */ | |
1621 | printer_uri[HTTP_MAX_URI]; | |
1622 | /* Printer URI... */ | |
e09246c8 | 1623 | char filename[1024]; /* Job filename */ |
1d2c70a6 | 1624 | struct stat filestats; /* Print file information */ |
e09246c8 | 1625 | size_t jobsize; /* Total job sizes */ |
1d2c70a6 | 1626 | |
1627 | ||
96df88bb | 1628 | DEBUG_printf(("get_jobs(%08x, %08x)\n", con, uri)); |
1d2c70a6 | 1629 | |
1630 | /* | |
1631 | * Is the destination valid? | |
1632 | */ | |
1633 | ||
c0341b41 | 1634 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1d2c70a6 | 1635 | |
1636 | if ((strncmp(resource, "/jobs", 5) == 0 && strlen(resource) <= 6) || | |
1637 | (strncmp(resource, "/printers", 9) == 0 && strlen(resource) <= 10)) | |
1638 | { | |
1639 | dest = NULL; | |
1640 | dtype = (cups_ptype_t)0; | |
1641 | } | |
1642 | else if (strncmp(resource, "/classes", 8) == 0 && strlen(resource) <= 9) | |
1643 | { | |
1644 | dest = NULL; | |
1645 | dtype = CUPS_PRINTER_CLASS; | |
1646 | } | |
1049abbe | 1647 | else if ((dest = ValidateDest(resource, &dtype)) == NULL) |
1d2c70a6 | 1648 | { |
1649 | /* | |
1650 | * Bad URI... | |
1651 | */ | |
1652 | ||
1917e0e9 | 1653 | LogMessage(LOG_ERROR, "get_jobs: resource name \'%s\' no good!", resource); |
1d2c70a6 | 1654 | send_ipp_error(con, IPP_NOT_FOUND); |
1655 | return; | |
1656 | } | |
1657 | ||
1658 | /* | |
1659 | * See if the "which-jobs" attribute have been specified; if so, return | |
96df88bb | 1660 | * right away if they specify "completed" - we don't keep old job records... |
1d2c70a6 | 1661 | */ |
1662 | ||
c0341b41 | 1663 | if ((attr = ippFindAttribute(con->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL && |
1664 | strcmp(attr->values[0].string.text, "completed") == 0) | |
bd84e0d1 | 1665 | completed = 1; |
1666 | else | |
1667 | completed = 0; | |
1d2c70a6 | 1668 | |
1669 | /* | |
1670 | * See if they want to limit the number of jobs reported; if not, limit | |
1671 | * the report to 1000 jobs to prevent swamping of the server... | |
1672 | */ | |
1673 | ||
c0341b41 | 1674 | if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) |
1d2c70a6 | 1675 | limit = attr->values[0].integer; |
1676 | else | |
1677 | limit = 1000; | |
1678 | ||
1679 | /* | |
1680 | * See if we only want to see jobs for a specific user... | |
1681 | */ | |
1682 | ||
c0341b41 | 1683 | if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && |
1d2c70a6 | 1684 | attr->values[0].boolean) |
1685 | { | |
1686 | strcpy(username, con->username); | |
1687 | ||
c0341b41 | 1688 | if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) |
1d2c70a6 | 1689 | { |
c0341b41 | 1690 | strncpy(username, attr->values[0].string.text, sizeof(username) - 1); |
1d2c70a6 | 1691 | username[sizeof(username) - 1] = '\0'; |
1692 | } | |
1693 | } | |
1694 | else | |
1695 | username[0] = '\0'; | |
1696 | ||
1697 | /* | |
1698 | * OK, build a list of jobs for this printer... | |
1699 | */ | |
1700 | ||
1701 | for (count = 0, job = Jobs; count < limit && job != NULL; job = job->next) | |
1702 | { | |
1703 | /* | |
1704 | * Filter out jobs that don't match... | |
1705 | */ | |
1706 | ||
96df88bb | 1707 | DEBUG_printf(("get_jobs: job->id = %d\n", job->id)); |
1708 | ||
1d2c70a6 | 1709 | if ((dest != NULL && strcmp(job->dest, dest) != 0)) |
1710 | continue; | |
1711 | if (job->dtype != dtype && | |
1712 | (username[0] == '\0' || strncmp(resource, "/jobs", 5) != 0)) | |
1713 | continue; | |
1714 | if (username[0] != '\0' && strcmp(username, job->username) != 0) | |
1715 | continue; | |
1716 | ||
1049abbe | 1717 | if (completed && job->state->values[0].integer <= IPP_JOB_STOPPED) |
bd84e0d1 | 1718 | continue; |
1049abbe | 1719 | if (!completed && job->state->values[0].integer > IPP_JOB_STOPPED) |
bd84e0d1 | 1720 | continue; |
1721 | ||
1d2c70a6 | 1722 | count ++; |
1723 | ||
96df88bb | 1724 | DEBUG_printf(("get_jobs: count = %d\n", count)); |
1725 | ||
1d2c70a6 | 1726 | /* |
1727 | * Send the following attributes for each job: | |
1728 | * | |
1729 | * job-id | |
1730 | * job-k-octets | |
1731 | * job-more-info | |
1732 | * job-originating-user-name | |
1733 | * job-printer-uri | |
1734 | * job-priority | |
1735 | * job-state | |
1736 | * job-uri | |
27b6a264 | 1737 | * job-name |
1d2c70a6 | 1738 | * |
1739 | * Note that we are supposed to look at the "requested-attributes" | |
1740 | * attribute to determine what we send, however the IPP/1.0 spec also | |
1741 | * doesn't state that the server must limit the attributes to those | |
1742 | * requested. In other words, the server can either implement the | |
1743 | * filtering or not, and if not it needs to send all attributes that | |
1744 | * it has... | |
1745 | */ | |
1746 | ||
1747 | sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, | |
1748 | ntohs(con->http.hostaddr.sin_port), job->id); | |
1749 | ||
e09246c8 | 1750 | for (i = 0, jobsize = 0; i < job->num_files; i ++) |
1751 | { | |
1752 | sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, i + 1); | |
1753 | stat(filename, &filestats); | |
1754 | jobsize += filestats.st_size; | |
1755 | } | |
1756 | ||
27b6a264 | 1757 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, |
e09246c8 | 1758 | "job-k-octets", (jobsize + 1023) / 1024); |
27b6a264 | 1759 | |
1760 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, | |
1761 | "job-more-info", NULL, job_uri); | |
1d2c70a6 | 1762 | |
27b6a264 | 1763 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, |
1049abbe | 1764 | "job-uri", NULL, job_uri); |
1d2c70a6 | 1765 | |
1049abbe | 1766 | /* |
1767 | * Copy the job attributes to the response using the requested-attributes | |
1768 | * attribute that may be provided by the client. | |
1769 | */ | |
1d2c70a6 | 1770 | |
1049abbe | 1771 | copy_attrs(con->response, job->attrs, |
1772 | ippFindAttribute(con->request, "requested-attributes", | |
1773 | IPP_TAG_KEYWORD)); | |
1d2c70a6 | 1774 | |
1d2c70a6 | 1775 | ippAddSeparator(con->response); |
1776 | } | |
1777 | ||
c0341b41 | 1778 | if (ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD) != NULL) |
1d2c70a6 | 1779 | con->response->request.status.status_code = IPP_OK_SUBST; |
1780 | else | |
1781 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 1782 | } |
1783 | ||
1784 | ||
1d2c70a6 | 1785 | /* |
1786 | * 'get_job_attrs()' - Get job attributes. | |
1787 | */ | |
1788 | ||
e31bfb6e | 1789 | static void |
1d2c70a6 | 1790 | get_job_attrs(client_t *con, /* I - Client connection */ |
1791 | ipp_attribute_t *uri) /* I - Job URI */ | |
e31bfb6e | 1792 | { |
e09246c8 | 1793 | int i; /* Looping var */ |
1d2c70a6 | 1794 | ipp_attribute_t *attr; /* Current attribute */ |
1795 | int jobid; /* Job ID */ | |
1796 | job_t *job; /* Current job */ | |
1797 | char method[HTTP_MAX_URI], | |
1798 | /* Method portion of URI */ | |
1799 | username[HTTP_MAX_URI], | |
1800 | /* Username portion of URI */ | |
1801 | host[HTTP_MAX_URI], | |
1802 | /* Host portion of URI */ | |
1803 | resource[HTTP_MAX_URI]; | |
1804 | /* Resource portion of URI */ | |
1805 | int port; /* Port portion of URI */ | |
782359ca | 1806 | char job_uri[HTTP_MAX_URI], |
1807 | /* Job URI... */ | |
1808 | printer_uri[HTTP_MAX_URI]; | |
1809 | /* Printer URI... */ | |
e09246c8 | 1810 | char filename[1024]; /* Job filename */ |
782359ca | 1811 | struct stat filestats; /* Print file information */ |
e09246c8 | 1812 | size_t jobsize; /* Total job sizes */ |
1d2c70a6 | 1813 | |
1814 | ||
1815 | DEBUG_printf(("get_job_attrs(%08x, %08x)\n", con, uri)); | |
1816 | ||
1817 | /* | |
1818 | * See if we have a job URI or a printer URI... | |
1819 | */ | |
1820 | ||
1821 | if (strcmp(uri->name, "printer-uri") == 0) | |
1822 | { | |
1823 | /* | |
1824 | * Got a printer URI; see if we also have a job-id attribute... | |
1825 | */ | |
1826 | ||
c0341b41 | 1827 | if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) |
1d2c70a6 | 1828 | { |
bd84e0d1 | 1829 | LogMessage(LOG_ERROR, "get_job_attrs: got a printer-uri attribute but no job-id!"); |
1d2c70a6 | 1830 | send_ipp_error(con, IPP_BAD_REQUEST); |
1831 | return; | |
1832 | } | |
1833 | ||
1834 | jobid = attr->values[0].integer; | |
1835 | } | |
1836 | else | |
1837 | { | |
1838 | /* | |
1839 | * Got a job URI; parse it to get the job ID... | |
1840 | */ | |
1841 | ||
c0341b41 | 1842 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1d2c70a6 | 1843 | |
1844 | if (strncmp(resource, "/jobs/", 6) != 0) | |
1845 | { | |
1846 | /* | |
1847 | * Not a valid URI! | |
1848 | */ | |
1849 | ||
bd84e0d1 | 1850 | LogMessage(LOG_ERROR, "get_job_attrs: bad job-uri attribute \'%s\'!\n", |
1851 | uri->values[0].string.text); | |
1d2c70a6 | 1852 | send_ipp_error(con, IPP_BAD_REQUEST); |
1853 | return; | |
1854 | } | |
1855 | ||
1856 | jobid = atoi(resource + 6); | |
1857 | } | |
1858 | ||
1859 | /* | |
1860 | * See if the job exists... | |
1861 | */ | |
1862 | ||
1863 | if ((job = FindJob(jobid)) == NULL) | |
1864 | { | |
1865 | /* | |
1866 | * Nope - return a "not found" error... | |
1867 | */ | |
1868 | ||
bd84e0d1 | 1869 | LogMessage(LOG_ERROR, "get_job_attrs: job #%d doesn't exist!", jobid); |
1d2c70a6 | 1870 | send_ipp_error(con, IPP_NOT_FOUND); |
1871 | return; | |
1872 | } | |
1873 | ||
782359ca | 1874 | /* |
1875 | * Put out the standard attributes... | |
1876 | */ | |
1877 | ||
1878 | sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, | |
1879 | ntohs(con->http.hostaddr.sin_port), job->id); | |
1880 | ||
782359ca | 1881 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); |
1882 | ||
e09246c8 | 1883 | for (i = 0, jobsize = 0; i < job->num_files; i ++) |
1884 | { | |
1885 | sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, i + 1); | |
1886 | stat(filename, &filestats); | |
1887 | jobsize += filestats.st_size; | |
1888 | } | |
782359ca | 1889 | |
782359ca | 1890 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, |
e09246c8 | 1891 | "job-k-octets", (jobsize + 1023) / 1024); |
782359ca | 1892 | |
1893 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, | |
1894 | "job-more-info", NULL, job_uri); | |
1895 | ||
782359ca | 1896 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, |
1897 | "job-uri", NULL, job_uri); | |
1898 | ||
1d2c70a6 | 1899 | /* |
d6de4648 | 1900 | * Copy the job attributes to the response using the requested-attributes |
1d2c70a6 | 1901 | * attribute that may be provided by the client. |
1902 | */ | |
1903 | ||
d6de4648 | 1904 | copy_attrs(con->response, job->attrs, |
1905 | ippFindAttribute(con->request, "requested-attributes", | |
1906 | IPP_TAG_KEYWORD)); | |
1d2c70a6 | 1907 | |
1049abbe | 1908 | if (ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD) != NULL) |
1909 | con->response->request.status.status_code = IPP_OK_SUBST; | |
1910 | else | |
1911 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 1912 | } |
1913 | ||
1914 | ||
bd84e0d1 | 1915 | /* |
1916 | * 'get_ppds()' - Get the list of PPD files on the local system. | |
1917 | */ | |
1918 | ||
1919 | static void | |
1920 | get_ppds(client_t *con) /* I - Client connection */ | |
1921 | { | |
1922 | /* | |
1923 | * Copy the PPD attributes to the response using the requested-attributes | |
1924 | * attribute that may be provided by the client. | |
1925 | */ | |
1926 | ||
1927 | copy_attrs(con->response, PPDs, | |
1928 | ippFindAttribute(con->request, "requested-attributes", | |
1929 | IPP_TAG_KEYWORD)); | |
1930 | ||
1931 | con->response->request.status.status_code = IPP_OK; | |
1932 | } | |
1933 | ||
1934 | ||
1d2c70a6 | 1935 | /* |
1936 | * 'get_printers()' - Get a list of printers. | |
1937 | */ | |
1938 | ||
e31bfb6e | 1939 | static void |
cbbfcc63 | 1940 | get_printers(client_t *con, /* I - Client connection */ |
1941 | int type) /* I - 0 or CUPS_PRINTER_CLASS */ | |
1d2c70a6 | 1942 | { |
1943 | ipp_attribute_t *attr; /* Current attribute */ | |
1944 | int limit; /* Maximum number of printers to return */ | |
1945 | int count; /* Number of printers that match */ | |
1946 | printer_t *printer; /* Current printer pointer */ | |
f3d580b9 | 1947 | time_t curtime; /* Current time */ |
1d2c70a6 | 1948 | |
1949 | ||
1950 | DEBUG_printf(("get_printers(%08x)\n", con)); | |
1951 | ||
1952 | /* | |
1953 | * See if they want to limit the number of printers reported; if not, limit | |
1954 | * the report to 1000 printers to prevent swamping of the server... | |
1955 | */ | |
1956 | ||
c0341b41 | 1957 | if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) |
1d2c70a6 | 1958 | limit = attr->values[0].integer; |
1959 | else | |
1960 | limit = 1000; | |
1961 | ||
1962 | /* | |
1963 | * OK, build a list of printers for this printer... | |
1964 | */ | |
1965 | ||
f3d580b9 | 1966 | curtime = time(NULL); |
1967 | ||
1d2c70a6 | 1968 | for (count = 0, printer = Printers; |
1969 | count < limit && printer != NULL; | |
1970 | printer = printer->next) | |
cbbfcc63 | 1971 | if ((printer->type & CUPS_PRINTER_CLASS) == type) |
1972 | { | |
1973 | /* | |
1974 | * Send the following attributes for each printer: | |
1975 | * | |
1976 | * printer-state | |
1977 | * printer-state-message | |
1978 | * printer-is-accepting-jobs | |
cbbfcc63 | 1979 | * + all printer attributes |
1980 | */ | |
1d2c70a6 | 1981 | |
cbbfcc63 | 1982 | ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, |
1983 | "printer-state", printer->state); | |
96df88bb | 1984 | |
cbbfcc63 | 1985 | if (printer->state_message[0]) |
1986 | ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, | |
1987 | "printer-state-message", NULL, printer->state_message); | |
1d2c70a6 | 1988 | |
cbbfcc63 | 1989 | ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", |
1990 | printer->accepting); | |
1d2c70a6 | 1991 | |
cbbfcc63 | 1992 | ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, |
1993 | "printer-up-time", curtime - StartTime); | |
1994 | ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", | |
1995 | ippTimeToDate(curtime)); | |
f3d580b9 | 1996 | |
cbbfcc63 | 1997 | copy_attrs(con->response, printer->attrs, |
1998 | ippFindAttribute(con->request, "requested-attributes", | |
1999 | IPP_TAG_KEYWORD)); | |
1d2c70a6 | 2000 | |
cbbfcc63 | 2001 | ippAddSeparator(con->response); |
2002 | } | |
1d2c70a6 | 2003 | |
d6de4648 | 2004 | con->response->request.status.status_code = IPP_OK; |
1d2c70a6 | 2005 | } |
2006 | ||
2007 | ||
2008 | /* | |
2009 | * 'get_printer_attrs()' - Get printer attributes. | |
2010 | */ | |
2011 | ||
2012 | static void | |
2013 | get_printer_attrs(client_t *con, /* I - Client connection */ | |
2014 | ipp_attribute_t *uri) /* I - Printer URI */ | |
2015 | { | |
1049abbe | 2016 | const char *dest; /* Destination */ |
1d2c70a6 | 2017 | cups_ptype_t dtype; /* Destination type (printer or class) */ |
2018 | char method[HTTP_MAX_URI], | |
2019 | /* Method portion of URI */ | |
2020 | username[HTTP_MAX_URI], | |
2021 | /* Username portion of URI */ | |
2022 | host[HTTP_MAX_URI], | |
2023 | /* Host portion of URI */ | |
2024 | resource[HTTP_MAX_URI]; | |
2025 | /* Resource portion of URI */ | |
2026 | int port; /* Port portion of URI */ | |
cbbfcc63 | 2027 | printer_t *printer; /* Printer/class */ |
f3d580b9 | 2028 | time_t curtime; /* Current time */ |
1d2c70a6 | 2029 | |
2030 | ||
2031 | DEBUG_printf(("get_printer_attrs(%08x, %08x)\n", con, uri)); | |
2032 | ||
2033 | /* | |
2034 | * Is the destination valid? | |
2035 | */ | |
2036 | ||
c0341b41 | 2037 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1d2c70a6 | 2038 | |
1049abbe | 2039 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
1d2c70a6 | 2040 | { |
2041 | /* | |
2042 | * Bad URI... | |
2043 | */ | |
2044 | ||
1917e0e9 | 2045 | LogMessage(LOG_ERROR, "get_printer_attrs: resource name \'%s\' no good!", resource); |
1d2c70a6 | 2046 | send_ipp_error(con, IPP_NOT_FOUND); |
2047 | return; | |
2048 | } | |
2049 | ||
1d2c70a6 | 2050 | if (dtype == CUPS_PRINTER_CLASS) |
cbbfcc63 | 2051 | printer = FindClass(dest); |
1d2c70a6 | 2052 | else |
2053 | printer = FindPrinter(dest); | |
2054 | ||
f3d580b9 | 2055 | curtime = time(NULL); |
2056 | ||
d6de4648 | 2057 | /* |
2058 | * Copy the printer attributes to the response using requested-attributes | |
2059 | * and document-format attributes that may be provided by the client. | |
2060 | */ | |
2061 | ||
2062 | copy_attrs(con->response, printer->attrs, | |
2063 | ippFindAttribute(con->request, "requested-attributes", | |
2064 | IPP_TAG_KEYWORD)); | |
1d2c70a6 | 2065 | |
96df88bb | 2066 | ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", |
2067 | printer->state); | |
2068 | ||
2069 | if (printer->state_message[0]) | |
2070 | ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, | |
2071 | "printer-state-message", NULL, printer->state_message); | |
2072 | ||
f3d580b9 | 2073 | ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", |
2074 | printer->accepting); | |
2075 | ||
2076 | ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, | |
2077 | "printer-up-time", curtime - StartTime); | |
2078 | ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", | |
2079 | ippTimeToDate(curtime)); | |
2080 | ||
d6de4648 | 2081 | con->response->request.status.status_code = IPP_OK; |
1d2c70a6 | 2082 | } |
2083 | ||
2084 | ||
2085 | /* | |
bd84e0d1 | 2086 | * 'hold_job()' - Cancel a print job. |
1d2c70a6 | 2087 | */ |
2088 | ||
2089 | static void | |
bd84e0d1 | 2090 | hold_job(client_t *con, /* I - Client connection */ |
2091 | ipp_attribute_t *uri) /* I - Job or Printer URI */ | |
e31bfb6e | 2092 | { |
bd84e0d1 | 2093 | int i; /* Looping var */ |
e31bfb6e | 2094 | ipp_attribute_t *attr; /* Current attribute */ |
bd84e0d1 | 2095 | int jobid; /* Job ID */ |
2096 | char method[HTTP_MAX_URI], | |
e31bfb6e | 2097 | /* Method portion of URI */ |
2098 | username[HTTP_MAX_URI], | |
2099 | /* Username portion of URI */ | |
2100 | host[HTTP_MAX_URI], | |
2101 | /* Host portion of URI */ | |
2102 | resource[HTTP_MAX_URI]; | |
2103 | /* Resource portion of URI */ | |
2104 | int port; /* Port portion of URI */ | |
bd84e0d1 | 2105 | job_t *job; /* Job information */ |
2106 | struct passwd *user; /* User info */ | |
2107 | struct group *group; /* System group info */ | |
e31bfb6e | 2108 | |
2109 | ||
bd84e0d1 | 2110 | DEBUG_printf(("hold_job(%08x, %08x)\n", con, uri)); |
e31bfb6e | 2111 | |
2aeb2b1d | 2112 | /* |
2113 | * Verify that the POST operation was done to a valid URI. | |
2114 | */ | |
2115 | ||
2116 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
bd84e0d1 | 2117 | strncmp(con->uri, "/jobs/", 5) != 0 && |
2aeb2b1d | 2118 | strncmp(con->uri, "/printers/", 10) != 0) |
2119 | { | |
bd84e0d1 | 2120 | LogMessage(LOG_ERROR, "hold_job: hold request on bad resource \'%s\'!", |
1124e9ec | 2121 | con->uri); |
2aeb2b1d | 2122 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
2123 | return; | |
2124 | } | |
2125 | ||
e31bfb6e | 2126 | /* |
bd84e0d1 | 2127 | * See if we have a job URI or a printer URI... |
e31bfb6e | 2128 | */ |
2129 | ||
bd84e0d1 | 2130 | if (strcmp(uri->name, "printer-uri") == 0) |
e31bfb6e | 2131 | { |
4791a466 | 2132 | /* |
bd84e0d1 | 2133 | * Got a printer URI; see if we also have a job-id attribute... |
4791a466 | 2134 | */ |
e31bfb6e | 2135 | |
bd84e0d1 | 2136 | if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) |
4791a466 | 2137 | { |
bd84e0d1 | 2138 | LogMessage(LOG_ERROR, "hold_job: got a printer-uri attribute but no job-id!"); |
4791a466 | 2139 | send_ipp_error(con, IPP_BAD_REQUEST); |
2140 | return; | |
2141 | } | |
4791a466 | 2142 | |
bd84e0d1 | 2143 | jobid = attr->values[0].integer; |
e31bfb6e | 2144 | } |
bd84e0d1 | 2145 | else |
e31bfb6e | 2146 | { |
782359ca | 2147 | /* |
bd84e0d1 | 2148 | * Got a job URI; parse it to get the job ID... |
782359ca | 2149 | */ |
2150 | ||
bd84e0d1 | 2151 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
2152 | ||
2153 | if (strncmp(resource, "/jobs/", 6) != 0) | |
c6e90b24 | 2154 | { |
2155 | /* | |
bd84e0d1 | 2156 | * Not a valid URI! |
2157 | */ | |
2158 | ||
2159 | LogMessage(LOG_ERROR, "hold_job: bad job-uri attribute \'%s\'!", | |
2160 | uri->values[0].string.text); | |
2161 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2162 | return; | |
2163 | } | |
2164 | ||
2165 | jobid = atoi(resource + 6); | |
2166 | } | |
2167 | ||
2168 | /* | |
2169 | * See if the job exists... | |
2170 | */ | |
2171 | ||
2172 | if ((job = FindJob(jobid)) == NULL) | |
2173 | { | |
2174 | /* | |
2175 | * Nope - return a "not found" error... | |
2176 | */ | |
2177 | ||
2178 | LogMessage(LOG_ERROR, "hold_job: job #%d doesn't exist!", jobid); | |
2179 | send_ipp_error(con, IPP_NOT_FOUND); | |
2180 | return; | |
2181 | } | |
2182 | ||
2183 | /* | |
2184 | * See if the job is owned by the requesting user... | |
2185 | */ | |
2186 | ||
2187 | if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) | |
2188 | { | |
2189 | strncpy(username, attr->values[0].string.text, sizeof(username) - 1); | |
2190 | username[sizeof(username) - 1] = '\0'; | |
2191 | } | |
2192 | else if (con->username[0]) | |
2193 | strcpy(username, con->username); | |
2194 | else | |
2195 | username[0] = '\0'; | |
2196 | ||
2197 | if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) | |
2198 | { | |
2199 | /* | |
2200 | * Not the owner or root; check to see if the user is a member of the | |
2201 | * system group... | |
2202 | */ | |
2203 | ||
2204 | user = getpwnam(username); | |
2205 | endpwent(); | |
2206 | ||
2207 | group = getgrnam(SystemGroup); | |
2208 | endgrent(); | |
2209 | ||
2210 | if (group != NULL) | |
2211 | for (i = 0; group->gr_mem[i]; i ++) | |
2212 | if (strcmp(username, group->gr_mem[i]) == 0) | |
2213 | break; | |
2214 | ||
2215 | if (user == NULL || group == NULL || | |
2216 | (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) | |
2217 | { | |
2218 | /* | |
2219 | * Username not found, group not found, or user is not part of the | |
2220 | * system group... | |
2221 | */ | |
2222 | ||
2223 | LogMessage(LOG_ERROR, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!", | |
2224 | username, jobid, job->username); | |
2225 | send_ipp_error(con, IPP_FORBIDDEN); | |
2226 | return; | |
2227 | } | |
2228 | } | |
2229 | ||
2230 | /* | |
2231 | * Hold the job and return... | |
2232 | */ | |
2233 | ||
2234 | HoldJob(jobid); | |
2235 | ||
2236 | LogMessage(LOG_INFO, "Job %d was held by \'%s\'.", jobid, | |
2237 | con->username[0] ? con->username : "unknown"); | |
2238 | ||
2239 | con->response->request.status.status_code = IPP_OK; | |
2240 | } | |
2241 | ||
2242 | ||
2243 | /* | |
2244 | * 'print_job()' - Print a file to a printer or class. | |
2245 | */ | |
2246 | ||
2247 | static void | |
2248 | print_job(client_t *con, /* I - Client connection */ | |
2249 | ipp_attribute_t *uri) /* I - Printer URI */ | |
2250 | { | |
2251 | ipp_attribute_t *attr; /* Current attribute */ | |
2252 | ipp_attribute_t *format; /* Document-format attribute */ | |
1049abbe | 2253 | const char *dest; /* Destination */ |
bd84e0d1 | 2254 | cups_ptype_t dtype; /* Destination type (printer or class) */ |
2255 | int priority; /* Job priority */ | |
2256 | char *title; /* Job name/title */ | |
2257 | job_t *job; /* Current job */ | |
2258 | char job_uri[HTTP_MAX_URI], | |
2259 | /* Job URI */ | |
1049abbe | 2260 | printer_uri[HTTP_MAX_URI], |
2261 | /* Printer URI */ | |
bd84e0d1 | 2262 | method[HTTP_MAX_URI], |
2263 | /* Method portion of URI */ | |
2264 | username[HTTP_MAX_URI], | |
2265 | /* Username portion of URI */ | |
2266 | host[HTTP_MAX_URI], | |
2267 | /* Host portion of URI */ | |
2268 | resource[HTTP_MAX_URI], | |
2269 | /* Resource portion of URI */ | |
2270 | filename[1024]; /* Job filename */ | |
2271 | int port; /* Port portion of URI */ | |
2272 | mime_type_t *filetype; /* Type of file */ | |
2273 | char super[MIME_MAX_SUPER], | |
2274 | /* Supertype of file */ | |
2275 | type[MIME_MAX_TYPE], | |
2276 | /* Subtype of file */ | |
2277 | mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; | |
2278 | /* Textual name of mime type */ | |
2279 | printer_t *printer; /* Printer data */ | |
2280 | ||
2281 | ||
2282 | DEBUG_printf(("print_job(%08x, %08x)\n", con, uri)); | |
2283 | ||
2284 | /* | |
2285 | * Verify that the POST operation was done to a valid URI. | |
2286 | */ | |
2287 | ||
2288 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
2289 | strncmp(con->uri, "/printers/", 10) != 0) | |
2290 | { | |
2291 | LogMessage(LOG_ERROR, "print_job: cancel request on bad resource \'%s\'!", | |
2292 | con->uri); | |
2293 | send_ipp_error(con, IPP_NOT_AUTHORIZED); | |
2294 | return; | |
2295 | } | |
2296 | ||
2297 | /* | |
2298 | * OK, see if the client is sending the document compressed - CUPS | |
2299 | * doesn't support compression yet... | |
2300 | */ | |
2301 | ||
2302 | if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) | |
2303 | { | |
2304 | LogMessage(LOG_ERROR, "print_job: Unsupported compression attribute!"); | |
2305 | send_ipp_error(con, IPP_ATTRIBUTES); | |
2306 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, | |
2307 | "compression", NULL, attr->values[0].string.text); | |
2308 | return; | |
2309 | } | |
2310 | ||
2311 | /* | |
2312 | * Do we have a file to print? | |
2313 | */ | |
2314 | ||
2315 | if (con->filename[0] == '\0') | |
2316 | { | |
2317 | LogMessage(LOG_ERROR, "print_job: No file!?!"); | |
2318 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2319 | return; | |
2320 | } | |
2321 | ||
2322 | /* | |
2323 | * Is it a format we support? | |
2324 | */ | |
2325 | ||
2326 | if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) | |
2327 | { | |
2328 | /* | |
2329 | * Grab format from client... | |
2330 | */ | |
2331 | ||
2332 | if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) | |
2333 | { | |
2334 | LogMessage(LOG_ERROR, "print_job: could not scan type \'%s\'!", | |
2335 | format->values[0].string.text); | |
2336 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2337 | return; | |
2338 | } | |
2339 | } | |
2340 | else | |
2341 | { | |
2342 | /* | |
2343 | * No document format attribute? Auto-type it! | |
2344 | */ | |
2345 | ||
2346 | strcpy(super, "application"); | |
2347 | strcpy(type, "octet-stream"); | |
2348 | } | |
2349 | ||
2350 | if (strcmp(super, "application") == 0 && | |
2351 | strcmp(type, "octet-stream") == 0) | |
2352 | { | |
2353 | /* | |
2354 | * Auto-type the file... | |
2355 | */ | |
2356 | ||
2357 | LogMessage(LOG_DEBUG, "print_job: auto-typing file..."); | |
2358 | ||
2359 | filetype = mimeFileType(MimeDatabase, con->filename); | |
2360 | ||
2361 | if (filetype != NULL) | |
2362 | { | |
2363 | /* | |
2364 | * Replace the document-format attribute value with the auto-typed one. | |
c6e90b24 | 2365 | */ |
782359ca | 2366 | |
c6e90b24 | 2367 | sprintf(mimetype, "%s/%s", filetype->super, filetype->type); |
4791a466 | 2368 | |
2369 | if (format != NULL) | |
2370 | { | |
2371 | free(format->values[0].string.text); | |
2372 | format->values[0].string.text = strdup(mimetype); | |
2373 | } | |
2374 | else | |
2375 | ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, | |
2376 | "document-format", NULL, mimetype); | |
c6e90b24 | 2377 | } |
e31bfb6e | 2378 | } |
2379 | else | |
2380 | filetype = mimeType(MimeDatabase, super, type); | |
2381 | ||
2382 | if (filetype == NULL) | |
2383 | { | |
bd84e0d1 | 2384 | LogMessage(LOG_ERROR, "print_job: Unsupported format \'%s\'!", |
2385 | format->values[0].string.text); | |
1d2c70a6 | 2386 | send_ipp_error(con, IPP_DOCUMENT_FORMAT); |
bd84e0d1 | 2387 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, |
2388 | "document-format", NULL, format->values[0].string.text); | |
e31bfb6e | 2389 | return; |
2390 | } | |
2391 | ||
bd84e0d1 | 2392 | LogMessage(LOG_DEBUG, "print_job: request file type is %s/%s.", |
2393 | filetype->super, filetype->type); | |
e31bfb6e | 2394 | |
2395 | /* | |
2396 | * Is the destination valid? | |
2397 | */ | |
2398 | ||
c0341b41 | 2399 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
e31bfb6e | 2400 | |
1049abbe | 2401 | if ((dest = ValidateDest(resource, &dtype)) == NULL) |
e31bfb6e | 2402 | { |
2403 | /* | |
2404 | * Bad URI... | |
2405 | */ | |
2406 | ||
1917e0e9 | 2407 | LogMessage(LOG_ERROR, "print_job: resource name \'%s\' no good!", resource); |
1d2c70a6 | 2408 | send_ipp_error(con, IPP_NOT_FOUND); |
e31bfb6e | 2409 | return; |
2410 | } | |
2411 | ||
f3d580b9 | 2412 | /* |
2413 | * See if the printer is accepting jobs... | |
2414 | */ | |
2415 | ||
2416 | if (dtype == CUPS_PRINTER_CLASS) | |
1049abbe | 2417 | { |
cbbfcc63 | 2418 | printer = FindClass(dest); |
1049abbe | 2419 | sprintf(printer_uri, "http://%s:%d/classes/%s", ServerName, |
2420 | ntohs(con->http.hostaddr.sin_port), dest); | |
2421 | } | |
f3d580b9 | 2422 | else |
1049abbe | 2423 | { |
f3d580b9 | 2424 | printer = FindPrinter(dest); |
2425 | ||
1049abbe | 2426 | sprintf(printer_uri, "http://%s:%d/printers/%s", ServerName, |
2427 | ntohs(con->http.hostaddr.sin_port), dest); | |
2428 | } | |
2429 | ||
cbbfcc63 | 2430 | if (!printer->accepting) |
2431 | { | |
1917e0e9 | 2432 | LogMessage(LOG_INFO, "print_job: destination \'%s\' is not accepting jobs.", |
2433 | dest); | |
cbbfcc63 | 2434 | send_ipp_error(con, IPP_NOT_ACCEPTING); |
2435 | return; | |
f3d580b9 | 2436 | } |
2437 | ||
e31bfb6e | 2438 | /* |
2439 | * Create the job and set things up... | |
2440 | */ | |
2441 | ||
c0341b41 | 2442 | if ((attr = ippFindAttribute(con->request, "job-priority", IPP_TAG_INTEGER)) != NULL) |
e31bfb6e | 2443 | priority = attr->values[0].integer; |
2444 | else | |
1049abbe | 2445 | ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority", |
2446 | priority = 50); | |
e31bfb6e | 2447 | |
27b6a264 | 2448 | if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL) |
2449 | title = attr->values[0].string.text; | |
2450 | else | |
1049abbe | 2451 | ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, |
2452 | title = "Untitled"); | |
27b6a264 | 2453 | |
cc0561c6 | 2454 | if ((job = AddJob(priority, printer->name)) == NULL) |
e31bfb6e | 2455 | { |
1917e0e9 | 2456 | LogMessage(LOG_ERROR, "print_job: unable to add job for destination \'%s\'!", |
2457 | dest); | |
e31bfb6e | 2458 | send_ipp_error(con, IPP_INTERNAL_ERROR); |
2459 | return; | |
2460 | } | |
2461 | ||
1049abbe | 2462 | job->state->values[0].integer = IPP_JOB_PENDING; |
2463 | job->dtype = dtype; | |
2464 | job->attrs = con->request; | |
2465 | con->request = NULL; | |
e31bfb6e | 2466 | |
e09246c8 | 2467 | if ((job->filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *))) == NULL) |
bd84e0d1 | 2468 | { |
2469 | CancelJob(job->id); | |
2470 | LogMessage(LOG_ERROR, "print_job: unable to allocate memory for file types!"); | |
2471 | send_ipp_error(con, IPP_INTERNAL_ERROR); | |
2472 | return; | |
2473 | } | |
2474 | ||
e09246c8 | 2475 | job->filetypes[0] = filetype; |
2476 | job->num_files = 1; | |
bd84e0d1 | 2477 | |
bd84e0d1 | 2478 | sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); |
2479 | rename(con->filename, filename); | |
2480 | ||
970017a4 | 2481 | strncpy(job->title, title, sizeof(job->title) - 1); |
2482 | ||
e31bfb6e | 2483 | con->filename[0] = '\0'; |
2484 | ||
2485 | strcpy(job->username, con->username); | |
c0341b41 | 2486 | if ((attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME)) != NULL) |
e31bfb6e | 2487 | { |
bd84e0d1 | 2488 | LogMessage(LOG_DEBUG, "print_job: requesting-user-name = \'%s\'", |
2489 | attr->values[0].string.text); | |
1d2c70a6 | 2490 | |
c0341b41 | 2491 | strncpy(job->username, attr->values[0].string.text, sizeof(job->username) - 1); |
e31bfb6e | 2492 | job->username[sizeof(job->username) - 1] = '\0'; |
2493 | } | |
2494 | ||
2495 | if (job->username[0] == '\0') | |
1049abbe | 2496 | strcpy(job->username, "anonymous"); |
2497 | ||
2498 | if (attr == NULL) | |
2499 | ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", | |
2500 | NULL, job->username); | |
2501 | else | |
2502 | { | |
2503 | free(attr->name); | |
2504 | attr->name = strdup("job-originating-user-name"); | |
2505 | } | |
e31bfb6e | 2506 | |
bd84e0d1 | 2507 | LogMessage(LOG_INFO, "Job %d queued on \'%s\' by \'%s\'.", job->id, |
2508 | job->dest, job->username); | |
1d2c70a6 | 2509 | |
1049abbe | 2510 | /* |
2511 | * Add remaining job attributes... | |
2512 | */ | |
2513 | ||
2514 | ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); | |
2515 | job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM, | |
2516 | "job->state", IPP_JOB_STOPPED); | |
2517 | ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, | |
2518 | printer_uri); | |
2519 | ||
e31bfb6e | 2520 | /* |
2521 | * Start the job if possible... | |
2522 | */ | |
2523 | ||
2524 | CheckJobs(); | |
2525 | ||
2526 | /* | |
2527 | * Fill in the response info... | |
2528 | */ | |
2529 | ||
2530 | sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, | |
2531 | ntohs(con->http.hostaddr.sin_port), job->id); | |
bd84e0d1 | 2532 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); |
e31bfb6e | 2533 | |
bd84e0d1 | 2534 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); |
e31bfb6e | 2535 | |
1049abbe | 2536 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", |
2537 | job->state->values[0].integer); | |
e31bfb6e | 2538 | |
2539 | con->response->request.status.status_code = IPP_OK; | |
2540 | } | |
2541 | ||
2542 | ||
f3d580b9 | 2543 | /* |
2544 | * 'reject_jobs()' - Reject print jobs to a printer. | |
2545 | */ | |
2546 | ||
2547 | static void | |
2548 | reject_jobs(client_t *con, /* I - Client connection */ | |
2549 | ipp_attribute_t *uri) /* I - Printer or class URI */ | |
2550 | { | |
2551 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
2552 | char method[HTTP_MAX_URI], | |
2553 | /* Method portion of URI */ | |
2554 | username[HTTP_MAX_URI], | |
2555 | /* Username portion of URI */ | |
2556 | host[HTTP_MAX_URI], | |
2557 | /* Host portion of URI */ | |
2558 | resource[HTTP_MAX_URI]; | |
2559 | /* Resource portion of URI */ | |
2560 | int port; /* Port portion of URI */ | |
1049abbe | 2561 | const char *name; /* Printer name */ |
f3d580b9 | 2562 | printer_t *printer; /* Printer data */ |
2563 | ipp_attribute_t *attr; /* printer-state-message text */ | |
2564 | ||
2565 | ||
2566 | DEBUG_printf(("reject_jobs(%08x, %08x)\n", con, uri)); | |
2567 | ||
2568 | /* | |
2569 | * Was this operation called from the correct URI? | |
2570 | */ | |
2571 | ||
2572 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
2573 | { | |
1917e0e9 | 2574 | LogMessage(LOG_ERROR, "reject_jobs: admin request on bad resource \'%s\'!", |
1124e9ec | 2575 | con->uri); |
f3d580b9 | 2576 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
2577 | return; | |
2578 | } | |
2579 | ||
2580 | /* | |
2581 | * Is the destination valid? | |
2582 | */ | |
2583 | ||
2584 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
2585 | ||
1049abbe | 2586 | if ((name = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 2587 | { |
2588 | /* | |
2589 | * Bad URI... | |
2590 | */ | |
2591 | ||
1917e0e9 | 2592 | LogMessage(LOG_ERROR, "reject_jobs: resource name \'%s\' no good!", resource); |
f3d580b9 | 2593 | send_ipp_error(con, IPP_NOT_FOUND); |
2594 | return; | |
2595 | } | |
2596 | ||
2597 | /* | |
2598 | * Reject jobs sent to the printer... | |
2599 | */ | |
2600 | ||
cbbfcc63 | 2601 | if (dtype == CUPS_PRINTER_CLASS) |
2602 | printer = FindClass(name); | |
2603 | else | |
2604 | printer = FindPrinter(name); | |
2605 | ||
f3d580b9 | 2606 | printer->accepting = 0; |
2607 | ||
2608 | if ((attr = ippFindAttribute(con->request, "printer-state-message", | |
2609 | IPP_TAG_TEXT)) == NULL) | |
2610 | strcpy(printer->state_message, "Rejecting Jobs"); | |
2611 | else | |
970017a4 | 2612 | { |
2613 | strncpy(printer->state_message, attr->values[0].string.text, | |
2614 | sizeof(printer->state_message) - 1); | |
2615 | printer->state_message[sizeof(printer->state_message) - 1] = '\0'; | |
2616 | } | |
f3d580b9 | 2617 | |
cc0561c6 | 2618 | if (dtype == CUPS_PRINTER_CLASS) |
2619 | LogMessage(LOG_INFO, "Class \'%s\' rejecting jobs (\'%s\').", name, | |
2620 | con->username); | |
2621 | else | |
2622 | LogMessage(LOG_INFO, "Printer \'%s\' rejecting jobs (\'%s\').", name, | |
2623 | con->username); | |
2624 | ||
f3d580b9 | 2625 | /* |
2626 | * Everything was ok, so return OK status... | |
2627 | */ | |
2628 | ||
2629 | con->response->request.status.status_code = IPP_OK; | |
2630 | } | |
2631 | ||
2632 | ||
bd84e0d1 | 2633 | /* |
2634 | * 'restart_job()' - Cancel a print job. | |
2635 | */ | |
2636 | ||
2637 | static void | |
2638 | restart_job(client_t *con, /* I - Client connection */ | |
2639 | ipp_attribute_t *uri) /* I - Job or Printer URI */ | |
2640 | { | |
2641 | int i; /* Looping var */ | |
2642 | ipp_attribute_t *attr; /* Current attribute */ | |
2643 | int jobid; /* Job ID */ | |
2644 | char method[HTTP_MAX_URI], | |
2645 | /* Method portion of URI */ | |
2646 | username[HTTP_MAX_URI], | |
2647 | /* Username portion of URI */ | |
2648 | host[HTTP_MAX_URI], | |
2649 | /* Host portion of URI */ | |
2650 | resource[HTTP_MAX_URI]; | |
2651 | /* Resource portion of URI */ | |
2652 | int port; /* Port portion of URI */ | |
2653 | job_t *job; /* Job information */ | |
2654 | struct passwd *user; /* User info */ | |
2655 | struct group *group; /* System group info */ | |
2656 | ||
2657 | ||
2658 | DEBUG_printf(("restart_job(%08x, %08x)\n", con, uri)); | |
2659 | ||
2660 | /* | |
2661 | * Verify that the POST operation was done to a valid URI. | |
2662 | */ | |
2663 | ||
2664 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
2665 | strncmp(con->uri, "/jobs/", 5) != 0 && | |
2666 | strncmp(con->uri, "/printers/", 10) != 0) | |
2667 | { | |
2668 | LogMessage(LOG_ERROR, "restart_job: restart request on bad resource \'%s\'!", | |
2669 | con->uri); | |
2670 | send_ipp_error(con, IPP_NOT_AUTHORIZED); | |
2671 | return; | |
2672 | } | |
2673 | ||
2674 | /* | |
2675 | * See if we have a job URI or a printer URI... | |
2676 | */ | |
2677 | ||
2678 | if (strcmp(uri->name, "printer-uri") == 0) | |
2679 | { | |
2680 | /* | |
2681 | * Got a printer URI; see if we also have a job-id attribute... | |
2682 | */ | |
2683 | ||
2684 | if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) | |
2685 | { | |
2686 | LogMessage(LOG_ERROR, "restart_job: got a printer-uri attribute but no job-id!"); | |
2687 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2688 | return; | |
2689 | } | |
2690 | ||
2691 | jobid = attr->values[0].integer; | |
2692 | } | |
2693 | else | |
2694 | { | |
2695 | /* | |
2696 | * Got a job URI; parse it to get the job ID... | |
2697 | */ | |
2698 | ||
2699 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
2700 | ||
2701 | if (strncmp(resource, "/jobs/", 6) != 0) | |
2702 | { | |
2703 | /* | |
2704 | * Not a valid URI! | |
2705 | */ | |
2706 | ||
2707 | LogMessage(LOG_ERROR, "restart_job: bad job-uri attribute \'%s\'!", | |
2708 | uri->values[0].string.text); | |
2709 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2710 | return; | |
2711 | } | |
2712 | ||
2713 | jobid = atoi(resource + 6); | |
2714 | } | |
2715 | ||
2716 | /* | |
2717 | * See if the job exists... | |
2718 | */ | |
2719 | ||
2720 | if ((job = FindJob(jobid)) == NULL) | |
2721 | { | |
2722 | /* | |
2723 | * Nope - return a "not found" error... | |
2724 | */ | |
2725 | ||
2726 | LogMessage(LOG_ERROR, "restart_job: job #%d doesn't exist!", jobid); | |
2727 | send_ipp_error(con, IPP_NOT_FOUND); | |
2728 | return; | |
2729 | } | |
2730 | ||
2731 | /* | |
2732 | * See if the job is owned by the requesting user... | |
2733 | */ | |
2734 | ||
2735 | if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) | |
2736 | { | |
2737 | strncpy(username, attr->values[0].string.text, sizeof(username) - 1); | |
2738 | username[sizeof(username) - 1] = '\0'; | |
2739 | } | |
2740 | else if (con->username[0]) | |
2741 | strcpy(username, con->username); | |
2742 | else | |
2743 | username[0] = '\0'; | |
2744 | ||
2745 | if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) | |
2746 | { | |
2747 | /* | |
2748 | * Not the owner or root; check to see if the user is a member of the | |
2749 | * system group... | |
2750 | */ | |
2751 | ||
2752 | user = getpwnam(username); | |
2753 | endpwent(); | |
2754 | ||
2755 | group = getgrnam(SystemGroup); | |
2756 | endgrent(); | |
2757 | ||
2758 | if (group != NULL) | |
2759 | for (i = 0; group->gr_mem[i]; i ++) | |
2760 | if (strcmp(username, group->gr_mem[i]) == 0) | |
2761 | break; | |
2762 | ||
2763 | if (user == NULL || group == NULL || | |
2764 | (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) | |
2765 | { | |
2766 | /* | |
2767 | * Username not found, group not found, or user is not part of the | |
2768 | * system group... | |
2769 | */ | |
2770 | ||
2771 | LogMessage(LOG_ERROR, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!", | |
2772 | username, jobid, job->username); | |
2773 | send_ipp_error(con, IPP_FORBIDDEN); | |
2774 | return; | |
2775 | } | |
2776 | } | |
2777 | ||
2778 | /* | |
2779 | * Restart the job and return... | |
2780 | */ | |
2781 | ||
2782 | RestartJob(jobid); | |
2783 | ||
2784 | LogMessage(LOG_INFO, "Job %d was restarted by \'%s\'.", jobid, | |
2785 | con->username[0] ? con->username : "unknown"); | |
2786 | ||
2787 | con->response->request.status.status_code = IPP_OK; | |
2788 | } | |
2789 | ||
2790 | ||
2791 | /* | |
2792 | * 'send_document()' - Send a file to a printer or class. | |
2793 | */ | |
2794 | ||
2795 | static void | |
2796 | send_document(client_t *con, /* I - Client connection */ | |
2797 | ipp_attribute_t *uri) /* I - Printer URI */ | |
2798 | { | |
e09246c8 | 2799 | int i; /* Looping var */ |
bd84e0d1 | 2800 | ipp_attribute_t *attr; /* Current attribute */ |
2801 | ipp_attribute_t *format; /* Document-format attribute */ | |
bd84e0d1 | 2802 | int jobid; /* Job ID number */ |
2803 | job_t *job; /* Current job */ | |
2804 | char job_uri[HTTP_MAX_URI], | |
2805 | /* Job URI */ | |
2806 | method[HTTP_MAX_URI], | |
2807 | /* Method portion of URI */ | |
2808 | username[HTTP_MAX_URI], | |
2809 | /* Username portion of URI */ | |
2810 | host[HTTP_MAX_URI], | |
2811 | /* Host portion of URI */ | |
2812 | resource[HTTP_MAX_URI]; | |
2813 | /* Resource portion of URI */ | |
2814 | int port; /* Port portion of URI */ | |
2815 | mime_type_t *filetype, /* Type of file */ | |
2816 | **filetypes; /* File types array */ | |
2817 | char super[MIME_MAX_SUPER], | |
2818 | /* Supertype of file */ | |
2819 | type[MIME_MAX_TYPE], | |
2820 | /* Subtype of file */ | |
2821 | mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; | |
2822 | /* Textual name of mime type */ | |
2823 | printer_t *printer; /* Printer data */ | |
e09246c8 | 2824 | struct passwd *user; /* User info */ |
2825 | struct group *group; /* System group info */ | |
2826 | char filename[1024]; /* Job filename */ | |
bd84e0d1 | 2827 | |
2828 | ||
2829 | DEBUG_printf(("send_document(%08x, %08x)\n", con, uri)); | |
2830 | ||
2831 | /* | |
2832 | * Verify that the POST operation was done to a valid URI. | |
2833 | */ | |
2834 | ||
2835 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
2836 | strncmp(con->uri, "/jobs/", 6) != 0 && | |
2837 | strncmp(con->uri, "/printers/", 10) != 0) | |
2838 | { | |
2839 | LogMessage(LOG_ERROR, "send_document: print request on bad resource \'%s\'!", | |
2840 | con->uri); | |
2841 | send_ipp_error(con, IPP_NOT_AUTHORIZED); | |
2842 | return; | |
2843 | } | |
2844 | ||
2845 | /* | |
2846 | * See if we have a job URI or a printer URI... | |
2847 | */ | |
2848 | ||
2849 | if (strcmp(uri->name, "printer-uri") == 0) | |
2850 | { | |
2851 | /* | |
2852 | * Got a printer URI; see if we also have a job-id attribute... | |
2853 | */ | |
2854 | ||
2855 | if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) | |
2856 | { | |
2857 | LogMessage(LOG_ERROR, "send_document: got a printer-uri attribute but no job-id!"); | |
2858 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2859 | return; | |
2860 | } | |
2861 | ||
2862 | jobid = attr->values[0].integer; | |
2863 | } | |
2864 | else | |
2865 | { | |
2866 | /* | |
2867 | * Got a job URI; parse it to get the job ID... | |
2868 | */ | |
2869 | ||
2870 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
2871 | ||
2872 | if (strncmp(resource, "/jobs/", 6) != 0) | |
2873 | { | |
2874 | /* | |
2875 | * Not a valid URI! | |
2876 | */ | |
2877 | ||
2878 | LogMessage(LOG_ERROR, "send_document: bad job-uri attribute \'%s\'!", | |
2879 | uri->values[0].string.text); | |
2880 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2881 | return; | |
2882 | } | |
2883 | ||
2884 | jobid = atoi(resource + 6); | |
2885 | } | |
2886 | ||
2887 | /* | |
2888 | * See if the job exists... | |
2889 | */ | |
2890 | ||
2891 | if ((job = FindJob(jobid)) == NULL) | |
2892 | { | |
2893 | /* | |
2894 | * Nope - return a "not found" error... | |
2895 | */ | |
2896 | ||
2897 | LogMessage(LOG_ERROR, "send_document: job #%d doesn't exist!", jobid); | |
2898 | send_ipp_error(con, IPP_NOT_FOUND); | |
2899 | return; | |
2900 | } | |
2901 | ||
2902 | /* | |
2903 | * See if the job is owned by the requesting user... | |
2904 | */ | |
2905 | ||
2906 | if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) | |
2907 | { | |
2908 | strncpy(username, attr->values[0].string.text, sizeof(username) - 1); | |
2909 | username[sizeof(username) - 1] = '\0'; | |
2910 | } | |
2911 | else if (con->username[0]) | |
2912 | strcpy(username, con->username); | |
2913 | else | |
2914 | username[0] = '\0'; | |
2915 | ||
2916 | if (strcmp(username, job->username) != 0 && strcmp(username, "root") != 0) | |
2917 | { | |
2918 | /* | |
2919 | * Not the owner or root; check to see if the user is a member of the | |
2920 | * system group... | |
2921 | */ | |
2922 | ||
2923 | user = getpwnam(username); | |
2924 | endpwent(); | |
2925 | ||
2926 | group = getgrnam(SystemGroup); | |
2927 | endgrent(); | |
2928 | ||
2929 | if (group != NULL) | |
2930 | for (i = 0; group->gr_mem[i]; i ++) | |
2931 | if (strcmp(username, group->gr_mem[i]) == 0) | |
2932 | break; | |
2933 | ||
2934 | if (user == NULL || group == NULL || | |
2935 | (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid)) | |
2936 | { | |
2937 | /* | |
2938 | * Username not found, group not found, or user is not part of the | |
2939 | * system group... | |
2940 | */ | |
2941 | ||
2942 | LogMessage(LOG_ERROR, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!", | |
2943 | username, jobid, job->username); | |
2944 | send_ipp_error(con, IPP_FORBIDDEN); | |
2945 | return; | |
2946 | } | |
2947 | } | |
2948 | ||
2949 | /* | |
2950 | * OK, see if the client is sending the document compressed - CUPS | |
2951 | * doesn't support compression yet... | |
2952 | */ | |
2953 | ||
2954 | if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) | |
2955 | { | |
2956 | LogMessage(LOG_ERROR, "send_document: Unsupported compression attribute!"); | |
2957 | send_ipp_error(con, IPP_ATTRIBUTES); | |
2958 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, | |
2959 | "compression", NULL, attr->values[0].string.text); | |
2960 | return; | |
2961 | } | |
2962 | ||
2963 | /* | |
2964 | * Do we have a file to print? | |
2965 | */ | |
2966 | ||
2967 | if (con->filename[0] == '\0') | |
2968 | { | |
2969 | LogMessage(LOG_ERROR, "send_document: No file!?!"); | |
2970 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2971 | return; | |
2972 | } | |
2973 | ||
2974 | /* | |
2975 | * Is it a format we support? | |
2976 | */ | |
2977 | ||
2978 | if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) | |
2979 | { | |
2980 | /* | |
2981 | * Grab format from client... | |
2982 | */ | |
2983 | ||
2984 | if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) | |
2985 | { | |
2986 | LogMessage(LOG_ERROR, "send_document: could not scan type \'%s\'!", | |
2987 | format->values[0].string.text); | |
2988 | send_ipp_error(con, IPP_BAD_REQUEST); | |
2989 | return; | |
2990 | } | |
2991 | } | |
2992 | else | |
2993 | { | |
2994 | /* | |
2995 | * No document format attribute? Auto-type it! | |
2996 | */ | |
2997 | ||
2998 | strcpy(super, "application"); | |
2999 | strcpy(type, "octet-stream"); | |
3000 | } | |
3001 | ||
3002 | if (strcmp(super, "application") == 0 && | |
3003 | strcmp(type, "octet-stream") == 0) | |
3004 | { | |
3005 | /* | |
3006 | * Auto-type the file... | |
3007 | */ | |
3008 | ||
3009 | LogMessage(LOG_DEBUG, "send_document: auto-typing file..."); | |
3010 | ||
3011 | filetype = mimeFileType(MimeDatabase, con->filename); | |
3012 | ||
3013 | if (filetype != NULL) | |
3014 | { | |
3015 | /* | |
3016 | * Replace the document-format attribute value with the auto-typed one. | |
3017 | */ | |
3018 | ||
3019 | sprintf(mimetype, "%s/%s", filetype->super, filetype->type); | |
3020 | ||
3021 | if (format != NULL) | |
3022 | { | |
3023 | free(format->values[0].string.text); | |
3024 | format->values[0].string.text = strdup(mimetype); | |
3025 | } | |
3026 | else | |
3027 | ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, | |
3028 | "document-format", NULL, mimetype); | |
3029 | } | |
3030 | } | |
3031 | else | |
3032 | filetype = mimeType(MimeDatabase, super, type); | |
3033 | ||
3034 | if (filetype == NULL) | |
3035 | { | |
3036 | LogMessage(LOG_ERROR, "send_document: Unsupported format \'%s\'!", | |
3037 | format->values[0].string.text); | |
3038 | send_ipp_error(con, IPP_DOCUMENT_FORMAT); | |
3039 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, | |
3040 | "document-format", NULL, format->values[0].string.text); | |
3041 | return; | |
3042 | } | |
3043 | ||
3044 | LogMessage(LOG_DEBUG, "send_document: request file type is %s/%s.", | |
3045 | filetype->super, filetype->type); | |
3046 | ||
3047 | /* | |
3048 | * Add the file to the job... | |
3049 | */ | |
3050 | ||
3051 | if (job->num_files == 0) | |
e09246c8 | 3052 | filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *)); |
bd84e0d1 | 3053 | else |
e09246c8 | 3054 | filetypes = (mime_type_t **)realloc(job->filetypes, |
bd84e0d1 | 3055 | (job->num_files + 1) * |
e09246c8 | 3056 | sizeof(mime_type_t)); |
bd84e0d1 | 3057 | |
3058 | if (filetypes == NULL) | |
3059 | { | |
3060 | CancelJob(job->id); | |
3061 | LogMessage(LOG_ERROR, "send_document: unable to allocate memory for file types!"); | |
3062 | send_ipp_error(con, IPP_INTERNAL_ERROR); | |
3063 | return; | |
3064 | } | |
3065 | ||
3066 | job->filetypes = filetypes; | |
3067 | job->filetypes[job->num_files] = filetype; | |
3068 | ||
3069 | job->num_files ++; | |
3070 | sprintf(filename, "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); | |
3071 | rename(con->filename, filename); | |
3072 | ||
bd84e0d1 | 3073 | con->filename[0] = '\0'; |
3074 | ||
3075 | LogMessage(LOG_INFO, "File queued in job #%d by \'%s\'.", job->id, | |
3076 | job->username); | |
3077 | ||
1049abbe | 3078 | /* |
3079 | * Start the job if this is the last document... | |
3080 | */ | |
3081 | ||
3082 | if ((attr = ippFindAttribute(con->request, "last-document", IPP_TAG_BOOLEAN)) != NULL && | |
3083 | attr->values[0].boolean) | |
3084 | { | |
3085 | job->state->values[0].integer = IPP_JOB_PENDING; | |
3086 | CheckJobs(); | |
3087 | } | |
3088 | ||
bd84e0d1 | 3089 | /* |
3090 | * Fill in the response info... | |
3091 | */ | |
3092 | ||
3093 | sprintf(job_uri, "http://%s:%d/jobs/%d", ServerName, | |
3094 | ntohs(con->http.hostaddr.sin_port), job->id); | |
1049abbe | 3095 | ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, |
3096 | job_uri); | |
bd84e0d1 | 3097 | |
3098 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); | |
3099 | ||
1049abbe | 3100 | ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", |
3101 | job->state->values[0].integer); | |
bd84e0d1 | 3102 | |
3103 | con->response->request.status.status_code = IPP_OK; | |
3104 | } | |
3105 | ||
3106 | ||
e31bfb6e | 3107 | /* |
3108 | * 'send_ipp_error()' - Send an error status back to the IPP client. | |
3109 | */ | |
3110 | ||
3111 | static void | |
3112 | send_ipp_error(client_t *con, /* I - Client connection */ | |
3113 | ipp_status_t status) /* I - IPP status code */ | |
3114 | { | |
e31bfb6e | 3115 | DEBUG_printf(("send_ipp_error(%08x, %04x)\n", con, status)); |
3116 | ||
1917e0e9 | 3117 | LogMessage(LOG_DEBUG, "Sending IPP error code %x.", status); |
e31bfb6e | 3118 | if (con->filename[0]) |
3119 | unlink(con->filename); | |
3120 | ||
3121 | con->response->request.status.status_code = status; | |
e31bfb6e | 3122 | } |
3123 | ||
3124 | ||
3270670b | 3125 | /* |
3126 | * 'set_default()' - Set the default destination... | |
3127 | */ | |
3128 | ||
3129 | static void | |
3130 | set_default(client_t *con, /* I - Client connection */ | |
3131 | ipp_attribute_t *uri) /* I - Printer URI */ | |
3132 | { | |
3133 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
3134 | char method[HTTP_MAX_URI], | |
3135 | /* Method portion of URI */ | |
3136 | username[HTTP_MAX_URI], | |
3137 | /* Username portion of URI */ | |
3138 | host[HTTP_MAX_URI], | |
3139 | /* Host portion of URI */ | |
3140 | resource[HTTP_MAX_URI]; | |
3141 | /* Resource portion of URI */ | |
3142 | int port; /* Port portion of URI */ | |
1049abbe | 3143 | const char *name; /* Printer name */ |
3270670b | 3144 | |
3145 | ||
3146 | DEBUG_printf(("set_default(%08x, %08x)\n", con, uri)); | |
3147 | ||
3148 | /* | |
3149 | * Was this operation called from the correct URI? | |
3150 | */ | |
3151 | ||
3152 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
3153 | { | |
1917e0e9 | 3154 | LogMessage(LOG_ERROR, "set_default: admin request on bad resource \'%s\'!", |
1124e9ec | 3155 | con->uri); |
3270670b | 3156 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
3157 | return; | |
3158 | } | |
3159 | ||
3160 | /* | |
3161 | * Is the destination valid? | |
3162 | */ | |
3163 | ||
3164 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
3165 | ||
1049abbe | 3166 | if ((name = ValidateDest(resource, &dtype)) == NULL) |
3270670b | 3167 | { |
3168 | /* | |
3169 | * Bad URI... | |
3170 | */ | |
3171 | ||
1917e0e9 | 3172 | LogMessage(LOG_ERROR, "set_default: resource name \'%s\' no good!", resource); |
3270670b | 3173 | send_ipp_error(con, IPP_NOT_FOUND); |
3174 | return; | |
3175 | } | |
3176 | ||
3177 | /* | |
3178 | * Set it as the default... | |
3179 | */ | |
3180 | ||
3181 | if (dtype == CUPS_PRINTER_CLASS) | |
3182 | DefaultPrinter = FindClass(name); | |
3183 | else | |
3184 | DefaultPrinter = FindPrinter(name); | |
3185 | ||
cc0561c6 | 3186 | SaveAllPrinters(); |
3187 | SaveAllClasses(); | |
3188 | ||
3189 | LogMessage(LOG_INFO, "Default destination set to \'%s\' by \'%s\'.", name, | |
3190 | con->username); | |
3191 | ||
3270670b | 3192 | /* |
3193 | * Everything was ok, so return OK status... | |
3194 | */ | |
3195 | ||
3196 | con->response->request.status.status_code = IPP_OK; | |
3197 | } | |
3198 | ||
3199 | ||
f3d580b9 | 3200 | /* |
3201 | * 'start_printer()' - Start a printer. | |
3202 | */ | |
3203 | ||
3204 | static void | |
3205 | start_printer(client_t *con, /* I - Client connection */ | |
3206 | ipp_attribute_t *uri) /* I - Printer URI */ | |
3207 | { | |
3208 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
3209 | char method[HTTP_MAX_URI], | |
3210 | /* Method portion of URI */ | |
3211 | username[HTTP_MAX_URI], | |
3212 | /* Username portion of URI */ | |
3213 | host[HTTP_MAX_URI], | |
3214 | /* Host portion of URI */ | |
3215 | resource[HTTP_MAX_URI]; | |
3216 | /* Resource portion of URI */ | |
3217 | int port; /* Port portion of URI */ | |
1049abbe | 3218 | const char *name; /* Printer name */ |
f3d580b9 | 3219 | printer_t *printer; /* Printer data */ |
3220 | ||
3270670b | 3221 | |
f3d580b9 | 3222 | DEBUG_printf(("start_printer(%08x, %08x)\n", con, uri)); |
3223 | ||
3224 | /* | |
3225 | * Was this operation called from the correct URI? | |
3226 | */ | |
3227 | ||
3228 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
3229 | { | |
1917e0e9 | 3230 | LogMessage(LOG_ERROR, "start_printer: admin request on bad resource \'%s\'!", |
1124e9ec | 3231 | con->uri); |
f3d580b9 | 3232 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
3233 | return; | |
3234 | } | |
3235 | ||
3236 | /* | |
3237 | * Is the destination valid? | |
3238 | */ | |
3239 | ||
3240 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
3241 | ||
1049abbe | 3242 | if ((name = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 3243 | { |
3244 | /* | |
3245 | * Bad URI... | |
3246 | */ | |
3247 | ||
1917e0e9 | 3248 | LogMessage(LOG_ERROR, "start_printer: resource name \'%s\' no good!", resource); |
f3d580b9 | 3249 | send_ipp_error(con, IPP_NOT_FOUND); |
3250 | return; | |
3251 | } | |
3252 | ||
3253 | /* | |
3254 | * Start the printer... | |
3255 | */ | |
3256 | ||
cbbfcc63 | 3257 | if (dtype == CUPS_PRINTER_CLASS) |
3258 | printer = FindClass(name); | |
3259 | else | |
3260 | printer = FindPrinter(name); | |
f3d580b9 | 3261 | |
3262 | StartPrinter(printer); | |
3263 | ||
cc0561c6 | 3264 | if (dtype == CUPS_PRINTER_CLASS) |
3265 | SaveAllClasses(); | |
3266 | else | |
3267 | SaveAllPrinters(); | |
3268 | ||
3269 | if (dtype == CUPS_PRINTER_CLASS) | |
3270 | LogMessage(LOG_INFO, "Class \'%s\' started by \'%s\'.", name, | |
3271 | con->username); | |
3272 | else | |
3273 | LogMessage(LOG_INFO, "Printer \'%s\' started by \'%s\'.", name, | |
3274 | con->username); | |
3275 | ||
f3d580b9 | 3276 | printer->state_message[0] = '\0'; |
3277 | ||
3278 | /* | |
3279 | * Everything was ok, so return OK status... | |
3280 | */ | |
3281 | ||
3282 | con->response->request.status.status_code = IPP_OK; | |
3283 | } | |
3284 | ||
3285 | ||
3286 | /* | |
3287 | * 'stop_printer()' - Stop a printer. | |
3288 | */ | |
3289 | ||
3290 | static void | |
3291 | stop_printer(client_t *con, /* I - Client connection */ | |
3292 | ipp_attribute_t *uri) /* I - Printer URI */ | |
3293 | { | |
3294 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
3295 | char method[HTTP_MAX_URI], | |
3296 | /* Method portion of URI */ | |
3297 | username[HTTP_MAX_URI], | |
3298 | /* Username portion of URI */ | |
3299 | host[HTTP_MAX_URI], | |
3300 | /* Host portion of URI */ | |
3301 | resource[HTTP_MAX_URI]; | |
3302 | /* Resource portion of URI */ | |
3303 | int port; /* Port portion of URI */ | |
1049abbe | 3304 | const char *name; /* Printer name */ |
f3d580b9 | 3305 | printer_t *printer; /* Printer data */ |
3306 | ipp_attribute_t *attr; /* printer-state-message attribute */ | |
3307 | ||
3308 | ||
3309 | DEBUG_printf(("stop_printer(%08x, %08x)\n", con, uri)); | |
3310 | ||
3311 | /* | |
3312 | * Was this operation called from the correct URI? | |
3313 | */ | |
3314 | ||
3315 | if (strncmp(con->uri, "/admin/", 7) != 0) | |
3316 | { | |
1917e0e9 | 3317 | LogMessage(LOG_ERROR, "stop_printer: admin request on bad resource \'%s\'!", |
1124e9ec | 3318 | con->uri); |
f3d580b9 | 3319 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
3320 | return; | |
3321 | } | |
3322 | ||
3323 | /* | |
3324 | * Is the destination valid? | |
3325 | */ | |
3326 | ||
3327 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); | |
3328 | ||
1049abbe | 3329 | if ((name = ValidateDest(resource, &dtype)) == NULL) |
f3d580b9 | 3330 | { |
3331 | /* | |
3332 | * Bad URI... | |
3333 | */ | |
3334 | ||
1917e0e9 | 3335 | LogMessage(LOG_ERROR, "stop_printer: resource name \'%s\' no good!", resource); |
f3d580b9 | 3336 | send_ipp_error(con, IPP_NOT_FOUND); |
3337 | return; | |
3338 | } | |
3339 | ||
3340 | /* | |
3341 | * Stop the printer... | |
3342 | */ | |
3343 | ||
cbbfcc63 | 3344 | if (dtype == CUPS_PRINTER_CLASS) |
3345 | printer = FindClass(name); | |
3346 | else | |
3347 | printer = FindPrinter(name); | |
f3d580b9 | 3348 | |
3349 | StopPrinter(printer); | |
3350 | ||
cc0561c6 | 3351 | if (dtype == CUPS_PRINTER_CLASS) |
3352 | SaveAllClasses(); | |
3353 | else | |
3354 | SaveAllPrinters(); | |
3355 | ||
f3d580b9 | 3356 | if ((attr = ippFindAttribute(con->request, "printer-state-message", |
3357 | IPP_TAG_TEXT)) == NULL) | |
3358 | strcpy(printer->state_message, "Paused"); | |
3359 | else | |
970017a4 | 3360 | { |
3361 | strncpy(printer->state_message, attr->values[0].string.text, | |
3362 | sizeof(printer->state_message) - 1); | |
3363 | printer->state_message[sizeof(printer->state_message) - 1] = '\0'; | |
3364 | } | |
f3d580b9 | 3365 | |
cc0561c6 | 3366 | if (dtype == CUPS_PRINTER_CLASS) |
3367 | LogMessage(LOG_INFO, "Class \'%s\' stopped by \'%s\'.", name, | |
3368 | con->username); | |
3369 | else | |
3370 | LogMessage(LOG_INFO, "Printer \'%s\' stopped by \'%s\'.", name, | |
3371 | con->username); | |
3372 | ||
f3d580b9 | 3373 | /* |
3374 | * Everything was ok, so return OK status... | |
3375 | */ | |
3376 | ||
3377 | con->response->request.status.status_code = IPP_OK; | |
3378 | } | |
3379 | ||
3380 | ||
1d2c70a6 | 3381 | /* |
3382 | * 'validate_job()' - Validate printer options and destination. | |
3383 | */ | |
3384 | ||
e31bfb6e | 3385 | static void |
1d2c70a6 | 3386 | validate_job(client_t *con, /* I - Client connection */ |
3387 | ipp_attribute_t *uri) /* I - Printer URI */ | |
e31bfb6e | 3388 | { |
1d2c70a6 | 3389 | ipp_attribute_t *attr; /* Current attribute */ |
3390 | ipp_attribute_t *format; /* Document-format attribute */ | |
3391 | cups_ptype_t dtype; /* Destination type (printer or class) */ | |
3392 | char method[HTTP_MAX_URI], | |
3393 | /* Method portion of URI */ | |
3394 | username[HTTP_MAX_URI], | |
3395 | /* Username portion of URI */ | |
3396 | host[HTTP_MAX_URI], | |
3397 | /* Host portion of URI */ | |
3398 | resource[HTTP_MAX_URI]; | |
3399 | /* Resource portion of URI */ | |
3400 | int port; /* Port portion of URI */ | |
3401 | char super[MIME_MAX_SUPER], | |
3402 | /* Supertype of file */ | |
3403 | type[MIME_MAX_TYPE]; | |
3404 | /* Subtype of file */ | |
3405 | ||
3406 | ||
3407 | DEBUG_printf(("validate_job(%08x, %08x)\n", con, uri)); | |
3408 | ||
2aeb2b1d | 3409 | /* |
3410 | * Verify that the POST operation was done to a valid URI. | |
3411 | */ | |
3412 | ||
3413 | if (strncmp(con->uri, "/classes/", 9) != 0 && | |
3414 | strncmp(con->uri, "/printers/", 10) != 0) | |
3415 | { | |
3416 | LogMessage(LOG_ERROR, "validate_job: request on bad resource \'%s\'!", | |
1124e9ec | 3417 | con->uri); |
2aeb2b1d | 3418 | send_ipp_error(con, IPP_NOT_AUTHORIZED); |
3419 | return; | |
3420 | } | |
3421 | ||
1d2c70a6 | 3422 | /* |
3423 | * OK, see if the client is sending the document compressed - CUPS | |
3424 | * doesn't support compression yet... | |
3425 | */ | |
3426 | ||
c0341b41 | 3427 | if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) |
1d2c70a6 | 3428 | { |
bd84e0d1 | 3429 | LogMessage(LOG_ERROR, "validate_job: Unsupported compression attribute!"); |
1d2c70a6 | 3430 | send_ipp_error(con, IPP_ATTRIBUTES); |
bd84e0d1 | 3431 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, |
3432 | "compression", NULL, attr->values[0].string.text); | |
1d2c70a6 | 3433 | return; |
3434 | } | |
3435 | ||
3436 | /* | |
3437 | * Is it a format we support? | |
3438 | */ | |
3439 | ||
c0341b41 | 3440 | if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) == NULL) |
1d2c70a6 | 3441 | { |
e09246c8 | 3442 | LogMessage(LOG_ERROR, "validate_job: missing document-format attribute!"); |
1d2c70a6 | 3443 | send_ipp_error(con, IPP_BAD_REQUEST); |
3444 | return; | |
3445 | } | |
3446 | ||
c0341b41 | 3447 | if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2) |
1d2c70a6 | 3448 | { |
bd84e0d1 | 3449 | LogMessage(LOG_ERROR, "validate_job: could not scan type \'%s\'!\n", |
3450 | format->values[0].string.text); | |
1d2c70a6 | 3451 | send_ipp_error(con, IPP_BAD_REQUEST); |
3452 | return; | |
3453 | } | |
3454 | ||
3455 | if ((strcmp(super, "application") != 0 || | |
3456 | strcmp(type, "octet-stream") != 0) && | |
3457 | mimeType(MimeDatabase, super, type) == NULL) | |
3458 | { | |
bd84e0d1 | 3459 | LogMessage(LOG_ERROR, "validate_job: Unsupported format \'%s\'!\n", |
3460 | format->values[0].string.text); | |
1d2c70a6 | 3461 | send_ipp_error(con, IPP_DOCUMENT_FORMAT); |
bd84e0d1 | 3462 | ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, |
3463 | "document-format", NULL, format->values[0].string.text); | |
1d2c70a6 | 3464 | return; |
3465 | } | |
3466 | ||
3467 | /* | |
3468 | * Is the destination valid? | |
3469 | */ | |
3470 | ||
c0341b41 | 3471 | httpSeparate(uri->values[0].string.text, method, username, host, &port, resource); |
1d2c70a6 | 3472 | |
1049abbe | 3473 | if (ValidateDest(resource, &dtype) == NULL) |
1d2c70a6 | 3474 | { |
3475 | /* | |
3476 | * Bad URI... | |
3477 | */ | |
3478 | ||
1917e0e9 | 3479 | LogMessage(LOG_ERROR, "validate_job: resource name \'%s\' no good!", resource); |
1d2c70a6 | 3480 | send_ipp_error(con, IPP_NOT_FOUND); |
3481 | return; | |
3482 | } | |
3483 | ||
3484 | /* | |
3485 | * Everything was ok, so return OK status... | |
3486 | */ | |
3487 | ||
3488 | con->response->request.status.status_code = IPP_OK; | |
e31bfb6e | 3489 | } |
3490 | ||
3491 | ||
3492 | /* | |
71fe22b7 | 3493 | * End of "$Id: ipp.c,v 1.41 2000/01/04 13:46:09 mike Exp $". |
e31bfb6e | 3494 | */ |