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