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