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