]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
Load cups into easysw/current.
[thirdparty/cups.git] / cgi-bin / admin.c
1 /*
2 * "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $"
3 *
4 * Administration CGI for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Main entry for CGI.
27 * compare_printer_devices() - Compare two printer devices.
28 * do_am_class() - Add or modify a class.
29 * do_am_printer() - Add or modify a printer.
30 * do_config_printer() - Configure the default options for a printer.
31 * do_config_server() - Configure server settings.
32 * do_delete_class() - Delete a class...
33 * do_delete_printer() - Delete a printer...
34 * do_menu() - Show the main menu...
35 * do_printer_op() - Do a printer operation.
36 * do_set_allowed_users() - Set the allowed/denied users for a queue.
37 * do_set_sharing() - Set printer-is-shared value...
38 * match_string() - Return the number of matching characters.
39 */
40
41 /*
42 * Include necessary headers...
43 */
44
45 #include "cgi-private.h"
46 #include <cups/file.h>
47 #include <errno.h>
48
49
50 /*
51 * Local functions...
52 */
53
54 static void do_am_class(http_t *http, cups_lang_t *language, int modify);
55 static void do_am_printer(http_t *http, cups_lang_t *language, int modify);
56 static void do_config_printer(http_t *http, cups_lang_t *language);
57 static void do_config_server(http_t *http, cups_lang_t *language);
58 static void do_delete_class(http_t *http, cups_lang_t *language);
59 static void do_delete_printer(http_t *http, cups_lang_t *language);
60 static void do_menu(http_t *http, cups_lang_t *language);
61 static void do_printer_op(http_t *http, cups_lang_t *language,
62 ipp_op_t op, const char *title);
63 static void do_set_allowed_users(http_t *http, cups_lang_t *language);
64 static void do_set_sharing(http_t *http, cups_lang_t *language);
65 static int match_string(const char *a, const char *b);
66
67
68 /*
69 * 'main()' - Main entry for CGI.
70 */
71
72 int /* O - Exit status */
73 main(int argc, /* I - Number of command-line arguments */
74 char *argv[]) /* I - Command-line arguments */
75 {
76 cups_lang_t *language; /* Language information */
77 http_t *http; /* Connection to the server */
78 const char *op; /* Operation name */
79
80
81 /*
82 * Get the request language...
83 */
84
85 language = cupsLangDefault();
86
87 /*
88 * Connect to the HTTP server...
89 */
90
91 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
92
93 /*
94 * Set the web interface section...
95 */
96
97 cgiSetVariable("SECTION", "admin");
98
99 /*
100 * See if we have form data...
101 */
102
103 if (!cgiInitialize())
104 {
105 /*
106 * Nope, send the administration menu...
107 */
108
109 do_menu(http, language);
110 }
111 else if ((op = cgiGetVariable("OP")) != NULL)
112 {
113 /*
114 * Do the operation...
115 */
116
117 if (!strcmp(op, "redirect"))
118 {
119 const char *url; /* Redirection URL... */
120
121
122 if ((url = cgiGetVariable("URL")) != NULL)
123 printf("Location: %s\n\n", url);
124 else
125 puts("Location: /admin\n");
126 }
127 else if (!strcmp(op, "start-printer"))
128 do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Printer");
129 else if (!strcmp(op, "stop-printer"))
130 do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Printer");
131 else if (!strcmp(op, "start-class"))
132 do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Class");
133 else if (!strcmp(op, "stop-class"))
134 do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Class");
135 else if (!strcmp(op, "accept-jobs"))
136 do_printer_op(http, language, CUPS_ACCEPT_JOBS, "Accept Jobs");
137 else if (!strcmp(op, "reject-jobs"))
138 do_printer_op(http, language, CUPS_REJECT_JOBS, "Reject Jobs");
139 else if (!strcmp(op, "purge-jobs"))
140 do_printer_op(http, language, IPP_PURGE_JOBS, "Purge Jobs");
141 else if (!strcmp(op, "set-allowed-users"))
142 do_set_allowed_users(http, language);
143 else if (!strcmp(op, "set-as-default"))
144 do_printer_op(http, language, CUPS_SET_DEFAULT, "Set As Default");
145 else if (!strcmp(op, "set-sharing"))
146 do_set_sharing(http, language);
147 else if (!strcmp(op, "add-class"))
148 do_am_class(http, language, 0);
149 else if (!strcmp(op, "add-printer"))
150 do_am_printer(http, language, 0);
151 else if (!strcmp(op, "modify-class"))
152 do_am_class(http, language, 1);
153 else if (!strcmp(op, "modify-printer"))
154 do_am_printer(http, language, 1);
155 else if (!strcmp(op, "delete-class"))
156 do_delete_class(http, language);
157 else if (!strcmp(op, "delete-printer"))
158 do_delete_printer(http, language);
159 else if (!strcmp(op, "set-printer-options"))
160 do_config_printer(http, language);
161 else if (!strcmp(op, "config-server"))
162 do_config_server(http, language);
163 else
164 {
165 /*
166 * Bad operation code... Display an error...
167 */
168
169 cgiStartHTML("Error");
170 cgiCopyTemplateLang("admin-op.tmpl");
171 cgiEndHTML();
172 }
173
174 /*
175 * Close the HTTP server connection...
176 */
177
178 httpClose(http);
179 }
180 else
181 {
182 /*
183 * Form data but no operation code... Display an error...
184 */
185
186 cgiStartHTML("Error");
187 cgiCopyTemplateLang("admin-op.tmpl");
188 cgiEndHTML();
189 }
190
191 /*
192 * Free the request language...
193 */
194
195 cupsLangFree(language);
196
197 /*
198 * Return with no errors...
199 */
200
201 return (0);
202 }
203
204
205 /*
206 * 'compare_printer_devices()' - Compare two printer devices.
207 */
208
209 static int /* O - Result of comparison */
210 compare_printer_devices(const void *a, /* I - First device */
211 const void *b) /* I - Second device */
212 {
213 return (strcmp(*((char **)a), *((char **)b)));
214 }
215
216
217 /*
218 * 'do_am_class()' - Add or modify a class.
219 */
220
221 static void
222 do_am_class(http_t *http, /* I - HTTP connection */
223 cups_lang_t *language, /* I - Client's language */
224 int modify) /* I - Modify the printer? */
225 {
226 int i, j; /* Looping vars */
227 int element; /* Element number */
228 int num_printers; /* Number of printers */
229 ipp_t *request, /* IPP request */
230 *response; /* IPP response */
231 ipp_attribute_t *attr; /* member-uris attribute */
232 ipp_status_t status; /* Request status */
233 char uri[HTTP_MAX_URI]; /* Device or printer URI */
234 const char *name, /* Pointer to class name */
235 *ptr; /* Pointer to CGI variable */
236 const char *title; /* Title of page */
237 static const char * const pattrs[] = /* Requested printer attributes */
238 {
239 "member-names",
240 "printer-info",
241 "printer-location"
242 };
243
244
245 title = modify ? "Modify Class" : "Add Class";
246 name = cgiGetVariable("PRINTER_NAME");
247
248 if (cgiGetVariable("PRINTER_LOCATION") == NULL)
249 {
250 /*
251 * Build a CUPS_GET_PRINTERS request, which requires the
252 * following attributes:
253 *
254 * attributes-charset
255 * attributes-natural-language
256 * printer-uri
257 */
258
259 request = ippNew();
260
261 request->request.op.operation_id = CUPS_GET_PRINTERS;
262 request->request.op.request_id = 1;
263
264 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
265 "attributes-charset", NULL, cupsLangEncoding(language));
266
267 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
268 "attributes-natural-language", NULL, language->language);
269
270 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
271 NULL, "ipp://localhost/printers");
272
273 /*
274 * Do the request and get back a response...
275 */
276
277 if ((response = cupsDoRequest(http, request, "/")) != NULL)
278 {
279 /*
280 * Create MEMBER_URIS and MEMBER_NAMES arrays...
281 */
282
283 for (element = 0, attr = response->attrs;
284 attr != NULL;
285 attr = attr->next)
286 if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
287 {
288 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
289 (!name || strcasecmp(name, ptr + 1)))
290 {
291 /*
292 * Don't show the current class...
293 */
294
295 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
296 element ++;
297 }
298 }
299
300 for (element = 0, attr = response->attrs;
301 attr != NULL;
302 attr = attr->next)
303 if (attr->name && !strcmp(attr->name, "printer-name"))
304 {
305 if (!name || strcasecmp(name, attr->values[0].string.text))
306 {
307 /*
308 * Don't show the current class...
309 */
310
311 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
312 element ++;
313 }
314 }
315
316 num_printers = cgiGetSize("MEMBER_URIS");
317
318 ippDelete(response);
319 }
320 else
321 num_printers = 0;
322
323 if (modify)
324 {
325 /*
326 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
327 * following attributes:
328 *
329 * attributes-charset
330 * attributes-natural-language
331 * printer-uri
332 */
333
334 request = ippNew();
335
336 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
337 request->request.op.request_id = 1;
338
339 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
340 "attributes-charset", NULL, cupsLangEncoding(language));
341
342 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
343 "attributes-natural-language", NULL, language->language);
344
345 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
346 "/classes/%s", name);
347 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
348 NULL, uri);
349
350 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
351 "requested-attributes",
352 (int)(sizeof(pattrs) / sizeof(pattrs[0])),
353 NULL, pattrs);
354
355 /*
356 * Do the request and get back a response...
357 */
358
359 if ((response = cupsDoRequest(http, request, "/")) != NULL)
360 {
361 if ((attr = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != NULL)
362 {
363 /*
364 * Mark any current members in the class...
365 */
366
367 for (j = 0; j < num_printers; j ++)
368 cgiSetArray("MEMBER_SELECTED", j, "");
369
370 for (i = 0; i < attr->num_values; i ++)
371 {
372 for (j = 0; j < num_printers; j ++)
373 {
374 if (!strcasecmp(attr->values[i].string.text,
375 cgiGetArray("MEMBER_NAMES", j)))
376 {
377 cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
378 break;
379 }
380 }
381 }
382 }
383
384 if ((attr = ippFindAttribute(response, "printer-info",
385 IPP_TAG_TEXT)) != NULL)
386 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
387
388 if ((attr = ippFindAttribute(response, "printer-location",
389 IPP_TAG_TEXT)) != NULL)
390 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
391
392 ippDelete(response);
393 }
394
395 /*
396 * Update the location and description of an existing printer...
397 */
398
399 cgiStartHTML(title);
400 cgiCopyTemplateLang("modify-class.tmpl");
401 }
402 else
403 {
404 /*
405 * Get the name, location, and description for a new printer...
406 */
407
408 cgiStartHTML(title);
409 cgiCopyTemplateLang("add-class.tmpl");
410 }
411
412 cgiEndHTML();
413
414 return;
415 }
416
417 for (ptr = name; *ptr; ptr ++)
418 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
419 break;
420
421 if (*ptr || ptr == name || strlen(name) > 127)
422 {
423 cgiSetVariable("ERROR", "The class name may only contain up to 127 printable "
424 "characters and may not contain spaces, slashes (/), "
425 "or the pound sign (#).");
426 cgiStartHTML(title);
427 cgiCopyTemplateLang("error.tmpl");
428 cgiEndHTML();
429 return;
430 }
431
432 /*
433 * Build a CUPS_ADD_CLASS request, which requires the following
434 * attributes:
435 *
436 * attributes-charset
437 * attributes-natural-language
438 * printer-uri
439 * printer-location
440 * printer-info
441 * printer-is-accepting-jobs
442 * printer-state
443 * member-uris
444 */
445
446 request = ippNew();
447
448 request->request.op.operation_id = CUPS_ADD_CLASS;
449 request->request.op.request_id = 1;
450
451 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
452 "attributes-charset", NULL, cupsLangEncoding(language));
453
454 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
455 "attributes-natural-language", NULL, language->language);
456
457 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
458 "/classes/%s", cgiGetVariable("PRINTER_NAME"));
459 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
460 NULL, uri);
461
462 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
463 NULL, cgiGetVariable("PRINTER_LOCATION"));
464
465 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
466 NULL, cgiGetVariable("PRINTER_INFO"));
467
468 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
469
470 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
471 IPP_PRINTER_IDLE);
472
473 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
474 {
475 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
476 num_printers, NULL, NULL);
477 for (i = 0; i < num_printers; i ++)
478 attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i));
479 }
480
481 /*
482 * Do the request and get back a response...
483 */
484
485 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
486 {
487 status = response->request.status.status_code;
488 ippDelete(response);
489 }
490 else
491 status = cupsLastError();
492
493 if (status > IPP_OK_CONFLICT)
494 {
495 cgiStartHTML(title);
496 cgiSetVariable("ERROR", ippErrorString(status));
497 cgiCopyTemplateLang("error.tmpl");
498 }
499 else
500 {
501 /*
502 * Redirect successful updates back to the class page...
503 */
504
505 char refresh[1024]; /* Refresh URL */
506
507 cgiFormEncode(uri, name, sizeof(uri));
508 snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/classes/%s",
509 uri);
510 cgiSetVariable("refresh_page", refresh);
511
512 cgiStartHTML(title);
513
514 if (modify)
515 cgiCopyTemplateLang("class-modified.tmpl");
516 else
517 cgiCopyTemplateLang("class-added.tmpl");
518 }
519
520 cgiEndHTML();
521 }
522
523
524 /*
525 * 'do_am_printer()' - Add or modify a printer.
526 */
527
528 static void
529 do_am_printer(http_t *http, /* I - HTTP connection */
530 cups_lang_t *language, /* I - Client's language */
531 int modify) /* I - Modify the printer? */
532 {
533 int i; /* Looping var */
534 int element; /* Element number */
535 ipp_attribute_t *attr, /* Current attribute */
536 *last; /* Last attribute */
537 ipp_t *request, /* IPP request */
538 *response, /* IPP response */
539 *oldinfo; /* Old printer information */
540 ipp_status_t status; /* Request status */
541 const cgi_file_t *file; /* Uploaded file, if any */
542 const char *var; /* CGI variable */
543 char uri[HTTP_MAX_URI], /* Device or printer URI */
544 *uriptr; /* Pointer into URI */
545 int maxrate; /* Maximum baud rate */
546 char baudrate[255]; /* Baud rate string */
547 const char *name, /* Pointer to class name */
548 *ptr; /* Pointer to CGI variable */
549 const char *title; /* Title of page */
550 static int baudrates[] = /* Baud rates */
551 {
552 1200,
553 2400,
554 4800,
555 9600,
556 19200,
557 38400,
558 57600,
559 115200,
560 230400,
561 460800
562 };
563
564
565 title = modify ? "Modify Printer" : "Add Printer";
566
567 if (modify)
568 {
569 /*
570 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
571 * following attributes:
572 *
573 * attributes-charset
574 * attributes-natural-language
575 * printer-uri
576 */
577
578 request = ippNew();
579
580 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
581 request->request.op.request_id = 1;
582
583 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
584 "attributes-charset", NULL, cupsLangEncoding(language));
585
586 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
587 "attributes-natural-language", NULL, language->language);
588
589 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
590 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
591 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
592 NULL, uri);
593
594 /*
595 * Do the request and get back a response...
596 */
597
598 oldinfo = cupsDoRequest(http, request, "/");
599 }
600 else
601 oldinfo = NULL;
602
603 if ((name = cgiGetVariable("PRINTER_NAME")) == NULL ||
604 cgiGetVariable("PRINTER_LOCATION") == NULL)
605 {
606 cgiStartHTML(title);
607
608 if (modify)
609 {
610 /*
611 * Update the location and description of an existing printer...
612 */
613
614 if (oldinfo)
615 cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0);
616
617 cgiCopyTemplateLang("modify-printer.tmpl");
618 }
619 else
620 {
621 /*
622 * Get the name, location, and description for a new printer...
623 */
624
625 cgiCopyTemplateLang("add-printer.tmpl");
626 }
627
628 cgiEndHTML();
629
630 if (oldinfo)
631 ippDelete(oldinfo);
632
633 return;
634 }
635
636 for (ptr = name; *ptr; ptr ++)
637 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
638 break;
639
640 if (*ptr || ptr == name || strlen(name) > 127)
641 {
642 cgiSetVariable("ERROR", "The printer name may only contain up to 127 printable "
643 "characters and may not contain spaces, slashes (/), "
644 "or the pound sign (#).");
645 cgiStartHTML(title);
646 cgiCopyTemplateLang("error.tmpl");
647 cgiEndHTML();
648 return;
649 }
650
651 file = cgiGetFile();
652
653 if (file)
654 {
655 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
656 fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
657 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
658 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
659 }
660
661 if ((var = cgiGetVariable("DEVICE_URI")) == NULL)
662 {
663 /*
664 * Build a CUPS_GET_DEVICES request, which requires the following
665 * attributes:
666 *
667 * attributes-charset
668 * attributes-natural-language
669 * printer-uri
670 */
671
672 request = ippNew();
673
674 request->request.op.operation_id = CUPS_GET_DEVICES;
675 request->request.op.request_id = 1;
676
677 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
678 "attributes-charset", NULL, cupsLangEncoding(language));
679
680 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
681 "attributes-natural-language", NULL, language->language);
682
683 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
684 NULL, "ipp://localhost/printers/");
685
686 /*
687 * Do the request and get back a response...
688 */
689
690 if ((response = cupsDoRequest(http, request, "/")) != NULL)
691 {
692 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
693 ippDelete(response);
694 }
695
696 /*
697 * Let the user choose...
698 */
699
700 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
701 {
702 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
703 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
704 *uriptr = '\0';
705
706 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
707 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
708 }
709
710 cgiStartHTML(title);
711 cgiCopyTemplateLang("choose-device.tmpl");
712 cgiEndHTML();
713 }
714 else if (strchr(var, '/') == NULL)
715 {
716 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
717 {
718 /*
719 * Set the current device URI for the form to the old one...
720 */
721
722 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
723 cgiSetVariable("DEVICE_URI", attr->values[0].string.text);
724 }
725
726 /*
727 * User needs to set the full URI...
728 */
729
730 cgiStartHTML(title);
731 cgiCopyTemplateLang("choose-uri.tmpl");
732 cgiEndHTML();
733 }
734 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
735 {
736 /*
737 * Need baud rate, parity, etc.
738 */
739
740 if ((var = strchr(var, '?')) != NULL &&
741 strncmp(var, "?baud=", 6) == 0)
742 maxrate = atoi(var + 6);
743 else
744 maxrate = 19200;
745
746 for (i = 0; i < 10; i ++)
747 if (baudrates[i] > maxrate)
748 break;
749 else
750 {
751 sprintf(baudrate, "%d", baudrates[i]);
752 cgiSetArray("BAUDRATES", i, baudrate);
753 }
754
755 cgiStartHTML(title);
756 cgiCopyTemplateLang("choose-serial.tmpl");
757 cgiEndHTML();
758 }
759 else if (!file && (var = cgiGetVariable("PPD_NAME")) == NULL)
760 {
761 if (modify)
762 {
763 /*
764 * Get the PPD file...
765 */
766
767 int fd; /* PPD file */
768 char filename[1024]; /* PPD filename */
769 ppd_file_t *ppd; /* PPD information */
770 char buffer[1024]; /* Buffer */
771 int bytes; /* Number of bytes */
772 http_status_t get_status; /* Status of GET */
773
774
775 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
776
777 if (httpGet(http, uri))
778 httpGet(http, uri);
779
780 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
781
782 if (get_status != HTTP_OK)
783 {
784 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
785 uri, get_status, httpStatus(get_status));
786 }
787 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
788 {
789 while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0)
790 write(fd, buffer, bytes);
791
792 close(fd);
793
794 if ((ppd = ppdOpenFile(filename)) != NULL)
795 {
796 if (ppd->manufacturer)
797 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
798
799 if (ppd->nickname)
800 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
801
802 ppdClose(ppd);
803 unlink(filename);
804 }
805 else
806 {
807 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
808 filename, ppdErrorString(ppdLastError(&bytes)));
809 }
810 }
811 else
812 {
813 httpFlush(http);
814
815 fprintf(stderr,
816 "ERROR: Unable to create temporary file for PPD file: %s\n",
817 strerror(errno));
818 }
819 }
820 else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL)
821 {
822 /*
823 * Extract make and make/model from device URI string...
824 */
825
826 char make[1024], /* Make string */
827 *makeptr; /* Pointer into make */
828
829
830 *uriptr++ = '\0';
831
832 strlcpy(make, uriptr, sizeof(make));
833
834 if ((makeptr = strchr(make, ' ')) != NULL)
835 *makeptr = '\0';
836 else if ((makeptr = strchr(make, '-')) != NULL)
837 *makeptr = '\0';
838 else if (!strncasecmp(make, "laserjet", 8) ||
839 !strncasecmp(make, "deskjet", 7) ||
840 !strncasecmp(make, "designjet", 9))
841 strcpy(make, "HP");
842 else if (!strncasecmp(make, "phaser", 6))
843 strcpy(make, "Xerox");
844 else if (!strncasecmp(make, "stylus", 6))
845 strcpy(make, "Epson");
846 else
847 strcpy(make, "Generic");
848
849 cgiSetVariable("CURRENT_MAKE", make);
850 cgiSetVariable("PPD_MAKE", make);
851 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
852 }
853
854 /*
855 * Build a CUPS_GET_PPDS request, which requires the following
856 * attributes:
857 *
858 * attributes-charset
859 * attributes-natural-language
860 * printer-uri
861 */
862
863 request = ippNew();
864
865 request->request.op.operation_id = CUPS_GET_PPDS;
866 request->request.op.request_id = 1;
867
868 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
869 "attributes-charset", NULL, cupsLangEncoding(language));
870
871 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
872 "attributes-natural-language", NULL, language->language);
873
874 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
875 NULL, "ipp://localhost/printers/");
876
877
878 if ((var = cgiGetVariable("PPD_MAKE")) != NULL)
879 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
880 "ppd-make", NULL, var);
881 else
882 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
883 "requested-attributes", NULL, "ppd-make");
884
885 /*
886 * Do the request and get back a response...
887 */
888
889 if ((response = cupsDoRequest(http, request, "/")) != NULL)
890 {
891 /*
892 * Got the list of PPDs, see if the user has selected a make...
893 */
894
895 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
896
897 if (var == NULL)
898 {
899 /*
900 * Let the user choose a make...
901 */
902
903 for (element = 0, attr = response->attrs, last = NULL;
904 attr != NULL;
905 attr = attr->next)
906 if (attr->name && strcmp(attr->name, "ppd-make") == 0)
907 if (last == NULL ||
908 strcasecmp(last->values[0].string.text,
909 attr->values[0].string.text) != 0)
910 {
911 cgiSetArray("PPD_MAKE", element, attr->values[0].string.text);
912 element ++;
913 last = attr;
914 }
915
916 cgiStartHTML(title);
917 cgiCopyTemplateLang("choose-make.tmpl");
918 cgiEndHTML();
919 }
920 else
921 {
922 /*
923 * Let the user choose a model...
924 */
925
926 const char *make_model; /* Current make/model string */
927
928
929 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
930 {
931 /*
932 * Scan for "close" matches...
933 */
934
935 int match, /* Current match */
936 best_match, /* Best match so far */
937 count; /* Number of drivers */
938 const char *best, /* Best matching string */
939 *current; /* Current string */
940
941
942 count = cgiGetSize("PPD_MAKE_AND_MODEL");
943
944 for (i = 0, best_match = 0, best = NULL; i < count; i ++)
945 {
946 current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
947 match = match_string(make_model, current);
948
949 if (match > best_match)
950 {
951 best_match = match;
952 best = current;
953 }
954 }
955
956 if (best_match > strlen(var))
957 {
958 /*
959 * Found a match longer than the make...
960 */
961
962 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
963 }
964 }
965
966 cgiStartHTML(title);
967 cgiCopyTemplateLang("choose-model.tmpl");
968 cgiEndHTML();
969 }
970
971
972 ippDelete(response);
973 }
974 else
975 {
976 char message[1024];
977
978
979 snprintf(message, sizeof(message), "Unable to get list of printer drivers: %s",
980 ippErrorString(cupsLastError()));
981 cgiSetVariable("ERROR", message);
982 cgiStartHTML(title);
983 cgiCopyTemplateLang("error.tmpl");
984 cgiEndHTML();
985 }
986 }
987 else
988 {
989 /*
990 * Build a CUPS_ADD_PRINTER request, which requires the following
991 * attributes:
992 *
993 * attributes-charset
994 * attributes-natural-language
995 * printer-uri
996 * printer-location
997 * printer-info
998 * ppd-name
999 * device-uri
1000 * printer-is-accepting-jobs
1001 * printer-state
1002 */
1003
1004 request = ippNew();
1005
1006 request->request.op.operation_id = CUPS_ADD_PRINTER;
1007 request->request.op.request_id = 1;
1008
1009 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1010 "attributes-charset", NULL, cupsLangEncoding(language));
1011
1012 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1013 "attributes-natural-language", NULL, language->language);
1014
1015 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1016 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
1017 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1018 NULL, uri);
1019
1020 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1021 NULL, cgiGetVariable("PRINTER_LOCATION"));
1022
1023 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1024 NULL, cgiGetVariable("PRINTER_INFO"));
1025
1026 if (!file)
1027 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1028 NULL, cgiGetVariable("PPD_NAME"));
1029
1030 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1031
1032 /*
1033 * Strip make and model from URI...
1034 */
1035
1036 if ((uriptr = strrchr(uri, '|')) != NULL)
1037 *uriptr = '\0';
1038
1039 if (strncmp(uri, "serial:", 7) == 0)
1040 {
1041 /*
1042 * Update serial port URI to include baud rate, etc.
1043 */
1044
1045 if ((uriptr = strchr(uri, '?')) == NULL)
1046 uriptr = uri + strlen(uri);
1047
1048 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1049 "?baud=%s+bits=%s+parity=%s+flow=%s",
1050 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1051 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1052 }
1053
1054 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1055 NULL, uri);
1056
1057 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1058
1059 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1060 IPP_PRINTER_IDLE);
1061
1062 /*
1063 * Do the request and get back a response...
1064 */
1065
1066 if (file)
1067 response = cupsDoFileRequest(http, request, "/admin/", file->tempfile);
1068 else
1069 response = cupsDoRequest(http, request, "/admin/");
1070
1071 if (response)
1072 {
1073 status = response->request.status.status_code;
1074 ippDelete(response);
1075 }
1076 else
1077 status = cupsLastError();
1078
1079 if (status > IPP_OK_CONFLICT)
1080 {
1081 cgiStartHTML(title);
1082 cgiSetVariable("ERROR", ippErrorString(status));
1083 cgiCopyTemplateLang("error.tmpl");
1084 }
1085 else
1086 {
1087 /*
1088 * Redirect successful updates back to the printer or set-options pages...
1089 */
1090
1091 char refresh[1024]; /* Refresh URL */
1092
1093
1094 cgiFormEncode(uri, name, sizeof(uri));
1095
1096 if (modify)
1097 snprintf(refresh, sizeof(refresh),
1098 "5;/admin?OP=redirect&URL=/printers/%s", uri);
1099 else
1100 snprintf(refresh, sizeof(refresh),
1101 "5;/admin?OP=set-printer-options&PRINTER_NAME=%s", uri);
1102
1103 cgiSetVariable("refresh_page", refresh);
1104
1105 cgiStartHTML(title);
1106
1107 if (modify)
1108 cgiCopyTemplateLang("printer-modified.tmpl");
1109 else
1110 cgiCopyTemplateLang("printer-added.tmpl");
1111 }
1112
1113 cgiEndHTML();
1114 }
1115
1116 if (oldinfo)
1117 ippDelete(oldinfo);
1118 }
1119
1120
1121 /*
1122 * 'do_config_printer()' - Configure the default options for a printer.
1123 */
1124
1125 static void
1126 do_config_printer(http_t *http, /* I - HTTP connection */
1127 cups_lang_t *language)/* I - Client's language */
1128 {
1129 int i, j, k, m; /* Looping vars */
1130 int have_options; /* Have options? */
1131 ipp_t *request, /* IPP request */
1132 *response; /* IPP response */
1133 ipp_attribute_t *attr; /* IPP attribute */
1134 char uri[HTTP_MAX_URI]; /* Job URI */
1135 const char *var; /* Variable value */
1136 const char *printer; /* Printer printer name */
1137 ipp_status_t status; /* Operation status... */
1138 const char *filename; /* PPD filename */
1139 char tempfile[1024]; /* Temporary filename */
1140 cups_file_t *in, /* Input file */
1141 *out; /* Output file */
1142 char line[1024]; /* Line from PPD file */
1143 char keyword[1024], /* Keyword from Default line */
1144 *keyptr; /* Pointer into keyword... */
1145 ppd_file_t *ppd; /* PPD file */
1146 ppd_group_t *group; /* Option group */
1147 ppd_option_t *option; /* Option */
1148 ppd_attr_t *protocol; /* cupsProtocol attribute */
1149
1150
1151 /*
1152 * Get the printer name...
1153 */
1154
1155 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1156 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1157 "/printers/%s", printer);
1158 else
1159 {
1160 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
1161 cgiStartHTML("Set Printer Options");
1162 cgiCopyTemplateLang("error.tmpl");
1163 cgiEndHTML();
1164 return;
1165 }
1166
1167 /*
1168 * Get the PPD file...
1169 */
1170
1171 if ((filename = cupsGetPPD(printer)) == NULL)
1172 {
1173 if (cupsLastError() == IPP_NOT_FOUND)
1174 {
1175 /*
1176 * No PPD file for this printer, so we can't configure it!
1177 */
1178
1179 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_POSSIBLE));
1180 cgiStartHTML("Set Printer Options");
1181 cgiCopyTemplateLang("error.tmpl");
1182 cgiEndHTML();
1183 }
1184 else
1185 {
1186 /*
1187 * Unable to access the PPD file for some reason...
1188 */
1189
1190 cgiSetVariable("ERROR", ippErrorString(cupsLastError()));
1191 cgiStartHTML("Set Printer Options");
1192 cgiCopyTemplateLang("error.tmpl");
1193 cgiEndHTML();
1194 }
1195 return;
1196 }
1197
1198 if ((ppd = ppdOpenFile(filename)) == NULL)
1199 {
1200 cgiSetVariable("ERROR", ippErrorString(IPP_DEVICE_ERROR));
1201 cgiStartHTML("Set Printer Options");
1202 cgiCopyTemplateLang("error.tmpl");
1203 cgiEndHTML();
1204 return;
1205 }
1206
1207 if (cgiGetVariable("job_sheets_start") != NULL ||
1208 cgiGetVariable("job_sheets_end") != NULL)
1209 have_options = 1;
1210 else
1211 have_options = 0;
1212
1213 ppdMarkDefaults(ppd);
1214
1215 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1216 "<UL>\n", ppd->num_groups));
1217
1218 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
1219 {
1220 DEBUG_printf(("<LI>%s<UL>\n", group->text));
1221
1222 for (j = group->num_options, option = group->options; j > 0; j --, option ++)
1223 if ((var = cgiGetVariable(option->keyword)) != NULL)
1224 {
1225 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
1226 have_options = 1;
1227 ppdMarkOption(ppd, option->keyword, var);
1228 }
1229 #ifdef DEBUG
1230 else
1231 printf("<LI>%s not defined!</LI>\n", option->keyword);
1232 #endif /* DEBUG */
1233
1234 DEBUG_puts("</UL></LI>");
1235 }
1236
1237 DEBUG_printf(("</UL>\n"
1238 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
1239
1240 if (!have_options || ppdConflicts(ppd))
1241 {
1242 /*
1243 * Show the options to the user...
1244 */
1245
1246 cgiStartHTML("Set Printer Options");
1247 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1248
1249 if (ppdConflicts(ppd))
1250 {
1251 for (i = ppd->num_groups, k = 0, group = ppd->groups; i > 0; i --, group ++)
1252 for (j = group->num_options, option = group->options; j > 0; j --, option ++)
1253 if (option->conflicted)
1254 {
1255 cgiSetArray("ckeyword", k, option->keyword);
1256 cgiSetArray("ckeytext", k, option->text);
1257 k ++;
1258 }
1259
1260 cgiCopyTemplateLang("option-conflict.tmpl");
1261 }
1262
1263 for (i = ppd->num_groups, group = ppd->groups;
1264 i > 0;
1265 i --, group ++)
1266 {
1267 if (!strcmp(group->name, "InstallableOptions"))
1268 cgiSetVariable("GROUP",
1269 _cupsLangString(language, _("Options Installed")));
1270 else
1271 cgiSetVariable("GROUP", group->text);
1272
1273 cgiCopyTemplateLang("option-header.tmpl");
1274
1275 for (j = group->num_options, option = group->options;
1276 j > 0;
1277 j --, option ++)
1278 {
1279 if (!strcmp(option->keyword, "PageRegion"))
1280 continue;
1281
1282 cgiSetVariable("KEYWORD", option->keyword);
1283 cgiSetVariable("KEYTEXT", option->text);
1284
1285 if (option->conflicted)
1286 cgiSetVariable("CONFLICTED", "1");
1287 else
1288 cgiSetVariable("CONFLICTED", "0");
1289
1290 cgiSetSize("CHOICES", 0);
1291 cgiSetSize("TEXT", 0);
1292 for (k = 0, m = 0; k < option->num_choices; k ++)
1293 {
1294 /*
1295 * Hide custom option values...
1296 */
1297
1298 if (!strcmp(option->choices[k].choice, "Custom"))
1299 continue;
1300
1301 cgiSetArray("CHOICES", m, option->choices[k].choice);
1302 cgiSetArray("TEXT", m, option->choices[k].text);
1303
1304 m ++;
1305
1306 if (option->choices[k].marked)
1307 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
1308 }
1309
1310 switch (option->ui)
1311 {
1312 case PPD_UI_BOOLEAN :
1313 cgiCopyTemplateLang("option-boolean.tmpl");
1314 break;
1315 case PPD_UI_PICKONE :
1316 cgiCopyTemplateLang("option-pickone.tmpl");
1317 break;
1318 case PPD_UI_PICKMANY :
1319 cgiCopyTemplateLang("option-pickmany.tmpl");
1320 break;
1321 }
1322 }
1323
1324 cgiCopyTemplateLang("option-trailer.tmpl");
1325 }
1326
1327 /*
1328 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1329 * following attributes:
1330 *
1331 * attributes-charset
1332 * attributes-natural-language
1333 * printer-uri
1334 */
1335
1336 request = ippNew();
1337
1338 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1339 request->request.op.request_id = 1;
1340
1341 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1342 "attributes-charset", NULL, cupsLangEncoding(language));
1343
1344 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1345 "attributes-natural-language", NULL, language->language);
1346
1347 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1348 "/printers/%s", printer);
1349 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1350 NULL, uri);
1351
1352 /*
1353 * Do the request and get back a response...
1354 */
1355
1356 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1357 {
1358 if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) != NULL)
1359 {
1360 /*
1361 * Add the job sheets options...
1362 */
1363
1364 cgiSetVariable("GROUP", "Banners");
1365 cgiCopyTemplateLang("option-header.tmpl");
1366
1367 cgiSetSize("CHOICES", attr->num_values);
1368 cgiSetSize("TEXT", attr->num_values);
1369 for (k = 0; k < attr->num_values; k ++)
1370 {
1371 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1372 cgiSetArray("TEXT", k, attr->values[k].string.text);
1373 }
1374
1375 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
1376
1377 cgiSetVariable("KEYWORD", "job_sheets_start");
1378 cgiSetVariable("KEYTEXT", "Starting Banner");
1379 cgiSetVariable("DEFCHOICE", attr == NULL ?
1380 "" : attr->values[0].string.text);
1381
1382 cgiCopyTemplateLang("option-pickone.tmpl");
1383
1384 cgiSetVariable("KEYWORD", "job_sheets_end");
1385 cgiSetVariable("KEYTEXT", "Ending Banner");
1386 cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
1387 "" : attr->values[1].string.text);
1388
1389 cgiCopyTemplateLang("option-pickone.tmpl");
1390
1391 cgiCopyTemplateLang("option-trailer.tmpl");
1392 }
1393
1394 if (ippFindAttribute(response, "printer-error-policy-supported",
1395 IPP_TAG_ZERO) ||
1396 ippFindAttribute(response, "printer-op-policy-supported",
1397 IPP_TAG_ZERO))
1398 {
1399 /*
1400 * Add the error and operation policy options...
1401 */
1402
1403 cgiSetVariable("GROUP", "Policies");
1404 cgiCopyTemplateLang("option-header.tmpl");
1405
1406 /*
1407 * Error policy...
1408 */
1409
1410 attr = ippFindAttribute(response, "printer-error-policy-supported",
1411 IPP_TAG_ZERO);
1412
1413 if (attr)
1414 {
1415 cgiSetSize("CHOICES", attr->num_values);
1416 cgiSetSize("TEXT", attr->num_values);
1417 for (k = 0; k < attr->num_values; k ++)
1418 {
1419 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1420 cgiSetArray("TEXT", k, attr->values[k].string.text);
1421 }
1422
1423 attr = ippFindAttribute(response, "printer-error-policy",
1424 IPP_TAG_ZERO);
1425
1426 cgiSetVariable("KEYWORD", "printer_error_policy");
1427 cgiSetVariable("KEYTEXT", "Error Policy");
1428 cgiSetVariable("DEFCHOICE", attr == NULL ?
1429 "" : attr->values[0].string.text);
1430 }
1431
1432 cgiCopyTemplateLang("option-pickone.tmpl");
1433
1434 /*
1435 * Operation policy...
1436 */
1437
1438 attr = ippFindAttribute(response, "printer-op-policy-supported",
1439 IPP_TAG_ZERO);
1440
1441 if (attr)
1442 {
1443 cgiSetSize("CHOICES", attr->num_values);
1444 cgiSetSize("TEXT", attr->num_values);
1445 for (k = 0; k < attr->num_values; k ++)
1446 {
1447 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1448 cgiSetArray("TEXT", k, attr->values[k].string.text);
1449 }
1450
1451 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
1452
1453 cgiSetVariable("KEYWORD", "printer_op_policy");
1454 cgiSetVariable("KEYTEXT", "Operation Policy");
1455 cgiSetVariable("DEFCHOICE", attr == NULL ?
1456 "" : attr->values[0].string.text);
1457
1458 cgiCopyTemplateLang("option-pickone.tmpl");
1459 }
1460
1461 cgiCopyTemplateLang("option-trailer.tmpl");
1462 }
1463
1464 ippDelete(response);
1465 }
1466
1467 /*
1468 * Binary protocol support...
1469 */
1470
1471 if (ppd->protocols && strstr(ppd->protocols, "BCP"))
1472 {
1473 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
1474
1475 cgiSetVariable("GROUP", "PS Binary Protocol");
1476 cgiCopyTemplateLang("option-header.tmpl");
1477
1478 cgiSetSize("CHOICES", 2);
1479 cgiSetSize("TEXT", 2);
1480 cgiSetArray("CHOICES", 0, "None");
1481 cgiSetArray("TEXT", 0, "None");
1482
1483 if (strstr(ppd->protocols, "TBCP"))
1484 {
1485 cgiSetArray("CHOICES", 1, "TBCP");
1486 cgiSetArray("TEXT", 1, "TBCP");
1487 }
1488 else
1489 {
1490 cgiSetArray("CHOICES", 1, "BCP");
1491 cgiSetArray("TEXT", 1, "BCP");
1492 }
1493
1494 cgiSetVariable("KEYWORD", "protocol");
1495 cgiSetVariable("KEYTEXT", "PS Binary Protocol");
1496 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
1497
1498 cgiCopyTemplateLang("option-pickone.tmpl");
1499
1500 cgiCopyTemplateLang("option-trailer.tmpl");
1501 }
1502
1503 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1504 cgiEndHTML();
1505 }
1506 else
1507 {
1508 /*
1509 * Set default options...
1510 */
1511
1512 out = cupsTempFile2(tempfile, sizeof(tempfile));
1513 in = cupsFileOpen(filename, "r");
1514
1515 if (!in || !out)
1516 {
1517 cgiSetVariable("ERROR", strerror(errno));
1518 cgiStartHTML("Set Printer Options");
1519 cgiCopyTemplateLang("error.tmpl");
1520 cgiEndHTML();
1521
1522 if (in)
1523 cupsFileClose(in);
1524
1525 if (out)
1526 {
1527 cupsFileClose(out);
1528 unlink(tempfile);
1529 }
1530
1531 unlink(filename);
1532 return;
1533 }
1534
1535 while (cupsFileGets(in, line, sizeof(line)))
1536 {
1537 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1538 continue;
1539 else if (strncmp(line, "*Default", 8))
1540 cupsFilePrintf(out, "%s\n", line);
1541 else
1542 {
1543 /*
1544 * Get default option name...
1545 */
1546
1547 strlcpy(keyword, line + 8, sizeof(keyword));
1548
1549 for (keyptr = keyword; *keyptr; keyptr ++)
1550 if (*keyptr == ':' || isspace(*keyptr & 255))
1551 break;
1552
1553 *keyptr = '\0';
1554
1555 if (!strcmp(keyword, "PageRegion"))
1556 var = cgiGetVariable("PageSize");
1557 else
1558 var = cgiGetVariable(keyword);
1559
1560 if (var != NULL)
1561 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
1562 else
1563 cupsFilePrintf(out, "%s\n", line);
1564 }
1565 }
1566
1567 if ((var = cgiGetVariable("protocol")) != NULL)
1568 cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1569
1570 cupsFileClose(in);
1571 cupsFileClose(out);
1572
1573 /*
1574 * Build a CUPS_ADD_PRINTER request, which requires the following
1575 * attributes:
1576 *
1577 * attributes-charset
1578 * attributes-natural-language
1579 * printer-uri
1580 * job-sheets-default
1581 * [ppd file]
1582 */
1583
1584 request = ippNew();
1585
1586 request->request.op.operation_id = CUPS_ADD_PRINTER;
1587 request->request.op.request_id = 1;
1588
1589 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1590 "attributes-charset", NULL, cupsLangEncoding(language));
1591
1592 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1593 "attributes-natural-language", NULL, language->language);
1594
1595 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1596 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
1597 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1598 NULL, uri);
1599
1600 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1601 "job-sheets-default", 2, NULL, NULL);
1602 attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start"));
1603 attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end"));
1604
1605 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1606 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1607 "printer-error-policy", NULL, var);
1608
1609 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1610 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1611 "printer-op-policy", NULL, var);
1612
1613 /*
1614 * Do the request and get back a response...
1615 */
1616
1617 if ((response = cupsDoFileRequest(http, request, "/admin/", tempfile)) != NULL)
1618 {
1619 status = response->request.status.status_code;
1620 ippDelete(response);
1621 }
1622 else
1623 status = cupsLastError();
1624
1625 if (status > IPP_OK_CONFLICT)
1626 {
1627 cgiStartHTML("Set Printer Options");
1628 cgiSetVariable("ERROR", ippErrorString(status));
1629 cgiCopyTemplateLang("error.tmpl");
1630 }
1631 else
1632 {
1633 /*
1634 * Redirect successful updates back to the printer page...
1635 */
1636
1637 char refresh[1024]; /* Refresh URL */
1638
1639 cgiFormEncode(uri, printer, sizeof(uri));
1640 snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
1641 uri);
1642 cgiSetVariable("refresh_page", refresh);
1643
1644 cgiStartHTML("Set Printer Options");
1645
1646 cgiCopyTemplateLang("printer-configured.tmpl");
1647 }
1648
1649 cgiEndHTML();
1650
1651 unlink(tempfile);
1652 }
1653
1654 unlink(filename);
1655 }
1656
1657
1658 /*
1659 * 'do_config_server()' - Configure server settings.
1660 */
1661
1662 static void
1663 do_config_server(http_t *http, /* I - HTTP connection */
1664 cups_lang_t *language) /* I - Client's language */
1665 {
1666 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1667 {
1668 /*
1669 * Save basic setting changes...
1670 */
1671
1672 http_status_t status; /* PUT status */
1673 cups_file_t *cupsd; /* cupsd.conf file */
1674 char tempfile[1024]; /* Temporary new cupsd.conf */
1675 int tempfd; /* Temporary file descriptor */
1676 cups_file_t *temp; /* Temporary file */
1677 char line[1024], /* Line from cupsd.conf file */
1678 *value; /* Value on line */
1679 const char *server_root; /* Location of config files */
1680 int linenum, /* Line number in file */
1681 in_policy, /* In a policy section? */
1682 in_cancel_job, /* In a cancel-job section? */
1683 in_admin_location, /* In the /admin location? */
1684 in_conf_location, /* In the /admin/conf location? */
1685 in_root_location; /* In the / location? */
1686 int remote_printers, /* Show remote printers */
1687 share_printers, /* Share local printers */
1688 remote_admin, /* Remote administration allowed? */
1689 user_cancel_any, /* Cancel-job policy set? */
1690 debug_logging; /* LogLevel debug set? */
1691 int wrote_port_listen, /* Wrote the port/listen lines? */
1692 wrote_browsing, /* Wrote the browsing lines? */
1693 wrote_policy, /* Wrote the policy? */
1694 wrote_loglevel, /* Wrote the LogLevel line? */
1695 wrote_admin_location, /* Wrote the /admin location? */
1696 wrote_conf_location, /* Wrote the /admin/conf location? */
1697 wrote_root_location; /* Wrote the / location? */
1698 int indent; /* Indentation */
1699
1700
1701 /*
1702 * Get form variables...
1703 */
1704
1705 remote_printers = cgiGetVariable("REMOTE_PRINTERS") != NULL;
1706 share_printers = cgiGetVariable("SHARE_PRINTERS") != NULL;
1707 remote_admin = cgiGetVariable("REMOTE_ADMIN") != NULL;
1708 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") != NULL;
1709 debug_logging = cgiGetVariable("DEBUG_LOGGING") != NULL;
1710
1711 /*
1712 * Locate the cupsd.conf file...
1713 */
1714
1715 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1716 server_root = CUPS_SERVERROOT;
1717
1718 snprintf(line, sizeof(line), "%s/cupsd.conf", server_root);
1719
1720 /*
1721 * Open the cupsd.conf file...
1722 */
1723
1724 if ((cupsd = cupsFileOpen(line, "r")) == NULL)
1725 {
1726 /*
1727 * Unable to open - log an error...
1728 */
1729
1730 cgiStartHTML("Change Settings");
1731 cgiSetVariable("ERROR", strerror(errno));
1732 cgiCopyTemplateLang("error.tmpl");
1733 cgiEndHTML();
1734
1735 perror(line);
1736 return;
1737 }
1738
1739 /*
1740 * Create a temporary file for the new cupsd.conf file...
1741 */
1742
1743 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1744 {
1745 cgiStartHTML("Change Settings");
1746 cgiSetVariable("ERROR", strerror(errno));
1747 cgiCopyTemplateLang("error.tmpl");
1748 cgiEndHTML();
1749
1750 perror(tempfile);
1751 cupsFileClose(cupsd);
1752 return;
1753 }
1754
1755 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1756 {
1757 cgiStartHTML("Change Settings");
1758 cgiSetVariable("ERROR", strerror(errno));
1759 cgiCopyTemplateLang("error.tmpl");
1760 cgiEndHTML();
1761
1762 perror(tempfile);
1763 close(tempfd);
1764 unlink(tempfile);
1765 cupsFileClose(cupsd);
1766 return;
1767 }
1768
1769 /*
1770 * Copy the old file to the new, making changes along the way...
1771 */
1772
1773 in_admin_location = 0;
1774 in_cancel_job = 0;
1775 in_conf_location = 0;
1776 in_policy = 0;
1777 in_root_location = 0;
1778 linenum = 0;
1779 wrote_admin_location = 0;
1780 wrote_browsing = 0;
1781 wrote_conf_location = 0;
1782 wrote_loglevel = 0;
1783 wrote_policy = 0;
1784 wrote_port_listen = 0;
1785 wrote_root_location = 0;
1786 indent = 0;
1787
1788 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
1789 {
1790 if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen"))
1791 {
1792 if (!wrote_port_listen)
1793 {
1794 wrote_port_listen = 1;
1795
1796 if (share_printers || remote_admin)
1797 {
1798 cupsFilePuts(temp, "# Allow remote access\n");
1799 cupsFilePrintf(temp, "Listen *:%d\n", ippPort());
1800 }
1801 else
1802 {
1803 cupsFilePuts(temp, "# Only listen for connections from the local machine.\n");
1804 cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
1805 }
1806
1807 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1808 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1809 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1810 }
1811 }
1812 else if (!strcasecmp(line, "Browsing") ||
1813 !strcasecmp(line, "BrowseAddress") ||
1814 !strcasecmp(line, "BrowseAllow") ||
1815 !strcasecmp(line, "BrowseDeny") ||
1816 !strcasecmp(line, "BrowseOrder"))
1817 {
1818 if (!wrote_browsing)
1819 {
1820 wrote_browsing = 1;
1821
1822 if (remote_printers || share_printers)
1823 {
1824 if (remote_printers && share_printers)
1825 cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
1826 else if (remote_printers)
1827 cupsFilePuts(temp, "# Show shared printers on the local network.\n");
1828 else
1829 cupsFilePuts(temp, "# Share local printers on the local network.\n");
1830
1831 cupsFilePuts(temp, "Browsing On\n");
1832 cupsFilePuts(temp, "BrowseOrder allow,deny\n");
1833
1834 if (remote_printers)
1835 cupsFilePuts(temp, "BrowseAllow @LOCAL\n");
1836
1837 if (share_printers)
1838 cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
1839 }
1840 else
1841 {
1842 cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
1843 cupsFilePuts(temp, "Browsing Off\n");
1844 }
1845 }
1846 }
1847 else if (!strcasecmp(line, "LogLevel"))
1848 {
1849 wrote_loglevel = 1;
1850
1851 if (debug_logging)
1852 {
1853 cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
1854 cupsFilePuts(temp, "LogLevel debug\n");
1855 }
1856 else
1857 {
1858 cupsFilePuts(temp, "# Show general information in error_log.\n");
1859 cupsFilePuts(temp, "LogLevel info\n");
1860 }
1861 }
1862 else if (!strcasecmp(line, "<Policy") && !strcasecmp(value, "default"))
1863 {
1864 in_policy = 1;
1865
1866 cupsFilePrintf(temp, "%s %s>\n", line, value);
1867 indent += 2;
1868 }
1869 else if (!strcasecmp(line, "</Policy>"))
1870 {
1871 indent -= 2;
1872 if (!wrote_policy)
1873 {
1874 wrote_policy = 1;
1875
1876 if (!user_cancel_any)
1877 cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
1878 " <Limit Cancel-Job>\n"
1879 " Order deny,allow\n"
1880 " Allow @SYSTEM\n"
1881 " Allow @OWNER\n"
1882 " </Limit>\n");
1883 }
1884
1885 in_policy = 0;
1886
1887 cupsFilePuts(temp, "</Policy>\n");
1888 }
1889 else if (!strcasecmp(line, "<Location"))
1890 {
1891 indent += 2;
1892 if (!strcmp(value, "/admin"))
1893 in_admin_location = 1;
1894 if (!strcmp(value, "/admin/conf"))
1895 in_conf_location = 1;
1896 else if (!strcmp(value, "/"))
1897 in_root_location = 1;
1898
1899 cupsFilePrintf(temp, "%s %s>\n", line, value);
1900 }
1901 else if (!strcasecmp(line, "</Location>"))
1902 {
1903 indent -= 2;
1904 if (in_admin_location)
1905 {
1906 wrote_admin_location = 1;
1907
1908 if (remote_admin)
1909 cupsFilePuts(temp, " # Allow remote administration...\n");
1910 else
1911 cupsFilePuts(temp, " # Restrict access to the admin pages...\n");
1912
1913 cupsFilePuts(temp, " Order allow,deny\n");
1914
1915 if (remote_admin)
1916 cupsFilePuts(temp, " Allow @LOCAL\n");
1917 else
1918 cupsFilePuts(temp, " Allow localhost\n");
1919 }
1920 else if (in_conf_location)
1921 {
1922 wrote_conf_location = 1;
1923
1924 if (remote_admin)
1925 cupsFilePuts(temp, " # Allow remote access to the configuration files...\n");
1926 else
1927 cupsFilePuts(temp, " # Restrict access to the configuration files...\n");
1928
1929 cupsFilePuts(temp, " Order allow,deny\n");
1930
1931 if (remote_admin)
1932 cupsFilePuts(temp, " Allow @LOCAL\n");
1933 else
1934 cupsFilePuts(temp, " Allow localhost\n");
1935 }
1936 else if (in_root_location)
1937 {
1938 wrote_root_location = 1;
1939
1940 if (remote_admin && share_printers)
1941 cupsFilePuts(temp, " # Allow shared printing and remote administration...\n");
1942 else if (remote_admin)
1943 cupsFilePuts(temp, " # Allow remote administration...\n");
1944 else if (share_printers)
1945 cupsFilePuts(temp, " # Allow shared printing...\n");
1946 else
1947 cupsFilePuts(temp, " # Restrict access to the server...\n");
1948
1949 cupsFilePuts(temp, " Order allow,deny\n");
1950
1951 if (remote_admin || share_printers)
1952 cupsFilePuts(temp, " Allow @LOCAL\n");
1953 else
1954 cupsFilePuts(temp, " Allow localhost\n");
1955 }
1956
1957 in_admin_location = 0;
1958 in_conf_location = 0;
1959 in_root_location = 0;
1960
1961 cupsFilePuts(temp, "</Location>\n");
1962 }
1963 else if (!strcasecmp(line, "<Limit") && in_policy)
1964 {
1965 /*
1966 * See if the policy limit is for the Cancel-Job operation...
1967 */
1968
1969 char *valptr; /* Pointer into value */
1970
1971
1972 indent += 2;
1973
1974 if (!strcasecmp(value, "cancel-job"))
1975 {
1976 /*
1977 * Don't write anything for this limit section...
1978 */
1979
1980 in_cancel_job = 2;
1981 }
1982 else
1983 {
1984 cupsFilePrintf(temp, " %s", line);
1985
1986 while (*value)
1987 {
1988 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
1989
1990 if (*valptr)
1991 *valptr++ = '\0';
1992
1993 if (!strcasecmp(value, "cancel-job"))
1994 {
1995 /*
1996 * Write everything except for this definition...
1997 */
1998
1999 in_cancel_job = 1;
2000 }
2001 else
2002 cupsFilePrintf(temp, " %s", value);
2003
2004 for (value = valptr; isspace(*value & 255); value ++);
2005 }
2006
2007 cupsFilePuts(temp, ">\n");
2008 }
2009 }
2010 else if (!strcasecmp(line, "</Limit>") && in_cancel_job)
2011 {
2012 indent -= 2;
2013
2014 if (in_cancel_job == 1)
2015 cupsFilePuts(temp, " </Limit>\n");
2016
2017 wrote_policy = 1;
2018
2019 if (!user_cancel_any)
2020 cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
2021 " <Limit Cancel-Job>\n"
2022 " Order deny,allow\n"
2023 " Require user @OWNER @SYSTEM\n"
2024 " </Limit>\n");
2025
2026 in_cancel_job = 0;
2027 }
2028 else if ((in_admin_location || in_conf_location || in_root_location) &&
2029 (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny") ||
2030 !strcasecmp(line, "Order")))
2031 continue;
2032 else if (in_cancel_job == 2)
2033 continue;
2034 else if (!strcasecmp(line, "<Limit") && value)
2035 cupsFilePrintf(temp, " %s %s>\n", line, value);
2036 else if (line[0] == '<')
2037 {
2038 if (value)
2039 {
2040 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
2041 indent += 2;
2042 }
2043 else
2044 {
2045 if (line[1] == '/')
2046 indent -= 2;
2047
2048 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
2049 }
2050 }
2051 else if (value)
2052 cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
2053 else
2054 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
2055 }
2056
2057 /*
2058 * Write any missing info...
2059 */
2060
2061 if (!wrote_browsing)
2062 {
2063 if (remote_printers || share_printers)
2064 {
2065 if (remote_printers && share_printers)
2066 cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
2067 else if (remote_printers)
2068 cupsFilePuts(temp, "# Show shared printers on the local network.\n");
2069 else
2070 cupsFilePuts(temp, "# Share local printers on the local network.\n");
2071
2072 cupsFilePuts(temp, "Browsing On\n");
2073 cupsFilePuts(temp, "BrowseOrder allow,deny\n");
2074
2075 if (remote_printers)
2076 cupsFilePuts(temp, "BrowseAllow @LOCAL\n");
2077
2078 if (share_printers)
2079 cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
2080 }
2081 else
2082 {
2083 cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
2084 cupsFilePuts(temp, "Browsing Off\n");
2085 }
2086 }
2087
2088 if (!wrote_loglevel)
2089 {
2090 if (debug_logging)
2091 {
2092 cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
2093 cupsFilePuts(temp, "LogLevel debug\n");
2094 }
2095 else
2096 {
2097 cupsFilePuts(temp, "# Show general information in error_log.\n");
2098 cupsFilePuts(temp, "LogLevel info\n");
2099 }
2100 }
2101
2102 if (!wrote_port_listen)
2103 {
2104 if (share_printers || remote_admin)
2105 {
2106 cupsFilePuts(temp, "# Allow remote access\n");
2107 cupsFilePrintf(temp, "Listen *:%d\n", ippPort());
2108 }
2109 else
2110 {
2111 cupsFilePuts(temp, "# Only listen for connections from the local machine.\n");
2112 cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
2113 }
2114
2115 #ifdef CUPS_DEFAULT_DOMAINSOCKET
2116 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
2117 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
2118 }
2119
2120 if (!wrote_root_location)
2121 {
2122 if (remote_admin && share_printers)
2123 cupsFilePuts(temp, "# Allow shared printing and remote administration...\n");
2124 else if (remote_admin)
2125 cupsFilePuts(temp, "# Allow remote administration...\n");
2126 else if (share_printers)
2127 cupsFilePuts(temp, "# Allow shared printing...\n");
2128 else
2129 cupsFilePuts(temp, "# Restrict access to the server...\n");
2130
2131 cupsFilePuts(temp, "<Location />\n"
2132 " Order allow,deny\n");
2133
2134 if (remote_admin || share_printers)
2135 cupsFilePuts(temp, " Allow @LOCAL\n");
2136 else
2137 cupsFilePuts(temp, " Allow localhost\n");
2138
2139 cupsFilePuts(temp, "</Location>\n");
2140 }
2141
2142 if (!wrote_admin_location)
2143 {
2144 if (remote_admin)
2145 cupsFilePuts(temp, "# Allow remote administration...\n");
2146 else
2147 cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
2148
2149 cupsFilePuts(temp, "<Location /admin>\n"
2150 " Order allow,deny\n");
2151
2152 if (remote_admin)
2153 cupsFilePuts(temp, " Allow @LOCAL\n");
2154 else
2155 cupsFilePuts(temp, " Allow localhost\n");
2156
2157 cupsFilePuts(temp, "</Location>\n");
2158 }
2159
2160 if (!wrote_conf_location)
2161 {
2162 if (remote_admin)
2163 cupsFilePuts(temp, "# Allow remote access to the configuration files...\n");
2164 else
2165 cupsFilePuts(temp, "# Restrict access to the configuration files...\n");
2166
2167 cupsFilePuts(temp, "<Location /admin/conf>\n"
2168 " AuthType Basic\n"
2169 " Require user @SYSTEM\n"
2170 " Order allow,deny\n");
2171
2172 if (remote_admin)
2173 cupsFilePuts(temp, " Allow @LOCAL\n");
2174 else
2175 cupsFilePuts(temp, " Allow localhost\n");
2176
2177 cupsFilePuts(temp, "</Location>\n");
2178 }
2179
2180 if (!wrote_policy)
2181 {
2182 cupsFilePuts(temp, "<Policy default>\n"
2183 " # Job-related operations must be done by the owner or an adminstrator...\n"
2184 " <Limit Send-Document Send-URI Hold-Job Release-Job "
2185 "Restart-Job Purge-Jobs Set-Job-Attributes "
2186 "Create-Job-Subscription Renew-Subscription "
2187 "Cancel-Subscription Get-Notifications Reprocess-Job "
2188 "Cancel-Current-Job Suspend-Current-Job Resume-Job "
2189 "CUPS-Move-Job>\n"
2190 " Require user @OWNER @SYSTEM\n"
2191 " Order deny,allow\n"
2192 " </Limit>\n"
2193 " # All administration operations require an adminstrator to authenticate...\n"
2194 " <Limit Pause-Printer Resume-Printer "
2195 "Set-Printer-Attributes Enable-Printer "
2196 "Disable-Printer Pause-Printer-After-Current-Job "
2197 "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
2198 "Activate-Printer Restart-Printer Shutdown-Printer "
2199 "Startup-Printer Promote-Job Schedule-Job-After "
2200 "CUPS-Add-Printer CUPS-Delete-Printer "
2201 "CUPS-Add-Class CUPS-Delete-Class "
2202 "CUPS-Accept-Jobs CUPS-Reject-Jobs "
2203 "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
2204 " AuthType Basic\n"
2205 " Require user @SYSTEM\n"
2206 " Order deny,allow\n"
2207 "</Limit>\n");
2208
2209 if (!user_cancel_any)
2210 cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
2211 " <Limit Cancel-Job>\n"
2212 " Require user @OWNER @SYSTEM\n"
2213 " Order deny,allow\n"
2214 " </Limit>\n");
2215
2216 cupsFilePuts(temp, " <Limit All>\n"
2217 " Order deny,allow\n"
2218 " </Limit>\n"
2219 "</Policy>\n");
2220 }
2221
2222 cupsFileClose(cupsd);
2223 cupsFileClose(temp);
2224
2225 /*
2226 * Upload the configuration file to the server...
2227 */
2228
2229 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
2230
2231 if (status != HTTP_CREATED)
2232 {
2233 cgiSetVariable("ERROR", httpStatus(status));
2234 cgiStartHTML("Change Settings");
2235 cgiCopyTemplateLang("error.tmpl");
2236 }
2237 else
2238 {
2239 cgiSetVariable("refresh_page", "5;/admin?OP=redirect");
2240
2241 cgiStartHTML("Change Settings");
2242 cgiCopyTemplateLang("restart.tmpl");
2243 }
2244
2245 cgiEndHTML();
2246
2247 unlink(tempfile);
2248 }
2249 else if (cgiIsPOST())
2250 {
2251 /*
2252 * Save hand-edited config file...
2253 */
2254
2255 http_status_t status; /* PUT status */
2256 char tempfile[1024]; /* Temporary new cupsd.conf */
2257 int tempfd; /* Temporary file descriptor */
2258 cups_file_t *temp; /* Temporary file */
2259 const char *start, /* Start of line */
2260 *end; /* End of line */
2261
2262
2263 /*
2264 * Create a temporary file for the new cupsd.conf file...
2265 */
2266
2267 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
2268 {
2269 cgiStartHTML("Edit Configuration File");
2270 cgiSetVariable("ERROR", strerror(errno));
2271 cgiCopyTemplateLang("error.tmpl");
2272 cgiEndHTML();
2273
2274 perror(tempfile);
2275 return;
2276 }
2277
2278 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
2279 {
2280 cgiStartHTML("Edit Configuration File");
2281 cgiSetVariable("ERROR", strerror(errno));
2282 cgiCopyTemplateLang("error.tmpl");
2283 cgiEndHTML();
2284
2285 perror(tempfile);
2286 close(tempfd);
2287 unlink(tempfile);
2288 return;
2289 }
2290
2291 /*
2292 * Copy the cupsd.conf text from the form variable...
2293 */
2294
2295 start = cgiGetVariable("CUPSDCONF");
2296 while (start)
2297 {
2298 if ((end = strstr(start, "\r\n")) == NULL)
2299 if ((end = strstr(start, "\n")) == NULL)
2300 end = start + strlen(start);
2301
2302 cupsFileWrite(temp, start, end - start);
2303 cupsFilePutChar(temp, '\n');
2304
2305 if (*end == '\r')
2306 start = end + 2;
2307 else if (*end == '\n')
2308 start = end + 1;
2309 else
2310 start = NULL;
2311 }
2312
2313 cupsFileClose(temp);
2314
2315 /*
2316 * Upload the configuration file to the server...
2317 */
2318
2319 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
2320
2321 if (status != HTTP_CREATED)
2322 {
2323 cgiSetVariable("ERROR", httpStatus(status));
2324 cgiStartHTML("Edit Configuration File");
2325 cgiCopyTemplateLang("error.tmpl");
2326 }
2327 else
2328 {
2329 cgiSetVariable("refresh_page", "5;/admin?OP=redirect");
2330
2331 cgiStartHTML("Edit Configuration File");
2332 cgiCopyTemplateLang("restart.tmpl");
2333 }
2334
2335 cgiEndHTML();
2336
2337 unlink(tempfile);
2338 }
2339 else
2340 {
2341 struct stat info; /* cupsd.conf information */
2342 cups_file_t *cupsd; /* cupsd.conf file */
2343 char *buffer; /* Buffer for entire file */
2344 char filename[1024]; /* Filename */
2345 const char *server_root; /* Location of config files */
2346
2347
2348 /*
2349 * Locate the cupsd.conf file...
2350 */
2351
2352 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
2353 server_root = CUPS_SERVERROOT;
2354
2355 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
2356
2357 /*
2358 * Figure out the size...
2359 */
2360
2361 if (stat(filename, &info))
2362 {
2363 cgiStartHTML("Edit Configuration File");
2364 cgiSetVariable("ERROR", strerror(errno));
2365 cgiCopyTemplateLang("error.tmpl");
2366 cgiEndHTML();
2367
2368 perror(filename);
2369 return;
2370 }
2371
2372 if (info.st_size > (1024 * 1024))
2373 {
2374 cgiStartHTML("Edit Configuration File");
2375 cgiSetVariable("ERROR", "Unable to edit cupsd.conf files larger than 1MB!");
2376 cgiCopyTemplateLang("error.tmpl");
2377 cgiEndHTML();
2378
2379 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
2380 (long)info.st_size);
2381 return;
2382 }
2383
2384 /*
2385 * Open the cupsd.conf file...
2386 */
2387
2388 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
2389 {
2390 /*
2391 * Unable to open - log an error...
2392 */
2393
2394 cgiStartHTML("Edit Configuration File");
2395 cgiSetVariable("ERROR", strerror(errno));
2396 cgiCopyTemplateLang("error.tmpl");
2397 cgiEndHTML();
2398
2399 perror(filename);
2400 return;
2401 }
2402
2403 /*
2404 * Allocate memory and load the file into a string buffer...
2405 */
2406
2407 buffer = calloc(1, info.st_size + 1);
2408
2409 cupsFileRead(cupsd, buffer, info.st_size);
2410 cupsFileClose(cupsd);
2411
2412 cgiSetVariable("CUPSDCONF", buffer);
2413 free(buffer);
2414
2415 /*
2416 * Show the current config file...
2417 */
2418
2419 cgiStartHTML("Edit Configuration File");
2420
2421 printf("<!-- \"%s\" -->\n", filename);
2422
2423 cgiCopyTemplateLang("edit-config.tmpl");
2424
2425 cgiEndHTML();
2426 }
2427 }
2428
2429
2430 /*
2431 * 'do_delete_class()' - Delete a class...
2432 */
2433
2434 static void
2435 do_delete_class(http_t *http, /* I - HTTP connection */
2436 cups_lang_t *language) /* I - Client's language */
2437 {
2438 ipp_t *request, /* IPP request */
2439 *response; /* IPP response */
2440 char uri[HTTP_MAX_URI]; /* Job URI */
2441 const char *pclass; /* Printer class name */
2442 ipp_status_t status; /* Operation status... */
2443
2444
2445 if (cgiGetVariable("CONFIRM") == NULL)
2446 {
2447 cgiStartHTML("Delete Class");
2448 cgiCopyTemplateLang("class-confirm.tmpl");
2449 cgiEndHTML();
2450 return;
2451 }
2452
2453 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
2454 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
2455 "/classes/%s", pclass);
2456 else
2457 {
2458 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
2459 cgiStartHTML("Delete Class");
2460 cgiCopyTemplateLang("error.tmpl");
2461 cgiEndHTML();
2462 return;
2463 }
2464
2465 /*
2466 * Build a CUPS_DELETE_CLASS request, which requires the following
2467 * attributes:
2468 *
2469 * attributes-charset
2470 * attributes-natural-language
2471 * printer-uri
2472 */
2473
2474 request = ippNew();
2475
2476 request->request.op.operation_id = CUPS_DELETE_CLASS;
2477 request->request.op.request_id = 1;
2478
2479 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2480 "attributes-charset", NULL, cupsLangEncoding(language));
2481
2482 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2483 "attributes-natural-language", NULL, language->language);
2484
2485 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2486 NULL, uri);
2487
2488 /*
2489 * Do the request and get back a response...
2490 */
2491
2492 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
2493 {
2494 status = response->request.status.status_code;
2495
2496 ippDelete(response);
2497 }
2498 else
2499 status = cupsLastError();
2500
2501 cgiStartHTML("Delete Class");
2502
2503 if (status > IPP_OK_CONFLICT)
2504 {
2505 cgiSetVariable("ERROR", ippErrorString(status));
2506 cgiCopyTemplateLang("error.tmpl");
2507 }
2508 else
2509 cgiCopyTemplateLang("class-deleted.tmpl");
2510
2511 cgiEndHTML();
2512 }
2513
2514
2515 /*
2516 * 'do_delete_printer()' - Delete a printer...
2517 */
2518
2519 static void
2520 do_delete_printer(http_t *http, /* I - HTTP connection */
2521 cups_lang_t *language)/* I - Client's language */
2522 {
2523 ipp_t *request, /* IPP request */
2524 *response; /* IPP response */
2525 char uri[HTTP_MAX_URI]; /* Job URI */
2526 const char *printer; /* Printer printer name */
2527 ipp_status_t status; /* Operation status... */
2528
2529
2530 if (cgiGetVariable("CONFIRM") == NULL)
2531 {
2532 cgiStartHTML("Delete Printer");
2533 cgiCopyTemplateLang("printer-confirm.tmpl");
2534 cgiEndHTML();
2535 return;
2536 }
2537
2538 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2539 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
2540 "/printers/%s", printer);
2541 else
2542 {
2543 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
2544 cgiStartHTML("Delete Printer");
2545 cgiCopyTemplateLang("error.tmpl");
2546 cgiEndHTML();
2547 return;
2548 }
2549
2550 /*
2551 * Build a CUPS_DELETE_PRINTER request, which requires the following
2552 * attributes:
2553 *
2554 * attributes-charset
2555 * attributes-natural-language
2556 * printer-uri
2557 */
2558
2559 request = ippNew();
2560
2561 request->request.op.operation_id = CUPS_DELETE_PRINTER;
2562 request->request.op.request_id = 1;
2563
2564 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2565 "attributes-charset", NULL, cupsLangEncoding(language));
2566
2567 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2568 "attributes-natural-language", NULL, language->language);
2569
2570 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2571 NULL, uri);
2572
2573 /*
2574 * Do the request and get back a response...
2575 */
2576
2577 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
2578 {
2579 status = response->request.status.status_code;
2580
2581 ippDelete(response);
2582 }
2583 else
2584 status = cupsLastError();
2585
2586 cgiStartHTML("Delete Printer");
2587
2588 if (status > IPP_OK_CONFLICT)
2589 {
2590 cgiSetVariable("ERROR", ippErrorString(status));
2591 cgiCopyTemplateLang("error.tmpl");
2592 }
2593 else
2594 cgiCopyTemplateLang("printer-deleted.tmpl");
2595
2596 cgiEndHTML();
2597 }
2598
2599
2600 /*
2601 * 'do_menu()' - Show the main menu...
2602 */
2603
2604 static void
2605 do_menu(http_t *http, /* I - HTTP connection */
2606 cups_lang_t *language) /* I - Client's language */
2607 {
2608 cups_file_t *cupsd; /* cupsd.conf file */
2609 char line[1024], /* Line from cupsd.conf file */
2610 *value; /* Value on line */
2611 const char *server_root; /* Location of config files */
2612 ipp_t *request, /* IPP request */
2613 *response; /* IPP response */
2614 ipp_attribute_t *attr; /* IPP attribute */
2615
2616
2617 /*
2618 * Locate the cupsd.conf file...
2619 */
2620
2621 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
2622 server_root = CUPS_SERVERROOT;
2623
2624 snprintf(line, sizeof(line), "%s/cupsd.conf", server_root);
2625
2626 cgiStartHTML("Administration");
2627
2628 printf("<!-- \"%s\" -->\n", line);
2629
2630 /*
2631 * Open the cupsd.conf file...
2632 */
2633
2634 if ((cupsd = cupsFileOpen(line, "r")) == NULL)
2635 {
2636 /*
2637 * Unable to open - log an error...
2638 */
2639
2640 cgiStartHTML("Administration");
2641 cgiSetVariable("ERROR", strerror(errno));
2642 cgiCopyTemplateLang("error.tmpl");
2643 cgiEndHTML();
2644
2645 perror(line);
2646 }
2647 else
2648 {
2649 /*
2650 * Read the file, keeping track of what settings are enabled...
2651 */
2652
2653 int remote_access = 0, /* Remote access allowed? */
2654 remote_admin = 0, /* Remote administration allowed? */
2655 browsing = 1, /* Browsing enabled? */
2656 browse_allow = 1, /* Browse address set? */
2657 browse_address = 0, /* Browse address set? */
2658 cancel_policy = 1, /* Cancel-job policy set? */
2659 debug_logging = 0; /* LogLevel debug set? */
2660 int linenum = 0, /* Line number in file */
2661 in_policy = 0, /* In a policy section? */
2662 in_cancel_job = 0, /* In a cancel-job section? */
2663 in_admin_location = 0; /* In the /admin location? */
2664
2665
2666 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
2667 {
2668 if (!strcasecmp(line, "Port"))
2669 {
2670 remote_access = 1;
2671 }
2672 else if (!strcasecmp(line, "Listen"))
2673 {
2674 char *port; /* Pointer to port number, if any */
2675
2676
2677 if ((port = strrchr(value, ':')) != NULL)
2678 *port = '\0';
2679
2680 if (strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1"))
2681 remote_access = 1;
2682 }
2683 else if (!strcasecmp(line, "Browsing"))
2684 {
2685 browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") ||
2686 !strcasecmp(value, "true");
2687 }
2688 else if (!strcasecmp(line, "BrowseAddress"))
2689 {
2690 browse_address = 1;
2691 }
2692 else if (!strcasecmp(line, "BrowseAllow"))
2693 {
2694 browse_allow = 1;
2695 }
2696 else if (!strcasecmp(line, "BrowseOrder"))
2697 {
2698 browse_allow = !strncasecmp(value, "deny,", 5);
2699 }
2700 else if (!strcasecmp(line, "LogLevel"))
2701 {
2702 debug_logging = !strncasecmp(value, "debug", 5);
2703 }
2704 else if (!strcasecmp(line, "<Policy") && !strcasecmp(value, "default"))
2705 {
2706 in_policy = 1;
2707 }
2708 else if (!strcasecmp(line, "</Policy>"))
2709 {
2710 in_policy = 0;
2711 }
2712 else if (!strcasecmp(line, "<Limit") && in_policy)
2713 {
2714 /*
2715 * See if the policy limit is for the Cancel-Job operation...
2716 */
2717
2718 char *valptr; /* Pointer into value */
2719
2720
2721 while (*value)
2722 {
2723 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
2724
2725 if (*valptr)
2726 *valptr++ = '\0';
2727
2728 if (!strcasecmp(value, "cancel-job") || !strcasecmp(value, "all"))
2729 {
2730 in_cancel_job = 1;
2731 break;
2732 }
2733
2734 for (value = valptr; isspace(*value & 255); value ++);
2735 }
2736 }
2737 else if (!strcasecmp(line, "</Limit>"))
2738 {
2739 in_cancel_job = 0;
2740 }
2741 else if (!strcasecmp(line, "Require") && in_cancel_job)
2742 {
2743 cancel_policy = 0;
2744 }
2745 else if (!strcasecmp(line, "<Location") && !strcasecmp(value, "/admin"))
2746 {
2747 in_admin_location = 1;
2748 }
2749 else if (!strcasecmp(line, "</Location>"))
2750 {
2751 in_admin_location = 0;
2752 }
2753 else if (!strcasecmp(line, "Allow") && in_admin_location &&
2754 strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1"))
2755 {
2756 remote_admin = 1;
2757 }
2758 }
2759
2760 cupsFileClose(cupsd);
2761
2762 if (browsing && browse_allow)
2763 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2764
2765 if (remote_access && browsing && browse_address)
2766 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2767
2768 if (remote_access && remote_admin)
2769 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2770
2771 if (cancel_policy)
2772 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2773
2774 if (debug_logging)
2775 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2776 }
2777
2778 /*
2779 * Get the list of printers and their devices...
2780 */
2781
2782 request = ippNew();
2783 request->request.op.operation_id = CUPS_GET_PRINTERS;
2784 request->request.op.request_id = 1;
2785
2786 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2787 "attributes-charset", NULL, cupsLangEncoding(language));
2788
2789 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2790 "attributes-natural-language", NULL, language->language);
2791
2792 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2793 "requested-attributes", NULL, "device-uri");
2794
2795 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2796 CUPS_PRINTER_LOCAL);
2797 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2798 CUPS_PRINTER_LOCAL);
2799
2800 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2801 {
2802 /*
2803 * Got the printer list, now load the devices...
2804 */
2805
2806 int i; /* Looping var */
2807 int num_printer_devices; /* Number of devices for local printers */
2808 char **printer_devices; /* Printer devices for local printers */
2809
2810
2811 /*
2812 * Count the number of printers we have...
2813 */
2814
2815 for (num_printer_devices = 0,
2816 attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2817 attr;
2818 num_printer_devices ++,
2819 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI));
2820
2821 if (num_printer_devices > 0)
2822 {
2823 /*
2824 * Allocate an array and copy the device strings...
2825 */
2826
2827 printer_devices = calloc(num_printer_devices, sizeof(char *));
2828
2829 for (i = 0, attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2830 attr;
2831 i ++, attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2832 {
2833 printer_devices[i] = strdup(attr->values[0].string.text);
2834 }
2835
2836 /*
2837 * Sort the printer devices as needed...
2838 */
2839
2840 if (num_printer_devices > 1)
2841 qsort(printer_devices, num_printer_devices, sizeof(char *),
2842 compare_printer_devices);
2843 }
2844 else
2845 printer_devices = NULL;
2846
2847 /*
2848 * Free the printer list and get the device list...
2849 */
2850
2851 ippDelete(response);
2852
2853 request = ippNew();
2854 request->request.op.operation_id = CUPS_GET_DEVICES;
2855 request->request.op.request_id = 1;
2856
2857 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2858 "attributes-charset", NULL, cupsLangEncoding(language));
2859
2860 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2861 "attributes-natural-language", NULL, language->language);
2862
2863 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2864 {
2865 /*
2866 * Got the device list, let's parse it...
2867 */
2868
2869 const char *device_uri, /* device-uri attribute value */
2870 *device_make_and_model, /* device-make-and-model value */
2871 *device_info; /* device-info value */
2872
2873
2874 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2875 {
2876 /*
2877 * Skip leading attributes until we hit a device...
2878 */
2879
2880 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2881 attr = attr->next;
2882
2883 if (!attr)
2884 break;
2885
2886 /*
2887 * Pull the needed attributes from this device...
2888 */
2889
2890 device_info = NULL;
2891 device_make_and_model = NULL;
2892 device_uri = NULL;
2893
2894 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2895 {
2896 if (strcmp(attr->name, "device-info") == 0 &&
2897 attr->value_tag == IPP_TAG_TEXT)
2898 device_info = attr->values[0].string.text;
2899
2900 if (strcmp(attr->name, "device-make-and-model") == 0 &&
2901 attr->value_tag == IPP_TAG_TEXT)
2902 device_make_and_model = attr->values[0].string.text;
2903
2904 if (strcmp(attr->name, "device-uri") == 0 &&
2905 attr->value_tag == IPP_TAG_URI)
2906 device_uri = attr->values[0].string.text;
2907
2908 attr = attr->next;
2909 }
2910
2911 /*
2912 * See if we have everything needed...
2913 */
2914
2915 if (device_info && device_make_and_model && device_uri &&
2916 strcasecmp(device_make_and_model, "unknown") &&
2917 strchr(device_uri, ':'))
2918 {
2919 /*
2920 * Yes, now see if there is already a printer for this
2921 * device...
2922 */
2923
2924 if (!bsearch(&device_uri, printer_devices, num_printer_devices,
2925 sizeof(char *), compare_printer_devices))
2926 {
2927 /*
2928 * Not found, so it must be a new printer...
2929 */
2930
2931 char options[1024], /* Form variables for this device */
2932 *options_ptr; /* Pointer into string */
2933 const char *ptr; /* Pointer into device string */
2934
2935
2936 /*
2937 * Format the printer name variable for this device...
2938 *
2939 * We use the device-info string first, then device-uri,
2940 * and finally device-make-and-model to come up with a
2941 * suitable name.
2942 */
2943
2944 strcpy(options, "PRINTER_NAME=");
2945 options_ptr = options + strlen(options);
2946
2947 if (strncasecmp(device_info, "unknown", 7))
2948 ptr = device_info;
2949 else if ((ptr = strstr(device_uri, "://")) != NULL)
2950 ptr += 3;
2951 else
2952 ptr = device_make_and_model;
2953
2954 for (;
2955 options_ptr < (options + sizeof(options) - 1) && *ptr;
2956 ptr ++)
2957 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.')
2958 *options_ptr++ = *ptr;
2959 else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_')
2960 *options_ptr++ = '_';
2961 else if (*ptr == '?' || *ptr == '(')
2962 break;
2963
2964 /*
2965 * Then add the make and model in the printer info, so
2966 * that MacOS clients see something reasonable...
2967 */
2968
2969 strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer"
2970 "&PRINTER_INFO=",
2971 sizeof(options) - (options_ptr - options));
2972 options_ptr += strlen(options_ptr);
2973
2974 cgiFormEncode(options_ptr, device_make_and_model,
2975 sizeof(options) - (options_ptr - options));
2976 options_ptr += strlen(options_ptr);
2977
2978 /*
2979 * Then copy the device URI...
2980 */
2981
2982 strlcpy(options_ptr, "&DEVICE_URI=",
2983 sizeof(options) - (options_ptr - options));
2984 options_ptr += strlen(options_ptr);
2985
2986 cgiFormEncode(options_ptr, device_uri,
2987 sizeof(options) - (options_ptr - options));
2988 options_ptr += strlen(options_ptr);
2989
2990 if (options_ptr < (options + sizeof(options) - 1))
2991 {
2992 *options_ptr++ = '|';
2993 cgiFormEncode(options_ptr, device_make_and_model,
2994 sizeof(options) - (options_ptr - options));
2995 }
2996
2997 /*
2998 * Finally, set the form variables for this printer...
2999 */
3000
3001 cgiSetArray("device_info", i, device_info);
3002 cgiSetArray("device_make_and_model", i, device_make_and_model);
3003 cgiSetArray("device_options", i, options);
3004 cgiSetArray("device_uri", i, device_uri);
3005 i ++;
3006 }
3007 }
3008
3009 if (!attr)
3010 break;
3011 }
3012
3013 /*
3014 * Free the device list...
3015 */
3016
3017 ippDelete(response);
3018
3019 if (num_printer_devices)
3020 free(printer_devices);
3021 }
3022 }
3023
3024 /*
3025 * Finally, show the main menu template...
3026 */
3027
3028 cgiCopyTemplateLang("admin.tmpl");
3029
3030 cgiEndHTML();
3031 }
3032
3033
3034 /*
3035 * 'do_printer_op()' - Do a printer operation.
3036 */
3037
3038 static void
3039 do_printer_op(http_t *http, /* I - HTTP connection */
3040 cups_lang_t *language, /* I - Client's language */
3041 ipp_op_t op, /* I - Operation to perform */
3042 const char *title) /* I - Title of page */
3043 {
3044 ipp_t *request, /* IPP request */
3045 *response; /* IPP response */
3046 char uri[HTTP_MAX_URI]; /* Printer URI */
3047 const char *printer; /* Printer name (purge-jobs) */
3048 ipp_status_t status; /* Operation status... */
3049
3050
3051 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3052 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
3053 "/printers/%s", printer);
3054 else
3055 {
3056 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
3057 cgiStartHTML(title);
3058 cgiCopyTemplateLang("error.tmpl");
3059 cgiEndHTML();
3060 return;
3061 }
3062
3063 /*
3064 * Build a printer request, which requires the following
3065 * attributes:
3066 *
3067 * attributes-charset
3068 * attributes-natural-language
3069 * printer-uri
3070 */
3071
3072 request = ippNew();
3073
3074 request->request.op.operation_id = op;
3075 request->request.op.request_id = 1;
3076
3077 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
3078 "attributes-charset", NULL, cupsLangEncoding(language));
3079
3080 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
3081 "attributes-natural-language", NULL, language->language);
3082
3083 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3084 NULL, uri);
3085
3086 /*
3087 * Do the request and get back a response...
3088 */
3089
3090 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3091 {
3092 status = response->request.status.status_code;
3093
3094 ippDelete(response);
3095 }
3096 else
3097 status = cupsLastError();
3098
3099 if (status > IPP_OK_CONFLICT)
3100 {
3101 cgiStartHTML(title);
3102 cgiSetVariable("ERROR", ippErrorString(status));
3103 cgiCopyTemplateLang("error.tmpl");
3104 }
3105 else
3106 {
3107 /*
3108 * Redirect successful updates back to the printer page...
3109 */
3110
3111 char refresh[1024]; /* Refresh URL */
3112
3113 cgiFormEncode(uri, printer, sizeof(uri));
3114 snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
3115 uri);
3116 cgiSetVariable("refresh_page", refresh);
3117
3118 cgiStartHTML(title);
3119
3120 if (op == IPP_PAUSE_PRINTER)
3121 cgiCopyTemplateLang("printer-stop.tmpl");
3122 else if (op == IPP_RESUME_PRINTER)
3123 cgiCopyTemplateLang("printer-start.tmpl");
3124 else if (op == CUPS_ACCEPT_JOBS)
3125 cgiCopyTemplateLang("printer-accept.tmpl");
3126 else if (op == CUPS_REJECT_JOBS)
3127 cgiCopyTemplateLang("printer-reject.tmpl");
3128 else if (op == IPP_PURGE_JOBS)
3129 cgiCopyTemplateLang("printer-purge.tmpl");
3130 else if (op == CUPS_SET_DEFAULT)
3131 cgiCopyTemplateLang("printer-default.tmpl");
3132 }
3133
3134 cgiEndHTML();
3135 }
3136
3137
3138 /*
3139 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
3140 */
3141
3142 static void
3143 do_set_allowed_users(
3144 http_t *http, /* I - HTTP connection */
3145 cups_lang_t *language) /* I - Language */
3146 {
3147 int i; /* Looping var */
3148 ipp_t *request, /* IPP request */
3149 *response; /* IPP response */
3150 char uri[HTTP_MAX_URI]; /* Printer URI */
3151 const char *printer, /* Printer name (purge-jobs) */
3152 *users, /* List of users or groups */
3153 *type; /* Allow/deny type */
3154 int num_users; /* Number of users */
3155 char *ptr, /* Pointer into users string */
3156 *end, /* Pointer to end of users string */
3157 quote; /* Quote character */
3158 ipp_attribute_t *attr; /* Attribute */
3159 ipp_status_t status; /* Operation status... */
3160 static const char * const attrs[] = /* Requested attributes */
3161 {
3162 "requesting-user-name-allowed",
3163 "requesting-user-name-denied"
3164 };
3165
3166
3167 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3168 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
3169 "/printers/%s", printer);
3170 else
3171 {
3172 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
3173 cgiStartHTML("Set Allowed Users");
3174 cgiCopyTemplateLang("error.tmpl");
3175 cgiEndHTML();
3176 return;
3177 }
3178
3179 users = cgiGetVariable("users");
3180 type = cgiGetVariable("type");
3181
3182 if (!users || !type ||
3183 (strcmp(type, "requesting-user-name-allowed") &&
3184 strcmp(type, "requesting-user-name-denied")))
3185 {
3186 /*
3187 * Build a Get-Printer-Attributes request, which requires the following
3188 * attributes:
3189 *
3190 * attributes-charset
3191 * attributes-natural-language
3192 * printer-uri
3193 * requested-attributes
3194 */
3195
3196 request = ippNew();
3197
3198 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
3199 request->request.op.request_id = 1;
3200
3201 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
3202 "attributes-charset", NULL, cupsLangEncoding(language));
3203
3204 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
3205 "attributes-natural-language", NULL, language->language);
3206
3207 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3208 NULL, uri);
3209
3210 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
3211 "requested-attributes",
3212 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
3213
3214 /*
3215 * Do the request and get back a response...
3216 */
3217
3218 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3219 {
3220 status = response->request.status.status_code;
3221
3222 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3223
3224 ippDelete(response);
3225 }
3226 else
3227 status = cupsLastError();
3228
3229 cgiStartHTML("Set Allowed Users");
3230
3231 if (status > IPP_OK_CONFLICT)
3232 {
3233 cgiSetVariable("ERROR", ippErrorString(status));
3234 cgiCopyTemplateLang("error.tmpl");
3235 }
3236 else
3237 cgiCopyTemplateLang("users.tmpl");
3238
3239 cgiEndHTML();
3240 }
3241 else
3242 {
3243 /*
3244 * Save the changes...
3245 */
3246
3247 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
3248 {
3249 /*
3250 * Skip whitespace and commas...
3251 */
3252
3253 while (*ptr == ',' || isspace(*ptr & 255))
3254 ptr ++;
3255
3256 if (*ptr == '\'' || *ptr == '\"')
3257 {
3258 /*
3259 * Scan quoted name...
3260 */
3261
3262 quote = *ptr++;
3263
3264 for (end = ptr; *end; end ++)
3265 if (*end == quote)
3266 break;
3267 }
3268 else
3269 {
3270 /*
3271 * Scan space or comma-delimited name...
3272 */
3273
3274 for (end = ptr; *end; end ++)
3275 if (isspace(*end & 255) || *end == ',')
3276 break;
3277 }
3278
3279 /*
3280 * Advance to the next name...
3281 */
3282
3283 ptr = end;
3284 }
3285
3286 /*
3287 * Build a CUPS-Add-Printer request, which requires the following
3288 * attributes:
3289 *
3290 * attributes-charset
3291 * attributes-natural-language
3292 * printer-uri
3293 * requesting-user-name-{allowed,denied}
3294 */
3295
3296 request = ippNew();
3297
3298 request->request.op.operation_id = CUPS_ADD_PRINTER;
3299 request->request.op.request_id = 1;
3300
3301 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
3302 "attributes-charset", NULL, cupsLangEncoding(language));
3303
3304 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
3305 "attributes-natural-language", NULL, language->language);
3306
3307 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3308 NULL, uri);
3309
3310 if (num_users == 0)
3311 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
3312 "requesting-user-name-allowed", NULL, "all");
3313 else
3314 {
3315 attr = ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
3316 type, num_users, NULL, NULL);
3317
3318 for (i = 0, ptr = (char *)users; *ptr; i ++)
3319 {
3320 /*
3321 * Skip whitespace and commas...
3322 */
3323
3324 while (*ptr == ',' || isspace(*ptr & 255))
3325 ptr ++;
3326
3327 if (*ptr == '\'' || *ptr == '\"')
3328 {
3329 /*
3330 * Scan quoted name...
3331 */
3332
3333 quote = *ptr++;
3334
3335 for (end = ptr; *end; end ++)
3336 if (*end == quote)
3337 break;
3338 }
3339 else
3340 {
3341 /*
3342 * Scan space or comma-delimited name...
3343 */
3344
3345 for (end = ptr; *end; end ++)
3346 if (isspace(*end & 255) || *end == ',')
3347 break;
3348 }
3349
3350 /*
3351 * Terminate the name...
3352 */
3353
3354 if (*end)
3355 *end++ = '\0';
3356
3357 /*
3358 * Add the name...
3359 */
3360
3361 attr->values[i].string.text = strdup(ptr);
3362
3363 /*
3364 * Advance to the next name...
3365 */
3366
3367 ptr = end;
3368 }
3369 }
3370
3371 /*
3372 * Do the request and get back a response...
3373 */
3374
3375 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3376 {
3377 status = response->request.status.status_code;
3378
3379 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3380
3381 ippDelete(response);
3382 }
3383 else
3384 status = cupsLastError();
3385
3386 if (status > IPP_OK_CONFLICT)
3387 {
3388 cgiStartHTML("Set Allowed Users");
3389 cgiSetVariable("ERROR", ippErrorString(status));
3390 cgiCopyTemplateLang("error.tmpl");
3391 }
3392 else
3393 {
3394 /*
3395 * Redirect successful updates back to the printer page...
3396 */
3397
3398 char refresh[1024]; /* Refresh URL */
3399
3400 cgiFormEncode(uri, printer, sizeof(uri));
3401 snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
3402 uri);
3403 cgiSetVariable("refresh_page", refresh);
3404
3405 cgiStartHTML("Set Allowed Users");
3406
3407 cgiCopyTemplateLang("printer-modified.tmpl");
3408 }
3409
3410 cgiEndHTML();
3411 }
3412 }
3413
3414
3415 /*
3416 * 'do_set_sharing()' - Set printer-is-shared value...
3417 */
3418
3419 static void
3420 do_set_sharing(http_t *http, /* I - HTTP connection */
3421 cups_lang_t *language) /* I - Language */
3422 {
3423 ipp_t *request, /* IPP request */
3424 *response; /* IPP response */
3425 char uri[HTTP_MAX_URI]; /* Printer URI */
3426 const char *printer, /* Printer name */
3427 *shared; /* Sharing value */
3428 ipp_status_t status; /* Operation status... */
3429
3430
3431 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3432 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
3433 "/printers/%s", printer);
3434 else
3435 {
3436 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
3437 cgiStartHTML("Set Publishing");
3438 cgiCopyTemplateLang("error.tmpl");
3439 cgiEndHTML();
3440 return;
3441 }
3442
3443 if ((shared = cgiGetVariable("SHARED")) == NULL)
3444 {
3445 cgiSetVariable("ERROR", "Missing SHARED parameter");
3446 cgiStartHTML("Set Publishing");
3447 cgiCopyTemplateLang("error.tmpl");
3448 cgiEndHTML();
3449 return;
3450 }
3451
3452 /*
3453 * Build a CUPS-Add-Printer request, which requires the following
3454 * attributes:
3455 *
3456 * attributes-charset
3457 * attributes-natural-language
3458 * printer-uri
3459 * printer-is-shared
3460 */
3461
3462 request = ippNew();
3463
3464 request->request.op.operation_id = CUPS_ADD_PRINTER;
3465 request->request.op.request_id = 1;
3466
3467 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
3468 "attributes-charset", NULL, cupsLangEncoding(language));
3469
3470 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
3471 "attributes-natural-language", NULL, language->language);
3472
3473 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3474 NULL, uri);
3475
3476 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3477
3478 /*
3479 * Do the request and get back a response...
3480 */
3481
3482 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3483 {
3484 status = response->request.status.status_code;
3485
3486 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3487
3488 ippDelete(response);
3489 }
3490 else
3491 status = cupsLastError();
3492
3493 if (status > IPP_OK_CONFLICT)
3494 {
3495 cgiStartHTML("Set Publishing");
3496 cgiSetVariable("ERROR", ippErrorString(status));
3497 cgiCopyTemplateLang("error.tmpl");
3498 }
3499 else
3500 {
3501 /*
3502 * Redirect successful updates back to the printer page...
3503 */
3504
3505 char refresh[1024]; /* Refresh URL */
3506
3507 cgiFormEncode(uri, printer, sizeof(uri));
3508 snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
3509 uri);
3510 cgiSetVariable("refresh_page", refresh);
3511
3512 cgiStartHTML("Set Publishing");
3513
3514 cgiCopyTemplateLang("printer-modified.tmpl");
3515 }
3516
3517 cgiEndHTML();
3518 }
3519
3520
3521 /*
3522 * 'match_string()' - Return the number of matching characters.
3523 */
3524
3525 static int /* O - Number of matching characters */
3526 match_string(const char *a, /* I - First string */
3527 const char *b) /* I - Second string */
3528 {
3529 int count; /* Number of matching characters */
3530
3531
3532 /*
3533 * Loop through both strings until we hit the end of either or we find
3534 * a non-matching character. For the purposes of comparison, we ignore
3535 * whitespace and do a case-insensitive comparison so that we have a
3536 * better chance of finding a match...
3537 */
3538
3539 for (count = 0; *a && *b; a++, b++, count ++)
3540 {
3541 /*
3542 * Skip leading whitespace characters...
3543 */
3544
3545 while (isspace(*a & 255))
3546 a ++;
3547
3548 while (isspace(*b & 255))
3549 b ++;
3550
3551 /*
3552 * Break out if we run out of characters...
3553 */
3554
3555 if (!*a || !*b)
3556 break;
3557
3558 /*
3559 * Do a case-insensitive comparison of the next two chars...
3560 */
3561
3562 if (tolower(*a & 255) != tolower(*b & 255))
3563 break;
3564 }
3565
3566 return (count);
3567 }
3568
3569
3570 /*
3571 * End of "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $".
3572 */