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