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