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