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