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