]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
Load cups into easysw/current.
[thirdparty/cups.git] / cgi-bin / admin.c
1 /*
2 * "$Id: admin.c 5360 2006-03-30 17:02:17Z mike $"
3 *
4 * Administration CGI for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Main entry for CGI.
27 * 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...
33 * do_export() - Export printers to Samba...
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/adminutil.h>
47 #include <cups/file.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <sys/wait.h>
52
53
54 /*
55 * Local functions...
56 */
57
58 static void do_am_class(http_t *http, int modify);
59 static void do_am_printer(http_t *http, int modify);
60 static void do_config_printer(http_t *http);
61 static void do_config_server(http_t *http);
62 static void do_delete_class(http_t *http);
63 static void do_delete_printer(http_t *http);
64 static void do_export(http_t *http);
65 static void do_menu(http_t *http);
66 static void do_printer_op(http_t *http,
67 ipp_op_t op, const char *title);
68 static void do_set_allowed_users(http_t *http);
69 static void do_set_sharing(http_t *http);
70 static int match_string(const char *a, const char *b);
71
72
73 /*
74 * 'main()' - Main entry for CGI.
75 */
76
77 int /* O - Exit status */
78 main(int argc, /* I - Number of command-line arguments */
79 char *argv[]) /* I - Command-line arguments */
80 {
81 http_t *http; /* Connection to the server */
82 const char *op; /* Operation name */
83
84
85 /*
86 * Connect to the HTTP server...
87 */
88
89 fputs("DEBUG: admin.cgi started...\n", stderr);
90
91 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
92
93 if (!http)
94 {
95 perror("ERROR: Unable to connect to cupsd");
96 fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n", cupsServer());
97 fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
98 fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
99 exit(1);
100 }
101
102 fprintf(stderr, "DEBUG: http=%p\n", http);
103
104 /*
105 * Set the web interface section...
106 */
107
108 cgiSetVariable("SECTION", "admin");
109
110 /*
111 * See if we have form data...
112 */
113
114 if (!cgiInitialize())
115 {
116 /*
117 * Nope, send the administration menu...
118 */
119
120 fputs("DEBUG: No form data, showing main menu...\n", stderr);
121
122 do_menu(http);
123 }
124 else if ((op = cgiGetVariable("OP")) != NULL)
125 {
126 /*
127 * Do the operation...
128 */
129
130 fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
131
132 if (!strcmp(op, "redirect"))
133 {
134 const char *url; /* Redirection URL... */
135 char prefix[1024]; /* URL prefix */
136
137
138 if (getenv("HTTPS"))
139 snprintf(prefix, sizeof(prefix), "https://%s:%s",
140 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
141 else
142 snprintf(prefix, sizeof(prefix), "http://%s:%s",
143 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
144
145 if ((url = cgiGetVariable("URL")) != NULL)
146 printf("Location: %s%s\n\n", prefix, url);
147 else
148 printf("Location: %s/admin\n\n", prefix);
149 }
150 else if (!strcmp(op, "start-printer"))
151 do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Printer")));
152 else if (!strcmp(op, "stop-printer"))
153 do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Printer")));
154 else if (!strcmp(op, "start-class"))
155 do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Class")));
156 else if (!strcmp(op, "stop-class"))
157 do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Class")));
158 else if (!strcmp(op, "accept-jobs"))
159 do_printer_op(http, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
160 else if (!strcmp(op, "reject-jobs"))
161 do_printer_op(http, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
162 else if (!strcmp(op, "purge-jobs"))
163 do_printer_op(http, IPP_PURGE_JOBS, cgiText(_("Purge Jobs")));
164 else if (!strcmp(op, "set-allowed-users"))
165 do_set_allowed_users(http);
166 else if (!strcmp(op, "set-as-default"))
167 do_printer_op(http, CUPS_SET_DEFAULT, cgiText(_("Set As Default")));
168 else if (!strcmp(op, "set-sharing"))
169 do_set_sharing(http);
170 else if (!strcmp(op, "add-class"))
171 do_am_class(http, 0);
172 else if (!strcmp(op, "add-printer"))
173 do_am_printer(http, 0);
174 else if (!strcmp(op, "modify-class"))
175 do_am_class(http, 1);
176 else if (!strcmp(op, "modify-printer"))
177 do_am_printer(http, 1);
178 else if (!strcmp(op, "delete-class"))
179 do_delete_class(http);
180 else if (!strcmp(op, "delete-printer"))
181 do_delete_printer(http);
182 else if (!strcmp(op, "set-printer-options"))
183 do_config_printer(http);
184 else if (!strcmp(op, "config-server"))
185 do_config_server(http);
186 else if (!strcmp(op, "export-samba"))
187 do_export(http);
188 else
189 {
190 /*
191 * Bad operation code... Display an error...
192 */
193
194 cgiStartHTML(cgiText(_("Administration")));
195 cgiCopyTemplateLang("error-op.tmpl");
196 cgiEndHTML();
197 }
198 }
199 else
200 {
201 /*
202 * Form data but no operation code... Display an error...
203 */
204
205 cgiStartHTML(cgiText(_("Administration")));
206 cgiCopyTemplateLang("error-op.tmpl");
207 cgiEndHTML();
208 }
209
210 /*
211 * Close the HTTP server connection...
212 */
213
214 httpClose(http);
215
216 /*
217 * Return with no errors...
218 */
219
220 return (0);
221 }
222
223
224 /*
225 * 'do_am_class()' - Add or modify a class.
226 */
227
228 static void
229 do_am_class(http_t *http, /* I - HTTP connection */
230 int modify) /* I - Modify the printer? */
231 {
232 int i, j; /* Looping vars */
233 int element; /* Element number */
234 int num_printers; /* Number of printers */
235 ipp_t *request, /* IPP request */
236 *response; /* IPP response */
237 ipp_attribute_t *attr; /* member-uris attribute */
238 char uri[HTTP_MAX_URI]; /* Device or printer URI */
239 const char *name, /* Pointer to class name */
240 *ptr; /* Pointer to CGI variable */
241 const char *title; /* Title of page */
242 static const char * const pattrs[] = /* Requested printer attributes */
243 {
244 "member-names",
245 "printer-info",
246 "printer-location"
247 };
248
249
250 title = cgiText(modify ? _("Modify Class") : _("Add Class"));
251 name = cgiGetVariable("PRINTER_NAME");
252
253 if (cgiGetVariable("PRINTER_LOCATION") == NULL)
254 {
255 /*
256 * Build a CUPS_GET_PRINTERS request, which requires the
257 * following attributes:
258 *
259 * attributes-charset
260 * attributes-natural-language
261 * printer-uri
262 */
263
264 request = ippNewRequest(CUPS_GET_PRINTERS);
265
266 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
267 NULL, "ipp://localhost/printers");
268
269 /*
270 * Do the request and get back a response...
271 */
272
273 if ((response = cupsDoRequest(http, request, "/")) != NULL)
274 {
275 /*
276 * Create MEMBER_URIS and MEMBER_NAMES arrays...
277 */
278
279 for (element = 0, attr = response->attrs;
280 attr != NULL;
281 attr = attr->next)
282 if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
283 {
284 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
285 (!name || strcasecmp(name, ptr + 1)))
286 {
287 /*
288 * Don't show the current class...
289 */
290
291 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
292 element ++;
293 }
294 }
295
296 for (element = 0, attr = response->attrs;
297 attr != NULL;
298 attr = attr->next)
299 if (attr->name && !strcmp(attr->name, "printer-name"))
300 {
301 if (!name || strcasecmp(name, attr->values[0].string.text))
302 {
303 /*
304 * Don't show the current class...
305 */
306
307 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
308 element ++;
309 }
310 }
311
312 num_printers = cgiGetSize("MEMBER_URIS");
313
314 ippDelete(response);
315 }
316 else
317 num_printers = 0;
318
319 if (modify)
320 {
321 /*
322 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
323 * following attributes:
324 *
325 * attributes-charset
326 * attributes-natural-language
327 * printer-uri
328 */
329
330 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
331
332 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
333 "localhost", 0, "/classes/%s", name);
334 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
335 NULL, uri);
336
337 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
338 "requested-attributes",
339 (int)(sizeof(pattrs) / sizeof(pattrs[0])),
340 NULL, pattrs);
341
342 /*
343 * Do the request and get back a response...
344 */
345
346 if ((response = cupsDoRequest(http, request, "/")) != NULL)
347 {
348 if ((attr = ippFindAttribute(response, "member-names",
349 IPP_TAG_NAME)) != NULL)
350 {
351 /*
352 * Mark any current members in the class...
353 */
354
355 for (j = 0; j < num_printers; j ++)
356 cgiSetArray("MEMBER_SELECTED", j, "");
357
358 for (i = 0; i < attr->num_values; i ++)
359 {
360 for (j = 0; j < num_printers; j ++)
361 {
362 if (!strcasecmp(attr->values[i].string.text,
363 cgiGetArray("MEMBER_NAMES", j)))
364 {
365 cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
366 break;
367 }
368 }
369 }
370 }
371
372 if ((attr = ippFindAttribute(response, "printer-info",
373 IPP_TAG_TEXT)) != NULL)
374 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
375
376 if ((attr = ippFindAttribute(response, "printer-location",
377 IPP_TAG_TEXT)) != NULL)
378 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
379
380 ippDelete(response);
381 }
382
383 /*
384 * Update the location and description of an existing printer...
385 */
386
387 cgiStartHTML(title);
388 cgiCopyTemplateLang("modify-class.tmpl");
389 }
390 else
391 {
392 /*
393 * Get the name, location, and description for a new printer...
394 */
395
396 cgiStartHTML(title);
397 cgiCopyTemplateLang("add-class.tmpl");
398 }
399
400 cgiEndHTML();
401
402 return;
403 }
404
405 for (ptr = name; *ptr; ptr ++)
406 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
407 break;
408
409 if (*ptr || ptr == name || strlen(name) > 127)
410 {
411 cgiSetVariable("ERROR",
412 cgiText(_("The class name may only contain up to "
413 "127 printable characters and may not "
414 "contain spaces, slashes (/), or the "
415 "pound sign (#).")));
416 cgiStartHTML(title);
417 cgiCopyTemplateLang("error.tmpl");
418 cgiEndHTML();
419 return;
420 }
421
422 /*
423 * Build a CUPS_ADD_CLASS request, which requires the following
424 * attributes:
425 *
426 * attributes-charset
427 * attributes-natural-language
428 * printer-uri
429 * printer-location
430 * printer-info
431 * printer-is-accepting-jobs
432 * printer-state
433 * member-uris
434 */
435
436 request = ippNewRequest(CUPS_ADD_CLASS);
437
438 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
439 "localhost", 0, "/classes/%s",
440 cgiGetVariable("PRINTER_NAME"));
441 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
442 NULL, uri);
443
444 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
445 NULL, cgiGetVariable("PRINTER_LOCATION"));
446
447 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
448 NULL, cgiGetVariable("PRINTER_INFO"));
449
450 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
451
452 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
453 IPP_PRINTER_IDLE);
454
455 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
456 {
457 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
458 num_printers, NULL, NULL);
459 for (i = 0; i < num_printers; i ++)
460 attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i));
461 }
462
463 /*
464 * Do the request and get back a response...
465 */
466
467 ippDelete(cupsDoRequest(http, request, "/admin/"));
468
469 if (cupsLastError() > IPP_OK_CONFLICT)
470 {
471 cgiStartHTML(title);
472 cgiShowIPPError(modify ? _("Unable to modify class:") :
473 _("Unable to add class:"));
474 }
475 else
476 {
477 /*
478 * Redirect successful updates back to the class page...
479 */
480
481 char refresh[1024]; /* Refresh URL */
482
483 cgiFormEncode(uri, name, sizeof(uri));
484 snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=/classes/%s",
485 uri);
486 cgiSetVariable("refresh_page", refresh);
487
488 cgiStartHTML(title);
489
490 if (modify)
491 cgiCopyTemplateLang("class-modified.tmpl");
492 else
493 cgiCopyTemplateLang("class-added.tmpl");
494 }
495
496 cgiEndHTML();
497 }
498
499
500 /*
501 * 'do_am_printer()' - Add or modify a printer.
502 */
503
504 static void
505 do_am_printer(http_t *http, /* I - HTTP connection */
506 int modify) /* I - Modify the printer? */
507 {
508 int i; /* Looping var */
509 int element; /* Element number */
510 ipp_attribute_t *attr, /* Current attribute */
511 *last; /* Last attribute */
512 ipp_t *request, /* IPP request */
513 *response, /* IPP response */
514 *oldinfo; /* Old printer information */
515 const cgi_file_t *file; /* Uploaded file, if any */
516 const char *var; /* CGI variable */
517 char uri[HTTP_MAX_URI], /* Device or printer URI */
518 *uriptr; /* Pointer into URI */
519 int maxrate; /* Maximum baud rate */
520 char baudrate[255]; /* Baud rate string */
521 const char *name, /* Pointer to class name */
522 *ptr; /* Pointer to CGI variable */
523 const char *title; /* Title of page */
524 static int baudrates[] = /* Baud rates */
525 {
526 1200,
527 2400,
528 4800,
529 9600,
530 19200,
531 38400,
532 57600,
533 115200,
534 230400,
535 460800
536 };
537
538
539 fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
540 cgiGetVariable("DEVICE_URI"));
541
542 title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
543
544 if (modify)
545 {
546 /*
547 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
548 * following attributes:
549 *
550 * attributes-charset
551 * attributes-natural-language
552 * printer-uri
553 */
554
555 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
556
557 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
558 "localhost", 0, "/printers/%s",
559 cgiGetVariable("PRINTER_NAME"));
560 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
561 NULL, uri);
562
563 /*
564 * Do the request and get back a response...
565 */
566
567 oldinfo = cupsDoRequest(http, request, "/");
568 }
569 else
570 oldinfo = NULL;
571
572 if ((name = cgiGetVariable("PRINTER_NAME")) == NULL ||
573 cgiGetVariable("PRINTER_LOCATION") == NULL)
574 {
575 cgiStartHTML(title);
576
577 if (modify)
578 {
579 /*
580 * Update the location and description of an existing printer...
581 */
582
583 if (oldinfo)
584 cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0);
585
586 cgiCopyTemplateLang("modify-printer.tmpl");
587 }
588 else
589 {
590 /*
591 * Get the name, location, and description for a new printer...
592 */
593
594 cgiCopyTemplateLang("add-printer.tmpl");
595 }
596
597 cgiEndHTML();
598
599 if (oldinfo)
600 ippDelete(oldinfo);
601
602 return;
603 }
604
605 for (ptr = name; *ptr; ptr ++)
606 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
607 break;
608
609 if (*ptr || ptr == name || strlen(name) > 127)
610 {
611 cgiSetVariable("ERROR",
612 cgiText(_("The printer name may only contain up to "
613 "127 printable characters and may not "
614 "contain spaces, slashes (/), or the "
615 "pound sign (#).")));
616 cgiStartHTML(title);
617 cgiCopyTemplateLang("error.tmpl");
618 cgiEndHTML();
619 return;
620 }
621
622 file = cgiGetFile();
623
624 if (file)
625 {
626 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
627 fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
628 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
629 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
630 }
631
632 if ((var = cgiGetVariable("DEVICE_URI")) == NULL)
633 {
634 /*
635 * Build a CUPS_GET_DEVICES request, which requires the following
636 * attributes:
637 *
638 * attributes-charset
639 * attributes-natural-language
640 * printer-uri
641 */
642
643 fputs("DEBUG: Getting list of devices...\n", stderr);
644
645 request = ippNewRequest(CUPS_GET_DEVICES);
646
647 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
648 NULL, "ipp://localhost/printers/");
649
650 /*
651 * Do the request and get back a response...
652 */
653
654 fprintf(stderr, "DEBUG: http=%p (%s)\n", http, http->hostname);
655
656 if ((response = cupsDoRequest(http, request, "/")) != NULL)
657 {
658 fputs("DEBUG: Got device list!\n", stderr);
659
660 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
661 ippDelete(response);
662 }
663 else
664 fprintf(stderr,
665 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
666 cupsLastError(), cupsLastErrorString());
667
668 /*
669 * Let the user choose...
670 */
671
672 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
673 {
674 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
675 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
676 *uriptr = '\0';
677
678 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
679 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
680 }
681
682 cgiStartHTML(title);
683 cgiCopyTemplateLang("choose-device.tmpl");
684 cgiEndHTML();
685 }
686 else if (strchr(var, '/') == NULL)
687 {
688 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
689 {
690 /*
691 * Set the current device URI for the form to the old one...
692 */
693
694 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
695 cgiSetVariable("DEVICE_URI", attr->values[0].string.text);
696 }
697
698 /*
699 * User needs to set the full URI...
700 */
701
702 cgiStartHTML(title);
703 cgiCopyTemplateLang("choose-uri.tmpl");
704 cgiEndHTML();
705 }
706 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
707 {
708 /*
709 * Need baud rate, parity, etc.
710 */
711
712 if ((var = strchr(var, '?')) != NULL &&
713 strncmp(var, "?baud=", 6) == 0)
714 maxrate = atoi(var + 6);
715 else
716 maxrate = 19200;
717
718 for (i = 0; i < 10; i ++)
719 if (baudrates[i] > maxrate)
720 break;
721 else
722 {
723 sprintf(baudrate, "%d", baudrates[i]);
724 cgiSetArray("BAUDRATES", i, baudrate);
725 }
726
727 cgiStartHTML(title);
728 cgiCopyTemplateLang("choose-serial.tmpl");
729 cgiEndHTML();
730 }
731 else if (!file && (var = cgiGetVariable("PPD_NAME")) == NULL)
732 {
733 if (modify)
734 {
735 /*
736 * Get the PPD file...
737 */
738
739 int fd; /* PPD file */
740 char filename[1024]; /* PPD filename */
741 ppd_file_t *ppd; /* PPD information */
742 char buffer[1024]; /* Buffer */
743 int bytes; /* Number of bytes */
744 http_status_t get_status; /* Status of GET */
745
746
747 /* TODO: Use cupsGetFile() API... */
748 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
749
750 if (httpGet(http, uri))
751 httpGet(http, uri);
752
753 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
754
755 if (get_status != HTTP_OK)
756 {
757 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
758 uri, get_status, httpStatus(get_status));
759 }
760 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
761 {
762 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
763 write(fd, buffer, bytes);
764
765 close(fd);
766
767 if ((ppd = ppdOpenFile(filename)) != NULL)
768 {
769 if (ppd->manufacturer)
770 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
771
772 if (ppd->nickname)
773 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
774
775 ppdClose(ppd);
776 unlink(filename);
777 }
778 else
779 {
780 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
781 filename, ppdErrorString(ppdLastError(&bytes)));
782 }
783 }
784 else
785 {
786 httpFlush(http);
787
788 fprintf(stderr,
789 "ERROR: Unable to create temporary file for PPD file: %s\n",
790 strerror(errno));
791 }
792 }
793 else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL)
794 {
795 /*
796 * Extract make and make/model from device URI string...
797 */
798
799 char make[1024], /* Make string */
800 *makeptr; /* Pointer into make */
801
802
803 *uriptr++ = '\0';
804
805 strlcpy(make, uriptr, sizeof(make));
806
807 if ((makeptr = strchr(make, ' ')) != NULL)
808 *makeptr = '\0';
809 else if ((makeptr = strchr(make, '-')) != NULL)
810 *makeptr = '\0';
811 else if (!strncasecmp(make, "laserjet", 8) ||
812 !strncasecmp(make, "deskjet", 7) ||
813 !strncasecmp(make, "designjet", 9))
814 strcpy(make, "HP");
815 else if (!strncasecmp(make, "phaser", 6))
816 strcpy(make, "Xerox");
817 else if (!strncasecmp(make, "stylus", 6))
818 strcpy(make, "Epson");
819 else
820 strcpy(make, "Generic");
821
822 cgiSetVariable("CURRENT_MAKE", make);
823 cgiSetVariable("PPD_MAKE", make);
824 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
825 }
826
827 /*
828 * Build a CUPS_GET_PPDS request, which requires the following
829 * attributes:
830 *
831 * attributes-charset
832 * attributes-natural-language
833 * printer-uri
834 */
835
836 request = ippNewRequest(CUPS_GET_PPDS);
837
838 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
839 NULL, "ipp://localhost/printers/");
840
841 if ((var = cgiGetVariable("PPD_MAKE")) != NULL)
842 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
843 "ppd-make", NULL, var);
844 else
845 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
846 "requested-attributes", NULL, "ppd-make");
847
848 /*
849 * Do the request and get back a response...
850 */
851
852 if ((response = cupsDoRequest(http, request, "/")) != NULL)
853 {
854 /*
855 * Got the list of PPDs, see if the user has selected a make...
856 */
857
858 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
859
860 if (var == NULL)
861 {
862 /*
863 * Let the user choose a make...
864 */
865
866 for (element = 0, attr = response->attrs, last = NULL;
867 attr != NULL;
868 attr = attr->next)
869 if (attr->name && strcmp(attr->name, "ppd-make") == 0)
870 if (last == NULL ||
871 strcasecmp(last->values[0].string.text,
872 attr->values[0].string.text) != 0)
873 {
874 cgiSetArray("PPD_MAKE", element, attr->values[0].string.text);
875 element ++;
876 last = attr;
877 }
878
879 cgiStartHTML(title);
880 cgiCopyTemplateLang("choose-make.tmpl");
881 cgiEndHTML();
882 }
883 else
884 {
885 /*
886 * Let the user choose a model...
887 */
888
889 const char *make_model; /* Current make/model string */
890
891
892 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
893 {
894 /*
895 * Scan for "close" matches...
896 */
897
898 int match, /* Current match */
899 best_match, /* Best match so far */
900 count; /* Number of drivers */
901 const char *best, /* Best matching string */
902 *current; /* Current string */
903
904
905 count = cgiGetSize("PPD_MAKE_AND_MODEL");
906
907 for (i = 0, best_match = 0, best = NULL; i < count; i ++)
908 {
909 current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
910 match = match_string(make_model, current);
911
912 if (match > best_match)
913 {
914 best_match = match;
915 best = current;
916 }
917 }
918
919 if (best_match > strlen(var))
920 {
921 /*
922 * Found a match longer than the make...
923 */
924
925 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
926 }
927 }
928
929 cgiStartHTML(title);
930 cgiCopyTemplateLang("choose-model.tmpl");
931 cgiEndHTML();
932 }
933
934
935 ippDelete(response);
936 }
937 else
938 {
939 cgiStartHTML(title);
940 cgiShowIPPError(_("Unable to get list of printer drivers:"));
941 cgiCopyTemplateLang("error.tmpl");
942 cgiEndHTML();
943 }
944 }
945 else
946 {
947 /*
948 * Build a CUPS_ADD_PRINTER request, which requires the following
949 * attributes:
950 *
951 * attributes-charset
952 * attributes-natural-language
953 * printer-uri
954 * printer-location
955 * printer-info
956 * ppd-name
957 * device-uri
958 * printer-is-accepting-jobs
959 * printer-state
960 */
961
962 request = ippNewRequest(CUPS_ADD_PRINTER);
963
964 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
965 "localhost", 0, "/printers/%s",
966 cgiGetVariable("PRINTER_NAME"));
967 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
968 NULL, uri);
969
970 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
971 NULL, cgiGetVariable("PRINTER_LOCATION"));
972
973 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
974 NULL, cgiGetVariable("PRINTER_INFO"));
975
976 if (!file)
977 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
978 NULL, cgiGetVariable("PPD_NAME"));
979
980 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
981
982 /*
983 * Strip make and model from URI...
984 */
985
986 if ((uriptr = strrchr(uri, '|')) != NULL)
987 *uriptr = '\0';
988
989 if (!strncmp(uri, "serial:", 7))
990 {
991 /*
992 * Update serial port URI to include baud rate, etc.
993 */
994
995 if ((uriptr = strchr(uri, '?')) == NULL)
996 uriptr = uri + strlen(uri);
997
998 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
999 "?baud=%s+bits=%s+parity=%s+flow=%s",
1000 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1001 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1002 }
1003
1004 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1005 NULL, uri);
1006
1007 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1008
1009 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1010 IPP_PRINTER_IDLE);
1011
1012 /*
1013 * Do the request and get back a response...
1014 */
1015
1016 if (file)
1017 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
1018 else
1019 ippDelete(cupsDoRequest(http, request, "/admin/"));
1020
1021 if (cupsLastError() > IPP_OK_CONFLICT)
1022 {
1023 cgiStartHTML(title);
1024 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1025 _("Unable to add printer:"));
1026 }
1027 else
1028 {
1029 /*
1030 * Redirect successful updates back to the printer or set-options pages...
1031 */
1032
1033 char refresh[1024]; /* Refresh URL */
1034
1035
1036 cgiFormEncode(uri, name, sizeof(uri));
1037
1038 if (modify)
1039 snprintf(refresh, sizeof(refresh),
1040 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
1041 else
1042 snprintf(refresh, sizeof(refresh),
1043 "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri);
1044
1045 cgiSetVariable("refresh_page", refresh);
1046
1047 cgiStartHTML(title);
1048
1049 if (modify)
1050 cgiCopyTemplateLang("printer-modified.tmpl");
1051 else
1052 cgiCopyTemplateLang("printer-added.tmpl");
1053 }
1054
1055 cgiEndHTML();
1056 }
1057
1058 if (oldinfo)
1059 ippDelete(oldinfo);
1060 }
1061
1062
1063 /*
1064 * 'do_config_printer()' - Configure the default options for a printer.
1065 */
1066
1067 static void
1068 do_config_printer(http_t *http) /* I - HTTP connection */
1069 {
1070 int i, j, k, m; /* Looping vars */
1071 int have_options; /* Have options? */
1072 ipp_t *request, /* IPP request */
1073 *response; /* IPP response */
1074 ipp_attribute_t *attr; /* IPP attribute */
1075 char uri[HTTP_MAX_URI]; /* Job URI */
1076 const char *var; /* Variable value */
1077 const char *printer; /* Printer printer name */
1078 const char *filename; /* PPD filename */
1079 char tempfile[1024]; /* Temporary filename */
1080 cups_file_t *in, /* Input file */
1081 *out; /* Output file */
1082 char line[1024]; /* Line from PPD file */
1083 char keyword[1024], /* Keyword from Default line */
1084 *keyptr; /* Pointer into keyword... */
1085 ppd_file_t *ppd; /* PPD file */
1086 ppd_group_t *group; /* Option group */
1087 ppd_option_t *option; /* Option */
1088 ppd_attr_t *protocol; /* cupsProtocol attribute */
1089 const char *title; /* Page title */
1090
1091
1092 title = cgiText(_("Set Printer Options"));
1093
1094 fprintf(stderr, "DEBUG: do_config_printer(http=%p)\n", http);
1095
1096 /*
1097 * Get the printer name...
1098 */
1099
1100 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1101 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1102 "localhost", 0, "/printers/%s", printer);
1103 else
1104 {
1105 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1106 cgiStartHTML(title);
1107 cgiCopyTemplateLang("error.tmpl");
1108 cgiEndHTML();
1109 return;
1110 }
1111
1112 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
1113
1114 /*
1115 * Get the PPD file...
1116 */
1117
1118 if ((filename = cupsGetPPD2(http, printer)) == NULL)
1119 {
1120 fputs("DEBUG: No PPD file!?!\n", stderr);
1121
1122 cgiStartHTML(title);
1123 cgiShowIPPError(_("Unable to get PPD file!"));
1124 cgiEndHTML();
1125 return;
1126 }
1127
1128 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
1129
1130 if ((ppd = ppdOpenFile(filename)) == NULL)
1131 {
1132 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
1133 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1134 cgiStartHTML(title);
1135 cgiCopyTemplateLang("error.tmpl");
1136 cgiEndHTML();
1137 return;
1138 }
1139
1140 if (cgiGetVariable("job_sheets_start") != NULL ||
1141 cgiGetVariable("job_sheets_end") != NULL)
1142 have_options = 1;
1143 else
1144 have_options = 0;
1145
1146 ppdMarkDefaults(ppd);
1147
1148 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1149 "<UL>\n", ppd->num_groups));
1150
1151 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
1152 {
1153 DEBUG_printf(("<LI>%s<UL>\n", group->text));
1154
1155 for (j = group->num_options, option = group->options;
1156 j > 0;
1157 j --, option ++)
1158 if ((var = cgiGetVariable(option->keyword)) != NULL)
1159 {
1160 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
1161 have_options = 1;
1162 ppdMarkOption(ppd, option->keyword, var);
1163 }
1164 #ifdef DEBUG
1165 else
1166 printf("<LI>%s not defined!</LI>\n", option->keyword);
1167 #endif /* DEBUG */
1168
1169 DEBUG_puts("</UL></LI>");
1170 }
1171
1172 DEBUG_printf(("</UL>\n"
1173 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
1174
1175 if (!have_options || ppdConflicts(ppd))
1176 {
1177 /*
1178 * Show the options to the user...
1179 */
1180
1181 fputs("DEBUG: Showing options...\n", stderr);
1182
1183 ppdLocalize(ppd);
1184
1185 cgiStartHTML("Set Printer Options");
1186 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1187
1188 if (ppdConflicts(ppd))
1189 {
1190 for (i = ppd->num_groups, k = 0, group = ppd->groups;
1191 i > 0;
1192 i --, group ++)
1193 for (j = group->num_options, option = group->options;
1194 j > 0;
1195 j --, option ++)
1196 if (option->conflicted)
1197 {
1198 cgiSetArray("ckeyword", k, option->keyword);
1199 cgiSetArray("ckeytext", k, option->text);
1200 k ++;
1201 }
1202
1203 cgiCopyTemplateLang("option-conflict.tmpl");
1204 }
1205
1206 for (i = ppd->num_groups, group = ppd->groups;
1207 i > 0;
1208 i --, group ++)
1209 {
1210 if (!strcmp(group->name, "InstallableOptions"))
1211 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1212 else
1213 cgiSetVariable("GROUP", group->text);
1214
1215 cgiCopyTemplateLang("option-header.tmpl");
1216
1217 for (j = group->num_options, option = group->options;
1218 j > 0;
1219 j --, option ++)
1220 {
1221 if (!strcmp(option->keyword, "PageRegion"))
1222 continue;
1223
1224 cgiSetVariable("KEYWORD", option->keyword);
1225 cgiSetVariable("KEYTEXT", option->text);
1226
1227 if (option->conflicted)
1228 cgiSetVariable("CONFLICTED", "1");
1229 else
1230 cgiSetVariable("CONFLICTED", "0");
1231
1232 cgiSetSize("CHOICES", 0);
1233 cgiSetSize("TEXT", 0);
1234 for (k = 0, m = 0; k < option->num_choices; k ++)
1235 {
1236 /*
1237 * Hide custom option values...
1238 */
1239
1240 if (!strcmp(option->choices[k].choice, "Custom"))
1241 continue;
1242
1243 cgiSetArray("CHOICES", m, option->choices[k].choice);
1244 cgiSetArray("TEXT", m, option->choices[k].text);
1245
1246 m ++;
1247
1248 if (option->choices[k].marked)
1249 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
1250 }
1251
1252 switch (option->ui)
1253 {
1254 case PPD_UI_BOOLEAN :
1255 cgiCopyTemplateLang("option-boolean.tmpl");
1256 break;
1257 case PPD_UI_PICKONE :
1258 cgiCopyTemplateLang("option-pickone.tmpl");
1259 break;
1260 case PPD_UI_PICKMANY :
1261 cgiCopyTemplateLang("option-pickmany.tmpl");
1262 break;
1263 }
1264 }
1265
1266 cgiCopyTemplateLang("option-trailer.tmpl");
1267 }
1268
1269 /*
1270 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1271 * following attributes:
1272 *
1273 * attributes-charset
1274 * attributes-natural-language
1275 * printer-uri
1276 */
1277
1278 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1279
1280 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1281 "localhost", 0, "/printers/%s", printer);
1282 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1283 NULL, uri);
1284
1285 /*
1286 * Do the request and get back a response...
1287 */
1288
1289 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1290 {
1291 if ((attr = ippFindAttribute(response, "job-sheets-supported",
1292 IPP_TAG_ZERO)) != NULL)
1293 {
1294 /*
1295 * Add the job sheets options...
1296 */
1297
1298 cgiSetVariable("GROUP", cgiText(_("Banners")));
1299 cgiCopyTemplateLang("option-header.tmpl");
1300
1301 cgiSetSize("CHOICES", attr->num_values);
1302 cgiSetSize("TEXT", attr->num_values);
1303 for (k = 0; k < attr->num_values; k ++)
1304 {
1305 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1306 cgiSetArray("TEXT", k, attr->values[k].string.text);
1307 }
1308
1309 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
1310
1311 cgiSetVariable("KEYWORD", "job_sheets_start");
1312 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1313 cgiSetVariable("DEFCHOICE", attr == NULL ?
1314 "" : attr->values[0].string.text);
1315
1316 cgiCopyTemplateLang("option-pickone.tmpl");
1317
1318 cgiSetVariable("KEYWORD", "job_sheets_end");
1319 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1320 cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
1321 "" : attr->values[1].string.text);
1322
1323 cgiCopyTemplateLang("option-pickone.tmpl");
1324
1325 cgiCopyTemplateLang("option-trailer.tmpl");
1326 }
1327
1328 if (ippFindAttribute(response, "printer-error-policy-supported",
1329 IPP_TAG_ZERO) ||
1330 ippFindAttribute(response, "printer-op-policy-supported",
1331 IPP_TAG_ZERO))
1332 {
1333 /*
1334 * Add the error and operation policy options...
1335 */
1336
1337 cgiSetVariable("GROUP", cgiText(_("Policies")));
1338 cgiCopyTemplateLang("option-header.tmpl");
1339
1340 /*
1341 * Error policy...
1342 */
1343
1344 attr = ippFindAttribute(response, "printer-error-policy-supported",
1345 IPP_TAG_ZERO);
1346
1347 if (attr)
1348 {
1349 cgiSetSize("CHOICES", attr->num_values);
1350 cgiSetSize("TEXT", attr->num_values);
1351 for (k = 0; k < attr->num_values; k ++)
1352 {
1353 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1354 cgiSetArray("TEXT", k, attr->values[k].string.text);
1355 }
1356
1357 attr = ippFindAttribute(response, "printer-error-policy",
1358 IPP_TAG_ZERO);
1359
1360 cgiSetVariable("KEYWORD", "printer_error_policy");
1361 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1362 cgiSetVariable("DEFCHOICE", attr == NULL ?
1363 "" : attr->values[0].string.text);
1364 }
1365
1366 cgiCopyTemplateLang("option-pickone.tmpl");
1367
1368 /*
1369 * Operation policy...
1370 */
1371
1372 attr = ippFindAttribute(response, "printer-op-policy-supported",
1373 IPP_TAG_ZERO);
1374
1375 if (attr)
1376 {
1377 cgiSetSize("CHOICES", attr->num_values);
1378 cgiSetSize("TEXT", attr->num_values);
1379 for (k = 0; k < attr->num_values; k ++)
1380 {
1381 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1382 cgiSetArray("TEXT", k, attr->values[k].string.text);
1383 }
1384
1385 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
1386
1387 cgiSetVariable("KEYWORD", "printer_op_policy");
1388 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1389 cgiSetVariable("DEFCHOICE", attr == NULL ?
1390 "" : attr->values[0].string.text);
1391
1392 cgiCopyTemplateLang("option-pickone.tmpl");
1393 }
1394
1395 cgiCopyTemplateLang("option-trailer.tmpl");
1396 }
1397
1398 ippDelete(response);
1399 }
1400
1401 /*
1402 * Binary protocol support...
1403 */
1404
1405 if (ppd->protocols && strstr(ppd->protocols, "BCP"))
1406 {
1407 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
1408
1409 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1410 cgiCopyTemplateLang("option-header.tmpl");
1411
1412 cgiSetSize("CHOICES", 2);
1413 cgiSetSize("TEXT", 2);
1414 cgiSetArray("CHOICES", 0, "None");
1415 cgiSetArray("TEXT", 0, cgiText(_("None")));
1416
1417 if (strstr(ppd->protocols, "TBCP"))
1418 {
1419 cgiSetArray("CHOICES", 1, "TBCP");
1420 cgiSetArray("TEXT", 1, "TBCP");
1421 }
1422 else
1423 {
1424 cgiSetArray("CHOICES", 1, "BCP");
1425 cgiSetArray("TEXT", 1, "BCP");
1426 }
1427
1428 cgiSetVariable("KEYWORD", "protocol");
1429 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1430 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
1431
1432 cgiCopyTemplateLang("option-pickone.tmpl");
1433
1434 cgiCopyTemplateLang("option-trailer.tmpl");
1435 }
1436
1437 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1438 cgiEndHTML();
1439 }
1440 else
1441 {
1442 /*
1443 * Set default options...
1444 */
1445
1446 fputs("DEBUG: Setting options...\n", stderr);
1447
1448 out = cupsTempFile2(tempfile, sizeof(tempfile));
1449 in = cupsFileOpen(filename, "r");
1450
1451 if (!in || !out)
1452 {
1453 cgiSetVariable("ERROR", strerror(errno));
1454 cgiStartHTML("Set Printer Options");
1455 cgiCopyTemplateLang("error.tmpl");
1456 cgiEndHTML();
1457
1458 if (in)
1459 cupsFileClose(in);
1460
1461 if (out)
1462 {
1463 cupsFileClose(out);
1464 unlink(tempfile);
1465 }
1466
1467 unlink(filename);
1468 return;
1469 }
1470
1471 while (cupsFileGets(in, line, sizeof(line)))
1472 {
1473 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1474 continue;
1475 else if (strncmp(line, "*Default", 8))
1476 cupsFilePrintf(out, "%s\n", line);
1477 else
1478 {
1479 /*
1480 * Get default option name...
1481 */
1482
1483 strlcpy(keyword, line + 8, sizeof(keyword));
1484
1485 for (keyptr = keyword; *keyptr; keyptr ++)
1486 if (*keyptr == ':' || isspace(*keyptr & 255))
1487 break;
1488
1489 *keyptr = '\0';
1490
1491 if (!strcmp(keyword, "PageRegion"))
1492 var = cgiGetVariable("PageSize");
1493 else
1494 var = cgiGetVariable(keyword);
1495
1496 if (var != NULL)
1497 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
1498 else
1499 cupsFilePrintf(out, "%s\n", line);
1500 }
1501 }
1502
1503 if ((var = cgiGetVariable("protocol")) != NULL)
1504 cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1505
1506 cupsFileClose(in);
1507 cupsFileClose(out);
1508
1509 /*
1510 * Build a CUPS_ADD_PRINTER request, which requires the following
1511 * attributes:
1512 *
1513 * attributes-charset
1514 * attributes-natural-language
1515 * printer-uri
1516 * job-sheets-default
1517 * [ppd file]
1518 */
1519
1520 request = ippNewRequest(CUPS_ADD_PRINTER);
1521
1522 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1523 "localhost", 0, "/printers/%s",
1524 cgiGetVariable("PRINTER_NAME"));
1525 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1526 NULL, uri);
1527
1528 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1529 "job-sheets-default", 2, NULL, NULL);
1530 attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start"));
1531 attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end"));
1532
1533 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1534 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1535 "printer-error-policy", NULL, var);
1536
1537 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1538 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1539 "printer-op-policy", NULL, var);
1540
1541 /*
1542 * Do the request and get back a response...
1543 */
1544
1545 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
1546
1547 if (cupsLastError() > IPP_OK_CONFLICT)
1548 {
1549 cgiStartHTML(title);
1550 cgiShowIPPError(_("Unable to set options:"));
1551 }
1552 else
1553 {
1554 /*
1555 * Redirect successful updates back to the printer page...
1556 */
1557
1558 char refresh[1024]; /* Refresh URL */
1559
1560
1561 cgiFormEncode(uri, printer, sizeof(uri));
1562 snprintf(refresh, sizeof(refresh),
1563 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
1564 cgiSetVariable("refresh_page", refresh);
1565
1566 cgiStartHTML(title);
1567
1568 cgiCopyTemplateLang("printer-configured.tmpl");
1569 }
1570
1571 cgiEndHTML();
1572
1573 unlink(tempfile);
1574 }
1575
1576 unlink(filename);
1577 }
1578
1579
1580 /*
1581 * 'do_config_server()' - Configure server settings.
1582 */
1583
1584 static void
1585 do_config_server(http_t *http) /* I - HTTP connection */
1586 {
1587 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1588 {
1589 /*
1590 * Save basic setting changes...
1591 */
1592
1593 int num_settings; /* Number of server settings */
1594 cups_option_t *settings; /* Server settings */
1595
1596
1597 num_settings = 0;
1598 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1599 cgiGetVariable("DEBUG_LOGGING") ? "1" : "0",
1600 num_settings, &settings);
1601 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1602 cgiGetVariable("REMOTE_ADMIN") ? "1" : "0",
1603 num_settings, &settings);
1604 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1605 cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0",
1606 num_settings, &settings);
1607 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1608 cgiGetVariable("SHARE_PRINTERS") ? "1" : "0",
1609 num_settings, &settings);
1610 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1611 cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0",
1612 num_settings, &settings);
1613
1614
1615 if (!_cupsAdminSetServerSettings(http, num_settings, settings))
1616 {
1617 cgiStartHTML(cgiText(_("Change Settings")));
1618 cgiSetVariable("MESSAGE",
1619 cgiText(_("Unable to change server settings:")));
1620 cgiSetVariable("ERROR", cupsLastErrorString());
1621 cgiCopyTemplateLang("error.tmpl");
1622 }
1623 else
1624 {
1625 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1626 cgiStartHTML(cgiText(_("Change Settings")));
1627 cgiCopyTemplateLang("restart.tmpl");
1628 }
1629
1630 cupsFreeOptions(num_settings, settings);
1631
1632 cgiEndHTML();
1633 }
1634 else if (cgiIsPOST())
1635 {
1636 /*
1637 * Save hand-edited config file...
1638 */
1639
1640 http_status_t status; /* PUT status */
1641 char tempfile[1024]; /* Temporary new cupsd.conf */
1642 int tempfd; /* Temporary file descriptor */
1643 cups_file_t *temp; /* Temporary file */
1644 const char *start, /* Start of line */
1645 *end; /* End of line */
1646
1647
1648 /*
1649 * Create a temporary file for the new cupsd.conf file...
1650 */
1651
1652 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1653 {
1654 cgiStartHTML(cgiText(_("Edit Configuration File")));
1655 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1656 cgiSetVariable("ERROR", strerror(errno));
1657 cgiCopyTemplateLang("error.tmpl");
1658 cgiEndHTML();
1659
1660 perror(tempfile);
1661 return;
1662 }
1663
1664 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1665 {
1666 cgiStartHTML(cgiText(_("Edit Configuration File")));
1667 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1668 cgiSetVariable("ERROR", strerror(errno));
1669 cgiCopyTemplateLang("error.tmpl");
1670 cgiEndHTML();
1671
1672 perror(tempfile);
1673 close(tempfd);
1674 unlink(tempfile);
1675 return;
1676 }
1677
1678 /*
1679 * Copy the cupsd.conf text from the form variable...
1680 */
1681
1682 start = cgiGetVariable("CUPSDCONF");
1683 while (start)
1684 {
1685 if ((end = strstr(start, "\r\n")) == NULL)
1686 if ((end = strstr(start, "\n")) == NULL)
1687 end = start + strlen(start);
1688
1689 cupsFileWrite(temp, start, end - start);
1690 cupsFilePutChar(temp, '\n');
1691
1692 if (*end == '\r')
1693 start = end + 2;
1694 else if (*end == '\n')
1695 start = end + 1;
1696 else
1697 start = NULL;
1698 }
1699
1700 cupsFileClose(temp);
1701
1702 /*
1703 * Upload the configuration file to the server...
1704 */
1705
1706 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1707
1708 if (status != HTTP_CREATED)
1709 {
1710 cgiSetVariable("MESSAGE",
1711 cgiText(_("Unable to upload cupsd.conf file:")));
1712 cgiSetVariable("ERROR", httpStatus(status));
1713
1714 cgiStartHTML(cgiText(_("Edit Configuration File")));
1715 cgiCopyTemplateLang("error.tmpl");
1716 }
1717 else
1718 {
1719 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1720
1721 cgiStartHTML(cgiText(_("Edit Configuration File")));
1722 cgiCopyTemplateLang("restart.tmpl");
1723 }
1724
1725 cgiEndHTML();
1726
1727 unlink(tempfile);
1728 }
1729 else
1730 {
1731 struct stat info; /* cupsd.conf information */
1732 cups_file_t *cupsd; /* cupsd.conf file */
1733 char *buffer; /* Buffer for entire file */
1734 char filename[1024]; /* Filename */
1735 const char *server_root; /* Location of config files */
1736
1737
1738 /*
1739 * Locate the cupsd.conf file...
1740 */
1741
1742 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1743 server_root = CUPS_SERVERROOT;
1744
1745 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
1746
1747 /*
1748 * Figure out the size...
1749 */
1750
1751 if (stat(filename, &info))
1752 {
1753 cgiStartHTML(cgiText(_("Edit Configuration File")));
1754 cgiSetVariable("MESSAGE",
1755 cgiText(_("Unable to access cupsd.conf file:")));
1756 cgiSetVariable("ERROR", strerror(errno));
1757 cgiCopyTemplateLang("error.tmpl");
1758 cgiEndHTML();
1759
1760 perror(filename);
1761 return;
1762 }
1763
1764 if (info.st_size > (1024 * 1024))
1765 {
1766 cgiStartHTML(cgiText(_("Edit Configuration File")));
1767 cgiSetVariable("MESSAGE",
1768 cgiText(_("Unable to access cupsd.conf file:")));
1769 cgiSetVariable("ERROR",
1770 cgiText(_("Unable to edit cupsd.conf files larger than "
1771 "1MB!")));
1772 cgiCopyTemplateLang("error.tmpl");
1773 cgiEndHTML();
1774
1775 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1776 (long)info.st_size);
1777 return;
1778 }
1779
1780 /*
1781 * Open the cupsd.conf file...
1782 */
1783
1784 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1785 {
1786 /*
1787 * Unable to open - log an error...
1788 */
1789
1790 cgiStartHTML(cgiText(_("Edit Configuration File")));
1791 cgiSetVariable("MESSAGE",
1792 cgiText(_("Unable to access cupsd.conf file:")));
1793 cgiSetVariable("ERROR", strerror(errno));
1794 cgiCopyTemplateLang("error.tmpl");
1795 cgiEndHTML();
1796
1797 perror(filename);
1798 return;
1799 }
1800
1801 /*
1802 * Allocate memory and load the file into a string buffer...
1803 */
1804
1805 buffer = calloc(1, info.st_size + 1);
1806
1807 cupsFileRead(cupsd, buffer, info.st_size);
1808 cupsFileClose(cupsd);
1809
1810 cgiSetVariable("CUPSDCONF", buffer);
1811 free(buffer);
1812
1813 /*
1814 * Show the current config file...
1815 */
1816
1817 cgiStartHTML("Edit Configuration File");
1818
1819 printf("<!-- \"%s\" -->\n", filename);
1820
1821 cgiCopyTemplateLang("edit-config.tmpl");
1822
1823 cgiEndHTML();
1824 }
1825 }
1826
1827
1828 /*
1829 * 'do_delete_class()' - Delete a class...
1830 */
1831
1832 static void
1833 do_delete_class(http_t *http) /* I - HTTP connection */
1834 {
1835 ipp_t *request; /* IPP request */
1836 char uri[HTTP_MAX_URI]; /* Job URI */
1837 const char *pclass; /* Printer class name */
1838
1839
1840 cgiStartHTML(cgiText(_("Delete Class")));
1841
1842 if (cgiGetVariable("CONFIRM") == NULL)
1843 {
1844 cgiCopyTemplateLang("class-confirm.tmpl");
1845 cgiEndHTML();
1846 return;
1847 }
1848
1849 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
1850 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1851 "localhost", 0, "/classes/%s", pclass);
1852 else
1853 {
1854 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1855 cgiCopyTemplateLang("error.tmpl");
1856 cgiEndHTML();
1857 return;
1858 }
1859
1860 /*
1861 * Build a CUPS_DELETE_CLASS request, which requires the following
1862 * attributes:
1863 *
1864 * attributes-charset
1865 * attributes-natural-language
1866 * printer-uri
1867 */
1868
1869 request = ippNewRequest(CUPS_DELETE_CLASS);
1870
1871 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1872 NULL, uri);
1873
1874 /*
1875 * Do the request and get back a response...
1876 */
1877
1878 ippDelete(cupsDoRequest(http, request, "/admin/"));
1879
1880 if (cupsLastError() > IPP_OK_CONFLICT)
1881 cgiShowIPPError(_("Unable to delete class:"));
1882 else
1883 cgiCopyTemplateLang("class-deleted.tmpl");
1884
1885 cgiEndHTML();
1886 }
1887
1888
1889 /*
1890 * 'do_delete_printer()' - Delete a printer...
1891 */
1892
1893 static void
1894 do_delete_printer(http_t *http) /* I - HTTP connection */
1895 {
1896 ipp_t *request; /* IPP request */
1897 char uri[HTTP_MAX_URI]; /* Job URI */
1898 const char *printer; /* Printer printer name */
1899
1900
1901 cgiStartHTML(cgiText(_("Delete Printer")));
1902
1903 if (cgiGetVariable("CONFIRM") == NULL)
1904 {
1905 cgiCopyTemplateLang("printer-confirm.tmpl");
1906 cgiEndHTML();
1907 return;
1908 }
1909
1910 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1911 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1912 "localhost", 0, "/printers/%s", printer);
1913 else
1914 {
1915 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1916 cgiCopyTemplateLang("error.tmpl");
1917 cgiEndHTML();
1918 return;
1919 }
1920
1921 /*
1922 * Build a CUPS_DELETE_PRINTER request, which requires the following
1923 * attributes:
1924 *
1925 * attributes-charset
1926 * attributes-natural-language
1927 * printer-uri
1928 */
1929
1930 request = ippNewRequest(CUPS_DELETE_PRINTER);
1931
1932 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1933 NULL, uri);
1934
1935 /*
1936 * Do the request and get back a response...
1937 */
1938
1939 ippDelete(cupsDoRequest(http, request, "/admin/"));
1940
1941 if (cupsLastError() > IPP_OK_CONFLICT)
1942 cgiShowIPPError(_("Unable to delete printer:"));
1943 else
1944 cgiCopyTemplateLang("printer-deleted.tmpl");
1945
1946 cgiEndHTML();
1947 }
1948
1949
1950 /*
1951 * 'do_export()' - Export printers to Samba...
1952 */
1953
1954 static void
1955 do_export(http_t *http) /* I - HTTP connection */
1956 {
1957 int i, j; /* Looping vars */
1958 ipp_t *request, /* IPP request */
1959 *response; /* IPP response */
1960 const char *username, /* Samba username */
1961 *password, /* Samba password */
1962 *export_all; /* Export all printers? */
1963 int export_count, /* Number of printers to export */
1964 printer_count; /* Number of available printers */
1965 const char *name, /* What name to pull */
1966 *dest; /* Current destination */
1967 char ppd[1024]; /* PPD file */
1968
1969
1970 /*
1971 * Get form data...
1972 */
1973
1974 username = cgiGetVariable("USERNAME");
1975 password = cgiGetVariable("PASSWORD");
1976 export_all = cgiGetVariable("EXPORT_ALL");
1977 export_count = cgiGetSize("EXPORT_NAME");
1978
1979 /*
1980 * Get list of available printers...
1981 */
1982
1983 cgiSetSize("PRINTER_NAME", 0);
1984 cgiSetSize("PRINTER_EXPORT", 0);
1985
1986 request = ippNewRequest(CUPS_GET_PRINTERS);
1987
1988 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1989 "printer-type", 0);
1990
1991 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1992 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
1993 CUPS_PRINTER_IMPLICIT);
1994
1995 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1996 "requested-attributes", NULL, "printer-name");
1997
1998 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1999 {
2000 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2001 ippDelete(response);
2002
2003 if (!export_all)
2004 {
2005 printer_count = cgiGetSize("PRINTER_NAME");
2006
2007 for (i = 0; i < printer_count; i ++)
2008 {
2009 dest = cgiGetArray("PRINTER_NAME", i);
2010
2011 for (j = 0; j < export_count; j ++)
2012 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2013 break;
2014
2015 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2016 }
2017 }
2018 }
2019
2020 /*
2021 * Export or get the printers to export...
2022 */
2023
2024 if (username && *username && password && *password &&
2025 (export_all || export_count > 0))
2026 {
2027 /*
2028 * Do export...
2029 */
2030
2031 fputs("DEBUG: Export printers...\n", stderr);
2032
2033 if (export_all)
2034 {
2035 name = "PRINTER_NAME";
2036 export_count = cgiGetSize("PRINTER_NAME");
2037 }
2038 else
2039 name = "EXPORT_NAME";
2040
2041 for (i = 0; i < export_count; i ++)
2042 {
2043 dest = cgiGetArray(name, i);
2044
2045 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2046 break;
2047
2048 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2049 stderr);
2050
2051 unlink(ppd);
2052
2053 if (!j)
2054 break;
2055 }
2056
2057 if (i < export_count)
2058 cgiSetVariable("ERROR", cupsLastErrorString());
2059 else
2060 {
2061 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2062 cgiCopyTemplateLang("samba-exported.tmpl");
2063 cgiEndHTML();
2064 return;
2065 }
2066 }
2067 else if (username && !*username)
2068 cgiSetVariable("ERROR",
2069 cgiText(_("A Samba username is required to export "
2070 "printer drivers!")));
2071 else if (username && (!password || !*password))
2072 cgiSetVariable("ERROR",
2073 cgiText(_("A Samba password is required to export "
2074 "printer drivers!")));
2075
2076 /*
2077 * Show form...
2078 */
2079
2080 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2081 cgiCopyTemplateLang("samba-export.tmpl");
2082 cgiEndHTML();
2083 }
2084
2085
2086 /*
2087 * 'do_menu()' - Show the main menu...
2088 */
2089
2090 static void
2091 do_menu(http_t *http) /* I - HTTP connection */
2092 {
2093 int num_settings; /* Number of server settings */
2094 cups_option_t *settings; /* Server settings */
2095 const char *val; /* Setting value */
2096 char filename[1024]; /* Temporary filename */
2097 const char *datadir; /* Location of data files */
2098 ipp_t *request, /* IPP request */
2099 *response; /* IPP response */
2100 ipp_attribute_t *attr; /* IPP attribute */
2101
2102
2103 /*
2104 * Get the current server settings...
2105 */
2106
2107 if (!_cupsAdminGetServerSettings(http, &num_settings, &settings))
2108 {
2109 cgiSetVariable("SETTINGS_MESSAGE",
2110 cgiText(_("Unable to open cupsd.conf file:")));
2111 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2112 }
2113
2114 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2115 settings)) != NULL && atoi(val))
2116 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2117
2118 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2119 settings)) != NULL && atoi(val))
2120 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2121
2122 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2123 settings)) != NULL && atoi(val))
2124 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2125
2126 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2127 settings)) != NULL && atoi(val))
2128 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2129
2130 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2131 settings)) != NULL && atoi(val))
2132 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2133
2134 cupsFreeOptions(num_settings, settings);
2135
2136 /*
2137 * Get the list of printers and their devices...
2138 */
2139
2140 request = ippNewRequest(CUPS_GET_PRINTERS);
2141
2142 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2143 "requested-attributes", NULL, "device-uri");
2144
2145 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2146 CUPS_PRINTER_LOCAL);
2147 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2148 CUPS_PRINTER_LOCAL);
2149
2150 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2151 {
2152 /*
2153 * Got the printer list, now load the devices...
2154 */
2155
2156 int i; /* Looping var */
2157 cups_array_t *printer_devices; /* Printer devices for local printers */
2158 char *printer_device; /* Current printer device */
2159
2160
2161 /*
2162 * Allocate an array and copy the device strings...
2163 */
2164
2165 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2166
2167 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2168 attr;
2169 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2170 {
2171 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
2172 }
2173
2174 /*
2175 * Free the printer list and get the device list...
2176 */
2177
2178 ippDelete(response);
2179
2180 request = ippNewRequest(CUPS_GET_DEVICES);
2181
2182 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2183 {
2184 /*
2185 * Got the device list, let's parse it...
2186 */
2187
2188 const char *device_uri, /* device-uri attribute value */
2189 *device_make_and_model, /* device-make-and-model value */
2190 *device_info; /* device-info value */
2191
2192
2193 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2194 {
2195 /*
2196 * Skip leading attributes until we hit a device...
2197 */
2198
2199 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2200 attr = attr->next;
2201
2202 if (!attr)
2203 break;
2204
2205 /*
2206 * Pull the needed attributes from this device...
2207 */
2208
2209 device_info = NULL;
2210 device_make_and_model = NULL;
2211 device_uri = NULL;
2212
2213 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2214 {
2215 if (!strcmp(attr->name, "device-info") &&
2216 attr->value_tag == IPP_TAG_TEXT)
2217 device_info = attr->values[0].string.text;
2218
2219 if (!strcmp(attr->name, "device-make-and-model") &&
2220 attr->value_tag == IPP_TAG_TEXT)
2221 device_make_and_model = attr->values[0].string.text;
2222
2223 if (!strcmp(attr->name, "device-uri") &&
2224 attr->value_tag == IPP_TAG_URI)
2225 device_uri = attr->values[0].string.text;
2226
2227 attr = attr->next;
2228 }
2229
2230 /*
2231 * See if we have everything needed...
2232 */
2233
2234 if (device_info && device_make_and_model && device_uri &&
2235 strcasecmp(device_make_and_model, "unknown") &&
2236 strchr(device_uri, ':'))
2237 {
2238 /*
2239 * Yes, now see if there is already a printer for this
2240 * device...
2241 */
2242
2243 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2244 {
2245 /*
2246 * Not found, so it must be a new printer...
2247 */
2248
2249 char options[1024], /* Form variables for this device */
2250 *options_ptr; /* Pointer into string */
2251 const char *ptr; /* Pointer into device string */
2252
2253
2254 /*
2255 * Format the printer name variable for this device...
2256 *
2257 * We use the device-info string first, then device-uri,
2258 * and finally device-make-and-model to come up with a
2259 * suitable name.
2260 */
2261
2262 strcpy(options, "PRINTER_NAME=");
2263 options_ptr = options + strlen(options);
2264
2265 if (strncasecmp(device_info, "unknown", 7))
2266 ptr = device_info;
2267 else if ((ptr = strstr(device_uri, "://")) != NULL)
2268 ptr += 3;
2269 else
2270 ptr = device_make_and_model;
2271
2272 for (;
2273 options_ptr < (options + sizeof(options) - 1) && *ptr;
2274 ptr ++)
2275 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2276 *ptr == '.')
2277 *options_ptr++ = *ptr;
2278 else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_')
2279 *options_ptr++ = '_';
2280 else if (*ptr == '?' || *ptr == '(')
2281 break;
2282
2283 /*
2284 * Then add the make and model in the printer info, so
2285 * that MacOS clients see something reasonable...
2286 */
2287
2288 strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer"
2289 "&PRINTER_INFO=",
2290 sizeof(options) - (options_ptr - options));
2291 options_ptr += strlen(options_ptr);
2292
2293 cgiFormEncode(options_ptr, device_make_and_model,
2294 sizeof(options) - (options_ptr - options));
2295 options_ptr += strlen(options_ptr);
2296
2297 /*
2298 * Then copy the device URI...
2299 */
2300
2301 strlcpy(options_ptr, "&DEVICE_URI=",
2302 sizeof(options) - (options_ptr - options));
2303 options_ptr += strlen(options_ptr);
2304
2305 cgiFormEncode(options_ptr, device_uri,
2306 sizeof(options) - (options_ptr - options));
2307 options_ptr += strlen(options_ptr);
2308
2309 if (options_ptr < (options + sizeof(options) - 1))
2310 {
2311 *options_ptr++ = '|';
2312 cgiFormEncode(options_ptr, device_make_and_model,
2313 sizeof(options) - (options_ptr - options));
2314 }
2315
2316 /*
2317 * Finally, set the form variables for this printer...
2318 */
2319
2320 cgiSetArray("device_info", i, device_info);
2321 cgiSetArray("device_make_and_model", i, device_make_and_model);
2322 cgiSetArray("device_options", i, options);
2323 cgiSetArray("device_uri", i, device_uri);
2324 i ++;
2325 }
2326 }
2327
2328 if (!attr)
2329 break;
2330 }
2331
2332 ippDelete(response);
2333
2334 /*
2335 * Free the device list...
2336 */
2337
2338 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2339 printer_device;
2340 printer_device = (char *)cupsArrayNext(printer_devices))
2341 free(printer_device);
2342
2343 cupsArrayDelete(printer_devices);
2344 }
2345 }
2346
2347 /*
2348 * See if Samba and the Windows drivers are installed...
2349 */
2350
2351 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2352 datadir = CUPS_DATADIR;
2353
2354 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2355 if (!access(filename, R_OK))
2356 {
2357 /*
2358 * Found Windows 2000 driver file, see if we have smbclient and
2359 * rpcclient...
2360 */
2361
2362 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2363 sizeof(filename)) &&
2364 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2365 sizeof(filename)))
2366 cgiSetVariable("HAVE_SAMBA", "Y");
2367 else
2368 {
2369 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2370 sizeof(filename)))
2371 fputs("ERROR: smbclient not found!\n", stderr);
2372
2373 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2374 sizeof(filename)))
2375 fputs("ERROR: rpcclient not found!\n", stderr);
2376 }
2377 }
2378 else
2379 perror(filename);
2380
2381 /*
2382 * Finally, show the main menu template...
2383 */
2384
2385 cgiStartHTML(cgiText(_("Administration")));
2386
2387 cgiCopyTemplateLang("admin.tmpl");
2388
2389 cgiEndHTML();
2390 }
2391
2392
2393 /*
2394 * 'do_printer_op()' - Do a printer operation.
2395 */
2396
2397 static void
2398 do_printer_op(http_t *http, /* I - HTTP connection */
2399 ipp_op_t op, /* I - Operation to perform */
2400 const char *title) /* I - Title of page */
2401 {
2402 ipp_t *request; /* IPP request */
2403 char uri[HTTP_MAX_URI]; /* Printer URI */
2404 const char *printer, /* Printer name (purge-jobs) */
2405 *is_class; /* Is a class? */
2406
2407
2408 is_class = cgiGetVariable("IS_CLASS");
2409 printer = cgiGetVariable("PRINTER_NAME");
2410
2411 if (!printer)
2412 {
2413 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2414 cgiStartHTML(title);
2415 cgiCopyTemplateLang("error.tmpl");
2416 cgiEndHTML();
2417 return;
2418 }
2419
2420 /*
2421 * Build a printer request, which requires the following
2422 * attributes:
2423 *
2424 * attributes-charset
2425 * attributes-natural-language
2426 * printer-uri
2427 */
2428
2429 request = ippNewRequest(op);
2430
2431 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2432 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2433 printer);
2434 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2435 NULL, uri);
2436
2437 /*
2438 * Do the request and get back a response...
2439 */
2440
2441 ippDelete(cupsDoRequest(http, request, "/admin/"));
2442
2443 if (cupsLastError() > IPP_OK_CONFLICT)
2444 {
2445 cgiStartHTML(title);
2446 cgiShowIPPError(_("Unable to change printer:"));
2447 }
2448 else
2449 {
2450 /*
2451 * Redirect successful updates back to the printer page...
2452 */
2453
2454 char url[1024], /* Printer/class URL */
2455 refresh[1024]; /* Refresh URL */
2456
2457
2458 cgiRewriteURL(uri, url, sizeof(url), NULL);
2459 cgiFormEncode(uri, url, sizeof(uri));
2460 snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri);
2461 cgiSetVariable("refresh_page", refresh);
2462
2463 cgiStartHTML(title);
2464
2465 if (op == IPP_PAUSE_PRINTER)
2466 cgiCopyTemplateLang("printer-stop.tmpl");
2467 else if (op == IPP_RESUME_PRINTER)
2468 cgiCopyTemplateLang("printer-start.tmpl");
2469 else if (op == CUPS_ACCEPT_JOBS)
2470 cgiCopyTemplateLang("printer-accept.tmpl");
2471 else if (op == CUPS_REJECT_JOBS)
2472 cgiCopyTemplateLang("printer-reject.tmpl");
2473 else if (op == IPP_PURGE_JOBS)
2474 cgiCopyTemplateLang("printer-purge.tmpl");
2475 else if (op == CUPS_SET_DEFAULT)
2476 cgiCopyTemplateLang("printer-default.tmpl");
2477 }
2478
2479 cgiEndHTML();
2480 }
2481
2482
2483 /*
2484 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2485 */
2486
2487 static void
2488 do_set_allowed_users(http_t *http) /* I - HTTP connection */
2489 {
2490 int i; /* Looping var */
2491 ipp_t *request, /* IPP request */
2492 *response; /* IPP response */
2493 char uri[HTTP_MAX_URI]; /* Printer URI */
2494 const char *printer, /* Printer name (purge-jobs) */
2495 *is_class, /* Is a class? */
2496 *users, /* List of users or groups */
2497 *type; /* Allow/deny type */
2498 int num_users; /* Number of users */
2499 char *ptr, /* Pointer into users string */
2500 *end, /* Pointer to end of users string */
2501 quote; /* Quote character */
2502 ipp_attribute_t *attr; /* Attribute */
2503 static const char * const attrs[] = /* Requested attributes */
2504 {
2505 "requesting-user-name-allowed",
2506 "requesting-user-name-denied"
2507 };
2508
2509
2510 is_class = cgiGetVariable("IS_CLASS");
2511 printer = cgiGetVariable("PRINTER_NAME");
2512
2513 if (!printer)
2514 {
2515 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2516 cgiStartHTML(cgiText(_("Set Allowed Users")));
2517 cgiCopyTemplateLang("error.tmpl");
2518 cgiEndHTML();
2519 return;
2520 }
2521
2522 users = cgiGetVariable("users");
2523 type = cgiGetVariable("type");
2524
2525 if (!users || !type ||
2526 (strcmp(type, "requesting-user-name-allowed") &&
2527 strcmp(type, "requesting-user-name-denied")))
2528 {
2529 /*
2530 * Build a Get-Printer-Attributes request, which requires the following
2531 * attributes:
2532 *
2533 * attributes-charset
2534 * attributes-natural-language
2535 * printer-uri
2536 * requested-attributes
2537 */
2538
2539 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2540
2541 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2542 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2543 printer);
2544 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2545 NULL, uri);
2546
2547 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2548 "requested-attributes",
2549 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2550
2551 /*
2552 * Do the request and get back a response...
2553 */
2554
2555 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2556 {
2557 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2558
2559 ippDelete(response);
2560 }
2561
2562 cgiStartHTML(cgiText(_("Set Allowed Users")));
2563
2564 if (cupsLastError() > IPP_OK_CONFLICT)
2565 cgiShowIPPError(_("Unable to get printer attributes:"));
2566 else
2567 cgiCopyTemplateLang("users.tmpl");
2568
2569 cgiEndHTML();
2570 }
2571 else
2572 {
2573 /*
2574 * Save the changes...
2575 */
2576
2577 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2578 {
2579 /*
2580 * Skip whitespace and commas...
2581 */
2582
2583 while (*ptr == ',' || isspace(*ptr & 255))
2584 ptr ++;
2585
2586 if (*ptr == '\'' || *ptr == '\"')
2587 {
2588 /*
2589 * Scan quoted name...
2590 */
2591
2592 quote = *ptr++;
2593
2594 for (end = ptr; *end; end ++)
2595 if (*end == quote)
2596 break;
2597 }
2598 else
2599 {
2600 /*
2601 * Scan space or comma-delimited name...
2602 */
2603
2604 for (end = ptr; *end; end ++)
2605 if (isspace(*end & 255) || *end == ',')
2606 break;
2607 }
2608
2609 /*
2610 * Advance to the next name...
2611 */
2612
2613 ptr = end;
2614 }
2615
2616 /*
2617 * Build a CUPS-Add-Printer/Class request, which requires the following
2618 * attributes:
2619 *
2620 * attributes-charset
2621 * attributes-natural-language
2622 * printer-uri
2623 * requesting-user-name-{allowed,denied}
2624 */
2625
2626 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2627
2628 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2629 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2630 printer);
2631 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2632 NULL, uri);
2633
2634 if (num_users == 0)
2635 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2636 "requesting-user-name-allowed", NULL, "all");
2637 else
2638 {
2639 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2640 type, num_users, NULL, NULL);
2641
2642 for (i = 0, ptr = (char *)users; *ptr; i ++)
2643 {
2644 /*
2645 * Skip whitespace and commas...
2646 */
2647
2648 while (*ptr == ',' || isspace(*ptr & 255))
2649 ptr ++;
2650
2651 if (*ptr == '\'' || *ptr == '\"')
2652 {
2653 /*
2654 * Scan quoted name...
2655 */
2656
2657 quote = *ptr++;
2658
2659 for (end = ptr; *end; end ++)
2660 if (*end == quote)
2661 break;
2662 }
2663 else
2664 {
2665 /*
2666 * Scan space or comma-delimited name...
2667 */
2668
2669 for (end = ptr; *end; end ++)
2670 if (isspace(*end & 255) || *end == ',')
2671 break;
2672 }
2673
2674 /*
2675 * Terminate the name...
2676 */
2677
2678 if (*end)
2679 *end++ = '\0';
2680
2681 /*
2682 * Add the name...
2683 */
2684
2685 attr->values[i].string.text = strdup(ptr);
2686
2687 /*
2688 * Advance to the next name...
2689 */
2690
2691 ptr = end;
2692 }
2693 }
2694
2695 /*
2696 * Do the request and get back a response...
2697 */
2698
2699 ippDelete(cupsDoRequest(http, request, "/admin/"));
2700
2701 if (cupsLastError() > IPP_OK_CONFLICT)
2702 {
2703 cgiStartHTML(cgiText(_("Set Allowed Users")));
2704 cgiShowIPPError(_("Unable to change printer:"));
2705 }
2706 else
2707 {
2708 /*
2709 * Redirect successful updates back to the printer page...
2710 */
2711
2712 char url[1024], /* Printer/class URL */
2713 refresh[1024]; /* Refresh URL */
2714
2715
2716 cgiRewriteURL(uri, url, sizeof(url), NULL);
2717 cgiFormEncode(uri, url, sizeof(uri));
2718 snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri);
2719 cgiSetVariable("refresh_page", refresh);
2720
2721 cgiStartHTML(cgiText(_("Set Allowed Users")));
2722
2723 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2724 "printer-modified.tmpl");
2725 }
2726
2727 cgiEndHTML();
2728 }
2729 }
2730
2731
2732 /*
2733 * 'do_set_sharing()' - Set printer-is-shared value...
2734 */
2735
2736 static void
2737 do_set_sharing(http_t *http) /* I - HTTP connection */
2738 {
2739 ipp_t *request, /* IPP request */
2740 *response; /* IPP response */
2741 char uri[HTTP_MAX_URI]; /* Printer URI */
2742 const char *printer, /* Printer name */
2743 *is_class, /* Is a class? */
2744 *shared; /* Sharing value */
2745
2746
2747 is_class = cgiGetVariable("IS_CLASS");
2748 printer = cgiGetVariable("PRINTER_NAME");
2749 shared = cgiGetVariable("SHARED");
2750
2751 if (!printer || !shared)
2752 {
2753 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2754 cgiStartHTML(cgiText(_("Set Publishing")));
2755 cgiCopyTemplateLang("error.tmpl");
2756 cgiEndHTML();
2757 return;
2758 }
2759
2760 /*
2761 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
2762 * following attributes:
2763 *
2764 * attributes-charset
2765 * attributes-natural-language
2766 * printer-uri
2767 * printer-is-shared
2768 */
2769
2770 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2771
2772 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2773 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2774 printer);
2775 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2776 NULL, uri);
2777
2778 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
2779
2780 /*
2781 * Do the request and get back a response...
2782 */
2783
2784 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
2785 {
2786 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2787
2788 ippDelete(response);
2789 }
2790
2791 if (cupsLastError() > IPP_OK_CONFLICT)
2792 {
2793 cgiStartHTML(cgiText(_("Set Publishing")));
2794 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
2795 }
2796 else
2797 {
2798 /*
2799 * Redirect successful updates back to the printer page...
2800 */
2801
2802 char url[1024], /* Printer/class URL */
2803 refresh[1024]; /* Refresh URL */
2804
2805
2806 cgiRewriteURL(uri, url, sizeof(url), NULL);
2807 cgiFormEncode(uri, url, sizeof(uri));
2808 snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri);
2809 cgiSetVariable("refresh_page", refresh);
2810
2811 cgiStartHTML(cgiText(_("Set Publishing")));
2812 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2813 "printer-modified.tmpl");
2814 }
2815
2816 cgiEndHTML();
2817 }
2818
2819
2820 /*
2821 * 'match_string()' - Return the number of matching characters.
2822 */
2823
2824 static int /* O - Number of matching characters */
2825 match_string(const char *a, /* I - First string */
2826 const char *b) /* I - Second string */
2827 {
2828 int count; /* Number of matching characters */
2829
2830
2831 /*
2832 * Loop through both strings until we hit the end of either or we find
2833 * a non-matching character. For the purposes of comparison, we ignore
2834 * whitespace and do a case-insensitive comparison so that we have a
2835 * better chance of finding a match...
2836 */
2837
2838 for (count = 0; *a && *b; a++, b++, count ++)
2839 {
2840 /*
2841 * Skip leading whitespace characters...
2842 */
2843
2844 while (isspace(*a & 255))
2845 a ++;
2846
2847 while (isspace(*b & 255))
2848 b ++;
2849
2850 /*
2851 * Break out if we run out of characters...
2852 */
2853
2854 if (!*a || !*b)
2855 break;
2856
2857 /*
2858 * Do a case-insensitive comparison of the next two chars...
2859 */
2860
2861 if (tolower(*a & 255) != tolower(*b & 255))
2862 break;
2863 }
2864
2865 return (count);
2866 }
2867
2868
2869 /*
2870 * End of "$Id: admin.c 5360 2006-03-30 17:02:17Z mike $".
2871 */