]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/admin.c
Import CUPS trunk (1.4svn) r7116.
[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 *
bc44d920 6 * Copyright 2007 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
323c5de1 1687 buffer = calloc(1, info.st_size + 1);
ef416fc2 1688
323c5de1 1689 cupsFileRead(cupsd, buffer, info.st_size);
1690 cupsFileClose(cupsd);
ef416fc2 1691
323c5de1 1692 cgiSetVariable("CUPSDCONF", buffer);
1693 free(buffer);
ef416fc2 1694
355e94dc
MS
1695 /*
1696 * Then get the default cupsd.conf file and put that into a string as
1697 * well...
1698 */
1699
1700 strlcat(filename, ".default", sizeof(filename));
1701
1702 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1703 (cupsd = cupsFileOpen(filename, "r")) != NULL)
1704 {
1705 buffer = calloc(1, 2 * info.st_size + 1);
1706 bufend = buffer + 2 * info.st_size - 1;
1707
1708 for (bufptr = buffer;
1709 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
1710 {
1711 if (ch == '\\' || ch == '\"')
1712 {
1713 *bufptr++ = '\\';
1714 *bufptr++ = ch;
1715 }
1716 else if (ch == '\n')
1717 {
1718 *bufptr++ = '\\';
1719 *bufptr++ = 'n';
1720 }
1721 else if (ch == '\t')
1722 {
1723 *bufptr++ = '\\';
1724 *bufptr++ = 't';
1725 }
1726 else if (ch >= ' ')
1727 *bufptr++ = ch;
1728 }
1729
1730 *bufptr = '\0';
1731
1732 cupsFileClose(cupsd);
1733
1734 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
1735 free(buffer);
1736 }
1737
323c5de1 1738 /*
1739 * Show the current config file...
1740 */
ef416fc2 1741
323c5de1 1742 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 1743
323c5de1 1744 cgiCopyTemplateLang("edit-config.tmpl");
ef416fc2 1745
323c5de1 1746 cgiEndHTML();
1747 }
1748}
ef416fc2 1749
ef416fc2 1750
323c5de1 1751/*
1752 * 'do_delete_class()' - Delete a class...
1753 */
ef416fc2 1754
323c5de1 1755static void
1756do_delete_class(http_t *http) /* I - HTTP connection */
1757{
1758 ipp_t *request; /* IPP request */
1759 char uri[HTTP_MAX_URI]; /* Job URI */
1760 const char *pclass; /* Printer class name */
ef416fc2 1761
ef416fc2 1762
323c5de1 1763 /*
1764 * Get form variables...
1765 */
ef416fc2 1766
323c5de1 1767 if (cgiGetVariable("CONFIRM") == NULL)
1768 {
1769 cgiStartHTML(cgiText(_("Delete Class")));
1770 cgiCopyTemplateLang("class-confirm.tmpl");
1771 cgiEndHTML();
1772 return;
1773 }
ef416fc2 1774
323c5de1 1775 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
1776 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1777 "localhost", 0, "/classes/%s", pclass);
1778 else
1779 {
1780 cgiStartHTML(cgiText(_("Delete Class")));
1781 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1782 cgiCopyTemplateLang("error.tmpl");
1783 cgiEndHTML();
1784 return;
1785 }
ef416fc2 1786
323c5de1 1787 /*
1788 * Build a CUPS_DELETE_CLASS request, which requires the following
1789 * attributes:
1790 *
1791 * attributes-charset
1792 * attributes-natural-language
1793 * printer-uri
1794 */
1795
1796 request = ippNewRequest(CUPS_DELETE_CLASS);
1797
1798 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1799 NULL, uri);
1800
1801 /*
1802 * Do the request and get back a response...
1803 */
1804
1805 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1806
323c5de1 1807 /*
1808 * Show the results...
1809 */
1810
355e94dc
MS
1811 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1812 {
1813 puts("Status: 401\n");
1814 exit(0);
1815 }
1816 else if (cupsLastError() <= IPP_OK_CONFLICT)
323c5de1 1817 {
ef416fc2 1818 /*
323c5de1 1819 * Redirect successful updates back to the classes page...
ef416fc2 1820 */
1821
323c5de1 1822 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1823 }
ef416fc2 1824
323c5de1 1825 cgiStartHTML(cgiText(_("Delete Class")));
ef416fc2 1826
323c5de1 1827 if (cupsLastError() > IPP_OK_CONFLICT)
1828 cgiShowIPPError(_("Unable to delete class:"));
1829 else
1830 cgiCopyTemplateLang("class-deleted.tmpl");
ef416fc2 1831
323c5de1 1832 cgiEndHTML();
1833}
ef416fc2 1834
ef416fc2 1835
323c5de1 1836/*
1837 * 'do_delete_printer()' - Delete a printer...
1838 */
ef416fc2 1839
323c5de1 1840static void
1841do_delete_printer(http_t *http) /* I - HTTP connection */
1842{
1843 ipp_t *request; /* IPP request */
1844 char uri[HTTP_MAX_URI]; /* Job URI */
1845 const char *printer; /* Printer printer name */
ef416fc2 1846
323c5de1 1847
1848 /*
1849 * Get form variables...
1850 */
1851
1852 if (cgiGetVariable("CONFIRM") == NULL)
1853 {
1854 cgiStartHTML(cgiText(_("Delete Printer")));
1855 cgiCopyTemplateLang("printer-confirm.tmpl");
ef416fc2 1856 cgiEndHTML();
323c5de1 1857 return;
ef416fc2 1858 }
323c5de1 1859
1860 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1861 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1862 "localhost", 0, "/printers/%s", printer);
ef416fc2 1863 else
323c5de1 1864 {
1865 cgiStartHTML(cgiText(_("Delete Printer")));
1866 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1867 cgiCopyTemplateLang("error.tmpl");
1868 cgiEndHTML();
1869 return;
1870 }
1871
1872 /*
1873 * Build a CUPS_DELETE_PRINTER request, which requires the following
1874 * attributes:
1875 *
1876 * attributes-charset
1877 * attributes-natural-language
1878 * printer-uri
1879 */
1880
1881 request = ippNewRequest(CUPS_DELETE_PRINTER);
1882
1883 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1884 NULL, uri);
1885
1886 /*
1887 * Do the request and get back a response...
1888 */
1889
1890 ippDelete(cupsDoRequest(http, request, "/admin/"));
1891
1892 /*
1893 * Show the results...
1894 */
1895
355e94dc
MS
1896 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1897 {
1898 puts("Status: 401\n");
1899 exit(0);
1900 }
1901 else if (cupsLastError() <= IPP_OK_CONFLICT)
ef416fc2 1902 {
1903 /*
323c5de1 1904 * Redirect successful updates back to the printers page...
ef416fc2 1905 */
1906
323c5de1 1907 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1908 }
bd7854cb 1909
323c5de1 1910 cgiStartHTML(cgiText(_("Delete Printer")));
ef416fc2 1911
323c5de1 1912 if (cupsLastError() > IPP_OK_CONFLICT)
1913 cgiShowIPPError(_("Unable to delete printer:"));
1914 else
1915 cgiCopyTemplateLang("printer-deleted.tmpl");
ef416fc2 1916
323c5de1 1917 cgiEndHTML();
1918}
ef416fc2 1919
ef416fc2 1920
323c5de1 1921/*
1922 * 'do_export()' - Export printers to Samba...
1923 */
ef416fc2 1924
323c5de1 1925static void
1926do_export(http_t *http) /* I - HTTP connection */
1927{
1928 int i, j; /* Looping vars */
1929 ipp_t *request, /* IPP request */
1930 *response; /* IPP response */
1931 const char *username, /* Samba username */
1932 *password, /* Samba password */
1933 *export_all; /* Export all printers? */
1934 int export_count, /* Number of printers to export */
1935 printer_count; /* Number of available printers */
1936 const char *name, /* What name to pull */
1937 *dest; /* Current destination */
1938 char ppd[1024]; /* PPD file */
ef416fc2 1939
ef416fc2 1940
323c5de1 1941 /*
1942 * Get form data...
1943 */
ef416fc2 1944
323c5de1 1945 username = cgiGetVariable("USERNAME");
1946 password = cgiGetVariable("PASSWORD");
1947 export_all = cgiGetVariable("EXPORT_ALL");
1948 export_count = cgiGetSize("EXPORT_NAME");
ef416fc2 1949
323c5de1 1950 /*
1951 * Get list of available printers...
1952 */
ef416fc2 1953
323c5de1 1954 cgiSetSize("PRINTER_NAME", 0);
1955 cgiSetSize("PRINTER_EXPORT", 0);
ef416fc2 1956
323c5de1 1957 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 1958
323c5de1 1959 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1960 "printer-type", 0);
ef416fc2 1961
323c5de1 1962 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1963 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
1964 CUPS_PRINTER_IMPLICIT);
ef416fc2 1965
323c5de1 1966 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1967 "requested-attributes", NULL, "printer-name");
ef416fc2 1968
323c5de1 1969 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1970 {
1971 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1972 ippDelete(response);
ef416fc2 1973
323c5de1 1974 if (!export_all)
1975 {
1976 printer_count = cgiGetSize("PRINTER_NAME");
ef416fc2 1977
323c5de1 1978 for (i = 0; i < printer_count; i ++)
1979 {
1980 dest = cgiGetArray("PRINTER_NAME", i);
ef416fc2 1981
323c5de1 1982 for (j = 0; j < export_count; j ++)
1983 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
1984 break;
1985
1986 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
1987 }
1988 }
1989 }
1990
1991 /*
1992 * Export or get the printers to export...
1993 */
ef416fc2 1994
323c5de1 1995 if (username && *username && password && *password &&
1996 (export_all || export_count > 0))
1997 {
ef416fc2 1998 /*
323c5de1 1999 * Do export...
ef416fc2 2000 */
2001
323c5de1 2002 fputs("DEBUG: Export printers...\n", stderr);
ef416fc2 2003
323c5de1 2004 if (export_all)
ef416fc2 2005 {
323c5de1 2006 name = "PRINTER_NAME";
2007 export_count = cgiGetSize("PRINTER_NAME");
ef416fc2 2008 }
2009 else
323c5de1 2010 name = "EXPORT_NAME";
ef416fc2 2011
323c5de1 2012 for (i = 0; i < export_count; i ++)
2013 {
2014 dest = cgiGetArray(name, i);
ef416fc2 2015
323c5de1 2016 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2017 break;
fa73b229 2018
323c5de1 2019 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2020 stderr);
ef416fc2 2021
323c5de1 2022 unlink(ppd);
ef416fc2 2023
323c5de1 2024 if (!j)
2025 break;
ef416fc2 2026 }
2027
323c5de1 2028 if (i < export_count)
2029 cgiSetVariable("ERROR", cupsLastErrorString());
2030 else
2031 {
2032 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2033 cgiCopyTemplateLang("samba-exported.tmpl");
2034 cgiEndHTML();
2035 return;
2036 }
ef416fc2 2037 }
323c5de1 2038 else if (username && !*username)
2039 cgiSetVariable("ERROR",
2040 cgiText(_("A Samba username is required to export "
2041 "printer drivers!")));
2042 else if (username && (!password || !*password))
2043 cgiSetVariable("ERROR",
2044 cgiText(_("A Samba password is required to export "
2045 "printer drivers!")));
2046
2047 /*
2048 * Show form...
2049 */
ef416fc2 2050
323c5de1 2051 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2052 cgiCopyTemplateLang("samba-export.tmpl");
2053 cgiEndHTML();
ef416fc2 2054}
2055
2056
2057/*
323c5de1 2058 * 'do_list_printers()' - List available printers...
ef416fc2 2059 */
2060
2061static void
323c5de1 2062do_list_printers(http_t *http) /* I - HTTP connection */
ef416fc2 2063{
323c5de1 2064 ipp_t *request, /* IPP request */
2065 *response; /* IPP response */
2066 ipp_attribute_t *attr; /* IPP attribute */
ef416fc2 2067
757d2cad 2068
323c5de1 2069 cgiStartHTML(cgiText(_("List Available Printers")));
2070 fflush(stdout);
2071
2072 /*
2073 * Get the list of printers and their devices...
2074 */
2075
2076 request = ippNewRequest(CUPS_GET_PRINTERS);
2077
2078 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2079 "requested-attributes", NULL, "device-uri");
2080
2081 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2082 CUPS_PRINTER_LOCAL);
2083 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2084 CUPS_PRINTER_LOCAL);
757d2cad 2085
323c5de1 2086 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2087 {
d09495fa 2088 /*
323c5de1 2089 * Got the printer list, now load the devices...
d09495fa 2090 */
2091
323c5de1 2092 int i; /* Looping var */
2093 cups_array_t *printer_devices; /* Printer devices for local printers */
2094 char *printer_device; /* Current printer device */
7594b224 2095
d09495fa 2096
2097 /*
323c5de1 2098 * Allocate an array and copy the device strings...
d09495fa 2099 */
2100
323c5de1 2101 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2102
2103 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2104 attr;
2105 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
ef416fc2 2106 {
323c5de1 2107 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
d09495fa 2108 }
2109
2110 /*
323c5de1 2111 * Free the printer list and get the device list...
d09495fa 2112 */
2113
323c5de1 2114 ippDelete(response);
d09495fa 2115
323c5de1 2116 request = ippNewRequest(CUPS_GET_DEVICES);
d09495fa 2117
323c5de1 2118 if ((response = cupsDoRequest(http, request, "/")) != NULL)
ef416fc2 2119 {
d09495fa 2120 /*
323c5de1 2121 * Got the device list, let's parse it...
d09495fa 2122 */
2123
323c5de1 2124 const char *device_uri, /* device-uri attribute value */
2125 *device_make_and_model, /* device-make-and-model value */
2126 *device_info; /* device-info value */
ef416fc2 2127
ef416fc2 2128
323c5de1 2129 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2130 {
2131 /*
2132 * Skip leading attributes until we hit a device...
2133 */
ef416fc2 2134
323c5de1 2135 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2136 attr = attr->next;
ef416fc2 2137
323c5de1 2138 if (!attr)
2139 break;
ef416fc2 2140
323c5de1 2141 /*
2142 * Pull the needed attributes from this device...
2143 */
ef416fc2 2144
323c5de1 2145 device_info = NULL;
2146 device_make_and_model = NULL;
2147 device_uri = NULL;
ef416fc2 2148
323c5de1 2149 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2150 {
2151 if (!strcmp(attr->name, "device-info") &&
2152 attr->value_tag == IPP_TAG_TEXT)
2153 device_info = attr->values[0].string.text;
ef416fc2 2154
323c5de1 2155 if (!strcmp(attr->name, "device-make-and-model") &&
2156 attr->value_tag == IPP_TAG_TEXT)
2157 device_make_and_model = attr->values[0].string.text;
ef416fc2 2158
323c5de1 2159 if (!strcmp(attr->name, "device-uri") &&
2160 attr->value_tag == IPP_TAG_URI)
2161 device_uri = attr->values[0].string.text;
ef416fc2 2162
323c5de1 2163 attr = attr->next;
2164 }
ef416fc2 2165
323c5de1 2166 /*
2167 * See if we have everything needed...
2168 */
ef416fc2 2169
323c5de1 2170 if (device_info && device_make_and_model && device_uri &&
2171 strcasecmp(device_make_and_model, "unknown") &&
2172 strchr(device_uri, ':'))
2173 {
2174 /*
2175 * Yes, now see if there is already a printer for this
2176 * device...
2177 */
ef416fc2 2178
323c5de1 2179 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2180 {
2181 /*
2182 * Not found, so it must be a new printer...
2183 */
ef416fc2 2184
2e4ff8af
MS
2185 char option[1024], /* Form variables for this device */
2186 *option_ptr; /* Pointer into string */
323c5de1 2187 const char *ptr; /* Pointer into device string */
ef416fc2 2188
fa73b229 2189
323c5de1 2190 /*
2191 * Format the printer name variable for this device...
2192 *
2193 * We use the device-info string first, then device-uri,
2194 * and finally device-make-and-model to come up with a
2195 * suitable name.
2196 */
ef416fc2 2197
323c5de1 2198 if (strncasecmp(device_info, "unknown", 7))
2199 ptr = device_info;
2200 else if ((ptr = strstr(device_uri, "://")) != NULL)
2201 ptr += 3;
2202 else
2203 ptr = device_make_and_model;
ef416fc2 2204
2e4ff8af
MS
2205 for (option_ptr = option;
2206 option_ptr < (option + sizeof(option) - 1) && *ptr;
323c5de1 2207 ptr ++)
2208 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2209 *ptr == '.')
2e4ff8af
MS
2210 *option_ptr++ = *ptr;
2211 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2212 *option_ptr++ = '_';
323c5de1 2213 else if (*ptr == '?' || *ptr == '(')
2214 break;
ef416fc2 2215
2e4ff8af 2216 *option_ptr = '\0';
ef416fc2 2217
2e4ff8af 2218 cgiSetArray("TEMPLATE_NAME", i, option);
ef416fc2 2219
323c5de1 2220 /*
2221 * Finally, set the form variables for this printer...
2222 */
ef416fc2 2223
323c5de1 2224 cgiSetArray("device_info", i, device_info);
2225 cgiSetArray("device_make_and_model", i, device_make_and_model);
323c5de1 2226 cgiSetArray("device_uri", i, device_uri);
2227 i ++;
2228 }
2229 }
ef416fc2 2230
323c5de1 2231 if (!attr)
2232 break;
2233 }
2234
2235 ippDelete(response);
ef416fc2 2236
ef416fc2 2237 /*
323c5de1 2238 * Free the device list...
ef416fc2 2239 */
2240
323c5de1 2241 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2242 printer_device;
2243 printer_device = (char *)cupsArrayNext(printer_devices))
2244 free(printer_device);
ef416fc2 2245
323c5de1 2246 cupsArrayDelete(printer_devices);
ef416fc2 2247 }
323c5de1 2248 }
ef416fc2 2249
323c5de1 2250 /*
2251 * Finally, show the printer list...
2252 */
ef416fc2 2253
323c5de1 2254 cgiCopyTemplateLang("list-available-printers.tmpl");
ef416fc2 2255
323c5de1 2256 cgiEndHTML();
ef416fc2 2257}
2258
2259
2260/*
323c5de1 2261 * 'do_menu()' - Show the main menu...
ef416fc2 2262 */
2263
2264static void
323c5de1 2265do_menu(http_t *http) /* I - HTTP connection */
ef416fc2 2266{
323c5de1 2267 int num_settings; /* Number of server settings */
2268 cups_option_t *settings; /* Server settings */
2269 const char *val; /* Setting value */
2270 char filename[1024]; /* Temporary filename */
2271 const char *datadir; /* Location of data files */
2272 ipp_t *request, /* IPP request */
2273 *response; /* IPP response */
ef416fc2 2274
2275
89d46774 2276 /*
323c5de1 2277 * Get the current server settings...
89d46774 2278 */
fa73b229 2279
323c5de1 2280 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 2281 {
323c5de1 2282 cgiSetVariable("SETTINGS_MESSAGE",
2283 cgiText(_("Unable to open cupsd.conf file:")));
2284 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
ef416fc2 2285 }
2286
323c5de1 2287 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2288 settings)) != NULL && atoi(val))
2289 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
ef416fc2 2290
323c5de1 2291 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2292 settings)) != NULL && atoi(val))
2293 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
ef416fc2 2294
323c5de1 2295 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2296 settings)) != NULL && atoi(val))
2297 cgiSetVariable("REMOTE_ANY", "CHECKED");
ef416fc2 2298
323c5de1 2299 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2300 settings)) != NULL && atoi(val))
2301 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
ef416fc2 2302
323c5de1 2303 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2304 settings)) != NULL && atoi(val))
2305 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
ef416fc2 2306
323c5de1 2307 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2308 settings)) != NULL && atoi(val))
2309 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2310
2311#ifdef HAVE_GSSAPI
2312 cgiSetVariable("HAVE_GSSAPI", "1");
2313
2314 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2315 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2316 cgiSetVariable("KERBEROS", "CHECKED");
2317#endif /* HAVE_GSSAPI */
2318
2319 cupsFreeOptions(num_settings, settings);
ef416fc2 2320
89d46774 2321 /*
323c5de1 2322 * See if Samba and the Windows drivers are installed...
89d46774 2323 */
2324
323c5de1 2325 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2326 datadir = CUPS_DATADIR;
2327
2328 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2329 if (!access(filename, R_OK))
f7deaa1a 2330 {
2331 /*
323c5de1 2332 * Found Windows 2000 driver file, see if we have smbclient and
2333 * rpcclient...
f7deaa1a 2334 */
2335
323c5de1 2336 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2337 sizeof(filename)) &&
2338 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2339 sizeof(filename)))
2340 cgiSetVariable("HAVE_SAMBA", "Y");
2341 else
2342 {
2343 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2344 sizeof(filename)))
2345 fputs("ERROR: smbclient not found!\n", stderr);
2346
2347 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2348 sizeof(filename)))
2349 fputs("ERROR: rpcclient not found!\n", stderr);
2350 }
f7deaa1a 2351 }
323c5de1 2352 else
2353 perror(filename);
f7deaa1a 2354
323c5de1 2355 /*
2356 * Subscriptions...
2357 */
89d46774 2358
323c5de1 2359 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2360
2361 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2362 NULL, "ipp://localhost/");
2363
2364 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2365 {
2366 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2367 ippDelete(response);
2368 }
2369
2370 /*
2371 * Finally, show the main menu template...
2372 */
2373
2374 cgiStartHTML(cgiText(_("Administration")));
2375
2376 cgiCopyTemplateLang("admin.tmpl");
ef416fc2 2377
2378 cgiEndHTML();
2379}
2380
2381
2382/*
323c5de1 2383 * 'do_printer_op()' - Do a printer operation.
ef416fc2 2384 */
2385
2386static void
323c5de1 2387do_printer_op(http_t *http, /* I - HTTP connection */
2388 ipp_op_t op, /* I - Operation to perform */
2389 const char *title) /* I - Title of page */
ef416fc2 2390{
fa73b229 2391 ipp_t *request; /* IPP request */
323c5de1 2392 char uri[HTTP_MAX_URI]; /* Printer URI */
2393 const char *printer, /* Printer name (purge-jobs) */
2394 *is_class; /* Is a class? */
ef416fc2 2395
fa73b229 2396
323c5de1 2397 is_class = cgiGetVariable("IS_CLASS");
2398 printer = cgiGetVariable("PRINTER_NAME");
ef416fc2 2399
323c5de1 2400 if (!printer)
ef416fc2 2401 {
fa73b229 2402 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
323c5de1 2403 cgiStartHTML(title);
ef416fc2 2404 cgiCopyTemplateLang("error.tmpl");
2405 cgiEndHTML();
2406 return;
2407 }
2408
2409 /*
323c5de1 2410 * Build a printer request, which requires the following
ef416fc2 2411 * attributes:
2412 *
2413 * attributes-charset
2414 * attributes-natural-language
2415 * printer-uri
2416 */
2417
323c5de1 2418 request = ippNewRequest(op);
ef416fc2 2419
323c5de1 2420 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2421 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2422 printer);
ef416fc2 2423 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2424 NULL, uri);
2425
2426 /*
2427 * Do the request and get back a response...
2428 */
2429
fa73b229 2430 ippDelete(cupsDoRequest(http, request, "/admin/"));
2431
355e94dc
MS
2432 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2433 {
2434 puts("Status: 401\n");
2435 exit(0);
2436 }
2437 else if (cupsLastError() > IPP_OK_CONFLICT)
323c5de1 2438 {
2439 cgiStartHTML(title);
2440 cgiShowIPPError(_("Unable to change printer:"));
2441 }
2442 else
f7deaa1a 2443 {
2444 /*
323c5de1 2445 * Redirect successful updates back to the printer page...
f7deaa1a 2446 */
2447
323c5de1 2448 char url[1024], /* Printer/class URL */
2449 refresh[1024]; /* Refresh URL */
f7deaa1a 2450
89d46774 2451
323c5de1 2452 cgiRewriteURL(uri, url, sizeof(url), NULL);
2453 cgiFormEncode(uri, url, sizeof(uri));
2454 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
2455 cgiSetVariable("refresh_page", refresh);
2456
2457 cgiStartHTML(title);
2458
2459 if (op == IPP_PAUSE_PRINTER)
2460 cgiCopyTemplateLang("printer-stop.tmpl");
2461 else if (op == IPP_RESUME_PRINTER)
2462 cgiCopyTemplateLang("printer-start.tmpl");
2463 else if (op == CUPS_ACCEPT_JOBS)
2464 cgiCopyTemplateLang("printer-accept.tmpl");
2465 else if (op == CUPS_REJECT_JOBS)
2466 cgiCopyTemplateLang("printer-reject.tmpl");
2467 else if (op == IPP_PURGE_JOBS)
2468 cgiCopyTemplateLang("printer-purge.tmpl");
2469 else if (op == CUPS_SET_DEFAULT)
2470 cgiCopyTemplateLang("printer-default.tmpl");
2471 }
fa73b229 2472
2473 cgiEndHTML();
2474}
2475
2476
2477/*
323c5de1 2478 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
fa73b229 2479 */
2480
2481static void
323c5de1 2482do_set_allowed_users(http_t *http) /* I - HTTP connection */
fa73b229 2483{
323c5de1 2484 int i; /* Looping var */
fa73b229 2485 ipp_t *request, /* IPP request */
2486 *response; /* IPP response */
323c5de1 2487 char uri[HTTP_MAX_URI]; /* Printer URI */
2488 const char *printer, /* Printer name (purge-jobs) */
2489 *is_class, /* Is a class? */
2490 *users, /* List of users or groups */
2491 *type; /* Allow/deny type */
2492 int num_users; /* Number of users */
2493 char *ptr, /* Pointer into users string */
2494 *end, /* Pointer to end of users string */
2495 quote; /* Quote character */
2496 ipp_attribute_t *attr; /* Attribute */
2497 static const char * const attrs[] = /* Requested attributes */
2498 {
2499 "requesting-user-name-allowed",
2500 "requesting-user-name-denied"
2501 };
fa73b229 2502
fa73b229 2503
323c5de1 2504 is_class = cgiGetVariable("IS_CLASS");
2505 printer = cgiGetVariable("PRINTER_NAME");
fa73b229 2506
323c5de1 2507 if (!printer)
2508 {
2509 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2510 cgiStartHTML(cgiText(_("Set Allowed Users")));
2511 cgiCopyTemplateLang("error.tmpl");
2512 cgiEndHTML();
2513 return;
2514 }
ef416fc2 2515
323c5de1 2516 users = cgiGetVariable("users");
2517 type = cgiGetVariable("type");
ef416fc2 2518
323c5de1 2519 if (!users || !type ||
2520 (strcmp(type, "requesting-user-name-allowed") &&
2521 strcmp(type, "requesting-user-name-denied")))
2522 {
2523 /*
2524 * Build a Get-Printer-Attributes request, which requires the following
2525 * attributes:
2526 *
2527 * attributes-charset
2528 * attributes-natural-language
2529 * printer-uri
2530 * requested-attributes
2531 */
fa73b229 2532
323c5de1 2533 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
fa73b229 2534
323c5de1 2535 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2536 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2537 printer);
2538 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2539 NULL, uri);
fa73b229 2540
323c5de1 2541 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2542 "requested-attributes",
2543 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
fa73b229 2544
323c5de1 2545 /*
2546 * Do the request and get back a response...
2547 */
fa73b229 2548
323c5de1 2549 if ((response = cupsDoRequest(http, request, "/")) != NULL)
fa73b229 2550 {
323c5de1 2551 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
fa73b229 2552
323c5de1 2553 ippDelete(response);
fa73b229 2554 }
ef416fc2 2555
323c5de1 2556 cgiStartHTML(cgiText(_("Set Allowed Users")));
757d2cad 2557
355e94dc
MS
2558 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2559 {
2560 puts("Status: 401\n");
2561 exit(0);
2562 }
2563 else if (cupsLastError() > IPP_OK_CONFLICT)
323c5de1 2564 cgiShowIPPError(_("Unable to get printer attributes:"));
2565 else
2566 cgiCopyTemplateLang("users.tmpl");
2567
2568 cgiEndHTML();
2569 }
2570 else
757d2cad 2571 {
2572 /*
323c5de1 2573 * Save the changes...
757d2cad 2574 */
2575
323c5de1 2576 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
757d2cad 2577 {
323c5de1 2578 /*
2579 * Skip whitespace and commas...
2580 */
fa73b229 2581
323c5de1 2582 while (*ptr == ',' || isspace(*ptr & 255))
2583 ptr ++;
ef416fc2 2584
323c5de1 2585 if (*ptr == '\'' || *ptr == '\"')
2586 {
2587 /*
2588 * Scan quoted name...
2589 */
ef416fc2 2590
323c5de1 2591 quote = *ptr++;
ef416fc2 2592
323c5de1 2593 for (end = ptr; *end; end ++)
2594 if (*end == quote)
2595 break;
2596 }
2597 else
2598 {
2599 /*
2600 * Scan space or comma-delimited name...
2601 */
ef416fc2 2602
323c5de1 2603 for (end = ptr; *end; end ++)
2604 if (isspace(*end & 255) || *end == ',')
2605 break;
2606 }
ef416fc2 2607
323c5de1 2608 /*
2609 * Advance to the next name...
2610 */
ef416fc2 2611
323c5de1 2612 ptr = end;
2613 }
ef416fc2 2614
323c5de1 2615 /*
2616 * Build a CUPS-Add-Printer/Class request, which requires the following
2617 * attributes:
2618 *
2619 * attributes-charset
2620 * attributes-natural-language
2621 * printer-uri
2622 * requesting-user-name-{allowed,denied}
2623 */
ef416fc2 2624
323c5de1 2625 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 2626
323c5de1 2627 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2628 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2629 printer);
2630 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2631 NULL, uri);
f7deaa1a 2632
323c5de1 2633 if (num_users == 0)
2634 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2635 "requesting-user-name-allowed", NULL, "all");
2636 else
2637 {
2638 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2639 type, num_users, NULL, NULL);
ef416fc2 2640
323c5de1 2641 for (i = 0, ptr = (char *)users; *ptr; i ++)
2642 {
2643 /*
2644 * Skip whitespace and commas...
2645 */
ef416fc2 2646
323c5de1 2647 while (*ptr == ',' || isspace(*ptr & 255))
2648 ptr ++;
ef416fc2 2649
323c5de1 2650 if (*ptr == '\'' || *ptr == '\"')
2651 {
2652 /*
2653 * Scan quoted name...
2654 */
7594b224 2655
323c5de1 2656 quote = *ptr++;
7594b224 2657
323c5de1 2658 for (end = ptr; *end; end ++)
2659 if (*end == quote)
2660 break;
2661 }
2662 else
2663 {
2664 /*
2665 * Scan space or comma-delimited name...
2666 */
480ef0fe 2667
323c5de1 2668 for (end = ptr; *end; end ++)
2669 if (isspace(*end & 255) || *end == ',')
2670 break;
2671 }
ef416fc2 2672
323c5de1 2673 /*
2674 * Terminate the name...
2675 */
ef416fc2 2676
323c5de1 2677 if (*end)
2678 *end++ = '\0';
ef416fc2 2679
323c5de1 2680 /*
2681 * Add the name...
2682 */
ef416fc2 2683
323c5de1 2684 attr->values[i].string.text = strdup(ptr);
ef416fc2 2685
323c5de1 2686 /*
2687 * Advance to the next name...
2688 */
ef416fc2 2689
323c5de1 2690 ptr = end;
2691 }
2692 }
ef416fc2 2693
2694 /*
323c5de1 2695 * Do the request and get back a response...
ef416fc2 2696 */
2697
323c5de1 2698 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2699
355e94dc
MS
2700 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2701 {
2702 puts("Status: 401\n");
2703 exit(0);
2704 }
2705 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 2706 {
323c5de1 2707 cgiStartHTML(cgiText(_("Set Allowed Users")));
2708 cgiShowIPPError(_("Unable to change printer:"));
ef416fc2 2709 }
323c5de1 2710 else
ef416fc2 2711 {
2712 /*
323c5de1 2713 * Redirect successful updates back to the printer page...
ef416fc2 2714 */
2715
323c5de1 2716 char url[1024], /* Printer/class URL */
2717 refresh[1024]; /* Refresh URL */
ef416fc2 2718
2719
323c5de1 2720 cgiRewriteURL(uri, url, sizeof(url), NULL);
2721 cgiFormEncode(uri, url, sizeof(uri));
2722 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
2723 uri);
2724 cgiSetVariable("refresh_page", refresh);
ef416fc2 2725
323c5de1 2726 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 2727
323c5de1 2728 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2729 "printer-modified.tmpl");
2730 }
ef416fc2 2731
323c5de1 2732 cgiEndHTML();
2733 }
2734}
ef416fc2 2735
ef416fc2 2736
323c5de1 2737/*
2738 * 'do_set_options()' - Configure the default options for a queue.
2739 */
ef416fc2 2740
323c5de1 2741static void
2742do_set_options(http_t *http, /* I - HTTP connection */
2743 int is_class) /* I - Set options for class? */
2744{
2745 int i, j, k, m; /* Looping vars */
2746 int have_options; /* Have options? */
2747 ipp_t *request, /* IPP request */
2748 *response; /* IPP response */
2749 ipp_attribute_t *attr; /* IPP attribute */
2750 char uri[HTTP_MAX_URI]; /* Job URI */
2751 const char *var; /* Variable value */
2752 const char *printer; /* Printer printer name */
2753 const char *filename; /* PPD filename */
2754 char tempfile[1024]; /* Temporary filename */
2755 cups_file_t *in, /* Input file */
2756 *out; /* Output file */
2757 char line[1024]; /* Line from PPD file */
2758 char keyword[1024], /* Keyword from Default line */
2759 *keyptr; /* Pointer into keyword... */
2760 ppd_file_t *ppd; /* PPD file */
2761 ppd_group_t *group; /* Option group */
2762 ppd_option_t *option; /* Option */
2763 ppd_attr_t *protocol; /* cupsProtocol attribute */
2764 const char *title; /* Page title */
ef416fc2 2765
ef416fc2 2766
323c5de1 2767 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
ef416fc2 2768
323c5de1 2769 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
2770 is_class);
ef416fc2 2771
323c5de1 2772 /*
2773 * Get the printer name...
2774 */
ef416fc2 2775
323c5de1 2776 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2777 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2778 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2779 printer);
2780 else
2781 {
2782 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2783 cgiStartHTML(title);
2784 cgiCopyTemplateLang("error.tmpl");
2785 cgiEndHTML();
2786 return;
2787 }
ef416fc2 2788
323c5de1 2789 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
ef416fc2 2790
323c5de1 2791 /*
2792 * Get the PPD file...
2793 */
ef416fc2 2794
323c5de1 2795 if (is_class)
2796 filename = NULL;
2797 else
2798 filename = cupsGetPPD2(http, printer);
ef416fc2 2799
323c5de1 2800 if (filename)
2801 {
2802 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
ef416fc2 2803
323c5de1 2804 if ((ppd = ppdOpenFile(filename)) == NULL)
2805 {
2806 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
2807 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2808 cgiStartHTML(title);
2809 cgiCopyTemplateLang("error.tmpl");
2810 cgiEndHTML();
2811 return;
2812 }
2813 }
2814 else
2815 {
2816 fputs("DEBUG: No PPD file\n", stderr);
2817 ppd = NULL;
2818 }
ef416fc2 2819
323c5de1 2820 if (cgiGetVariable("job_sheets_start") != NULL ||
2821 cgiGetVariable("job_sheets_end") != NULL)
2822 have_options = 1;
2823 else
2824 have_options = 0;
ef416fc2 2825
323c5de1 2826 if (ppd)
2827 {
2828 ppdMarkDefaults(ppd);
ef416fc2 2829
323c5de1 2830 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2831 "<UL>\n", ppd->num_groups));
ef416fc2 2832
323c5de1 2833 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2834 {
2835 DEBUG_printf(("<LI>%s<UL>\n", group->text));
ef416fc2 2836
323c5de1 2837 for (j = group->num_options, option = group->options;
2838 j > 0;
2839 j --, option ++)
2840 if ((var = cgiGetVariable(option->keyword)) != NULL)
2841 {
2842 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
2843 have_options = 1;
2844 ppdMarkOption(ppd, option->keyword, var);
ef416fc2 2845 }
323c5de1 2846#ifdef DEBUG
2847 else
2848 printf("<LI>%s not defined!</LI>\n", option->keyword);
2849#endif /* DEBUG */
ef416fc2 2850
323c5de1 2851 DEBUG_puts("</UL></LI>");
ef416fc2 2852 }
fa73b229 2853
323c5de1 2854 DEBUG_printf(("</UL>\n"
2855 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
2856 }
fa73b229 2857
323c5de1 2858 if (!have_options || ppdConflicts(ppd))
fa73b229 2859 {
2860 /*
323c5de1 2861 * Show the options to the user...
fa73b229 2862 */
2863
323c5de1 2864 fputs("DEBUG: Showing options...\n", stderr);
fa73b229 2865
323c5de1 2866 cgiStartHTML(cgiText(_("Set Printer Options")));
2867 cgiCopyTemplateLang("set-printer-options-header.tmpl");
fa73b229 2868
323c5de1 2869 if (ppd)
2870 {
2871 ppdLocalize(ppd);
f7deaa1a 2872
323c5de1 2873 if (ppdConflicts(ppd))
2874 {
2875 for (i = ppd->num_groups, k = 0, group = ppd->groups;
2876 i > 0;
2877 i --, group ++)
2878 for (j = group->num_options, option = group->options;
2879 j > 0;
2880 j --, option ++)
2881 if (option->conflicted)
2882 {
2883 cgiSetArray("ckeyword", k, option->keyword);
2884 cgiSetArray("ckeytext", k, option->text);
2885 k ++;
2886 }
f7deaa1a 2887
323c5de1 2888 cgiCopyTemplateLang("option-conflict.tmpl");
2889 }
f7deaa1a 2890
323c5de1 2891 for (i = ppd->num_groups, group = ppd->groups;
2892 i > 0;
2893 i --, group ++)
2894 {
2895 if (!strcmp(group->name, "InstallableOptions"))
2896 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2897 else
2898 cgiSetVariable("GROUP", group->text);
f7deaa1a 2899
323c5de1 2900 cgiCopyTemplateLang("option-header.tmpl");
2901
2902 for (j = group->num_options, option = group->options;
2903 j > 0;
2904 j --, option ++)
2905 {
2906 if (!strcmp(option->keyword, "PageRegion"))
2907 continue;
ef416fc2 2908
323c5de1 2909 cgiSetVariable("KEYWORD", option->keyword);
2910 cgiSetVariable("KEYTEXT", option->text);
2911
2912 if (option->conflicted)
2913 cgiSetVariable("CONFLICTED", "1");
2914 else
2915 cgiSetVariable("CONFLICTED", "0");
2916
2917 cgiSetSize("CHOICES", 0);
2918 cgiSetSize("TEXT", 0);
2919 for (k = 0, m = 0; k < option->num_choices; k ++)
2920 {
2921 /*
2922 * Hide custom option values...
2923 */
757d2cad 2924
323c5de1 2925 if (!strcmp(option->choices[k].choice, "Custom"))
2926 continue;
ef416fc2 2927
323c5de1 2928 cgiSetArray("CHOICES", m, option->choices[k].choice);
2929 cgiSetArray("TEXT", m, option->choices[k].text);
ef416fc2 2930
323c5de1 2931 m ++;
ef416fc2 2932
323c5de1 2933 if (option->choices[k].marked)
2934 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
2935 }
ef416fc2 2936
323c5de1 2937 switch (option->ui)
2938 {
2939 case PPD_UI_BOOLEAN :
2940 cgiCopyTemplateLang("option-boolean.tmpl");
2941 break;
2942 case PPD_UI_PICKONE :
2943 cgiCopyTemplateLang("option-pickone.tmpl");
2944 break;
2945 case PPD_UI_PICKMANY :
2946 cgiCopyTemplateLang("option-pickmany.tmpl");
2947 break;
2948 }
2949 }
ef416fc2 2950
323c5de1 2951 cgiCopyTemplateLang("option-trailer.tmpl");
2952 }
2953 }
ef416fc2 2954
323c5de1 2955 /*
2956 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2957 * following attributes:
2958 *
2959 * attributes-charset
2960 * attributes-natural-language
2961 * printer-uri
2962 */
fa73b229 2963
323c5de1 2964 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 2965
323c5de1 2966 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2967 "localhost", 0, "/printers/%s", printer);
2968 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2969 NULL, uri);
ef416fc2 2970
323c5de1 2971 /*
2972 * Do the request and get back a response...
2973 */
ef416fc2 2974
323c5de1 2975 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2976 {
2977 if ((attr = ippFindAttribute(response, "job-sheets-supported",
2978 IPP_TAG_ZERO)) != NULL)
2979 {
2980 /*
2981 * Add the job sheets options...
2982 */
ef416fc2 2983
323c5de1 2984 cgiSetVariable("GROUP", cgiText(_("Banners")));
2985 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 2986
323c5de1 2987 cgiSetSize("CHOICES", attr->num_values);
2988 cgiSetSize("TEXT", attr->num_values);
2989 for (k = 0; k < attr->num_values; k ++)
2990 {
2991 cgiSetArray("CHOICES", k, attr->values[k].string.text);
2992 cgiSetArray("TEXT", k, attr->values[k].string.text);
2993 }
ef416fc2 2994
323c5de1 2995 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
ef416fc2 2996
323c5de1 2997 cgiSetVariable("KEYWORD", "job_sheets_start");
2998 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
2999 cgiSetVariable("DEFCHOICE", attr == NULL ?
3000 "" : attr->values[0].string.text);
ef416fc2 3001
323c5de1 3002 cgiCopyTemplateLang("option-pickone.tmpl");
fa73b229 3003
323c5de1 3004 cgiSetVariable("KEYWORD", "job_sheets_end");
3005 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3006 cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
3007 "" : attr->values[1].string.text);
ef416fc2 3008
323c5de1 3009 cgiCopyTemplateLang("option-pickone.tmpl");
ef416fc2 3010
323c5de1 3011 cgiCopyTemplateLang("option-trailer.tmpl");
3012 }
ef416fc2 3013
323c5de1 3014 if (ippFindAttribute(response, "printer-error-policy-supported",
3015 IPP_TAG_ZERO) ||
3016 ippFindAttribute(response, "printer-op-policy-supported",
3017 IPP_TAG_ZERO))
3018 {
3019 /*
3020 * Add the error and operation policy options...
3021 */
ef416fc2 3022
323c5de1 3023 cgiSetVariable("GROUP", cgiText(_("Policies")));
3024 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 3025
323c5de1 3026 /*
3027 * Error policy...
3028 */
ef416fc2 3029
323c5de1 3030 attr = ippFindAttribute(response, "printer-error-policy-supported",
3031 IPP_TAG_ZERO);
3032
3033 if (attr)
3034 {
3035 cgiSetSize("CHOICES", attr->num_values);
3036 cgiSetSize("TEXT", attr->num_values);
3037 for (k = 0; k < attr->num_values; k ++)
3038 {
3039 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3040 cgiSetArray("TEXT", k, attr->values[k].string.text);
3041 }
ef416fc2 3042
323c5de1 3043 attr = ippFindAttribute(response, "printer-error-policy",
3044 IPP_TAG_ZERO);
ef416fc2 3045
323c5de1 3046 cgiSetVariable("KEYWORD", "printer_error_policy");
3047 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3048 cgiSetVariable("DEFCHOICE", attr == NULL ?
3049 "" : attr->values[0].string.text);
3050 }
fa73b229 3051
323c5de1 3052 cgiCopyTemplateLang("option-pickone.tmpl");
ef416fc2 3053
323c5de1 3054 /*
3055 * Operation policy...
3056 */
ef416fc2 3057
323c5de1 3058 attr = ippFindAttribute(response, "printer-op-policy-supported",
3059 IPP_TAG_ZERO);
ef416fc2 3060
323c5de1 3061 if (attr)
3062 {
3063 cgiSetSize("CHOICES", attr->num_values);
3064 cgiSetSize("TEXT", attr->num_values);
3065 for (k = 0; k < attr->num_values; k ++)
3066 {
3067 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3068 cgiSetArray("TEXT", k, attr->values[k].string.text);
3069 }
ef416fc2 3070
323c5de1 3071 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
ef416fc2 3072
323c5de1 3073 cgiSetVariable("KEYWORD", "printer_op_policy");
3074 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3075 cgiSetVariable("DEFCHOICE", attr == NULL ?
3076 "" : attr->values[0].string.text);
ef416fc2 3077
323c5de1 3078 cgiCopyTemplateLang("option-pickone.tmpl");
3079 }
ef416fc2 3080
323c5de1 3081 cgiCopyTemplateLang("option-trailer.tmpl");
3082 }
ef416fc2 3083
3084 ippDelete(response);
3085 }
ef416fc2 3086
ef416fc2 3087 /*
323c5de1 3088 * Binary protocol support...
ef416fc2 3089 */
3090
323c5de1 3091 if (ppd->protocols && strstr(ppd->protocols, "BCP"))
ef416fc2 3092 {
323c5de1 3093 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
ef416fc2 3094
323c5de1 3095 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3096 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 3097
323c5de1 3098 cgiSetSize("CHOICES", 2);
3099 cgiSetSize("TEXT", 2);
3100 cgiSetArray("CHOICES", 0, "None");
3101 cgiSetArray("TEXT", 0, cgiText(_("None")));
ef416fc2 3102
323c5de1 3103 if (strstr(ppd->protocols, "TBCP"))
3104 {
3105 cgiSetArray("CHOICES", 1, "TBCP");
3106 cgiSetArray("TEXT", 1, "TBCP");
ef416fc2 3107 }
3108 else
3109 {
323c5de1 3110 cgiSetArray("CHOICES", 1, "BCP");
3111 cgiSetArray("TEXT", 1, "BCP");
ef416fc2 3112 }
3113
323c5de1 3114 cgiSetVariable("KEYWORD", "protocol");
3115 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3116 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
ef416fc2 3117
323c5de1 3118 cgiCopyTemplateLang("option-pickone.tmpl");
3119
3120 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3121 }
3122
323c5de1 3123 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3124 cgiEndHTML();
3125 }
3126 else
3127 {
ef416fc2 3128 /*
323c5de1 3129 * Set default options...
ef416fc2 3130 */
3131
323c5de1 3132 fputs("DEBUG: Setting options...\n", stderr);
ef416fc2 3133
323c5de1 3134 if (filename)
ef416fc2 3135 {
323c5de1 3136 out = cupsTempFile2(tempfile, sizeof(tempfile));
3137 in = cupsFileOpen(filename, "r");
ef416fc2 3138
323c5de1 3139 if (!in || !out)
ef416fc2 3140 {
323c5de1 3141 cgiSetVariable("ERROR", strerror(errno));
3142 cgiStartHTML(cgiText(_("Set Printer Options")));
3143 cgiCopyTemplateLang("error.tmpl");
3144 cgiEndHTML();
ef416fc2 3145
323c5de1 3146 if (in)
3147 cupsFileClose(in);
ef416fc2 3148
323c5de1 3149 if (out)
ef416fc2 3150 {
323c5de1 3151 cupsFileClose(out);
3152 unlink(tempfile);
3153 }
ef416fc2 3154
323c5de1 3155 unlink(filename);
3156 return;
3157 }
ef416fc2 3158
323c5de1 3159 while (cupsFileGets(in, line, sizeof(line)))
3160 {
3161 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3162 continue;
3163 else if (strncmp(line, "*Default", 8))
3164 cupsFilePrintf(out, "%s\n", line);
ef416fc2 3165 else
3166 {
3167 /*
323c5de1 3168 * Get default option name...
ef416fc2 3169 */
3170
323c5de1 3171 strlcpy(keyword, line + 8, sizeof(keyword));
3172
3173 for (keyptr = keyword; *keyptr; keyptr ++)
3174 if (*keyptr == ':' || isspace(*keyptr & 255))
ef416fc2 3175 break;
ef416fc2 3176
323c5de1 3177 *keyptr = '\0';
ef416fc2 3178
323c5de1 3179 if (!strcmp(keyword, "PageRegion") ||
3180 !strcmp(keyword, "PaperDimension") ||
3181 !strcmp(keyword, "ImageableArea"))
3182 var = cgiGetVariable("PageSize");
3183 else
3184 var = cgiGetVariable(keyword);
ef416fc2 3185
323c5de1 3186 if (var != NULL)
3187 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3188 else
3189 cupsFilePrintf(out, "%s\n", line);
3190 }
3191 }
ef416fc2 3192
323c5de1 3193 if ((var = cgiGetVariable("protocol")) != NULL)
3194 cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
ef416fc2 3195
323c5de1 3196 cupsFileClose(in);
3197 cupsFileClose(out);
3198 }
3199 else
3200 {
3201 /*
3202 * Make sure temporary filename is cleared when there is no PPD...
3203 */
ef416fc2 3204
323c5de1 3205 tempfile[0] = '\0';
ef416fc2 3206 }
3207
323c5de1 3208 /*
3209 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3210 * following attributes:
3211 *
3212 * attributes-charset
3213 * attributes-natural-language
3214 * printer-uri
3215 * job-sheets-default
3216 * printer-error-policy
3217 * printer-op-policy
3218 * [ppd file]
3219 */
3220
3221 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3222 CUPS_ADD_MODIFY_PRINTER);
3223
3224 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3225 NULL, uri);
3226
3227 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3228 "job-sheets-default", 2, NULL, NULL);
3229 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3230 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3231
3232 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3233 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3234 "printer-error-policy", NULL, var);
3235
3236 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3237 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3238 "printer-op-policy", NULL, var);
3239
ef416fc2 3240 /*
3241 * Do the request and get back a response...
3242 */
3243
323c5de1 3244 if (filename)
3245 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3246 else
3247 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3248
355e94dc
MS
3249 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3250 {
3251 puts("Status: 401\n");
3252 exit(0);
3253 }
3254 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3255 {
323c5de1 3256 cgiStartHTML(title);
3257 cgiShowIPPError(_("Unable to set options:"));
ef416fc2 3258 }
3259 else
3260 {
3261 /*
3262 * Redirect successful updates back to the printer page...
3263 */
3264
323c5de1 3265 char refresh[1024]; /* Refresh URL */
ef416fc2 3266
fa73b229 3267
323c5de1 3268 cgiFormEncode(uri, printer, sizeof(uri));
3269 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3270 is_class ? "classes" : "printers", uri);
ef416fc2 3271 cgiSetVariable("refresh_page", refresh);
3272
323c5de1 3273 cgiStartHTML(title);
ef416fc2 3274
323c5de1 3275 cgiCopyTemplateLang("printer-configured.tmpl");
ef416fc2 3276 }
3277
3278 cgiEndHTML();
323c5de1 3279
3280 if (filename)
3281 unlink(tempfile);
ef416fc2 3282 }
323c5de1 3283
3284 if (filename)
3285 unlink(filename);
ef416fc2 3286}
3287
3288
3289/*
3290 * 'do_set_sharing()' - Set printer-is-shared value...
3291 */
3292
3293static void
fa73b229 3294do_set_sharing(http_t *http) /* I - HTTP connection */
ef416fc2 3295{
3296 ipp_t *request, /* IPP request */
3297 *response; /* IPP response */
3298 char uri[HTTP_MAX_URI]; /* Printer URI */
3299 const char *printer, /* Printer name */
fa73b229 3300 *is_class, /* Is a class? */
ef416fc2 3301 *shared; /* Sharing value */
ef416fc2 3302
3303
fa73b229 3304 is_class = cgiGetVariable("IS_CLASS");
3305 printer = cgiGetVariable("PRINTER_NAME");
3306 shared = cgiGetVariable("SHARED");
ef416fc2 3307
fa73b229 3308 if (!printer || !shared)
ef416fc2 3309 {
fa73b229 3310 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3311 cgiStartHTML(cgiText(_("Set Publishing")));
ef416fc2 3312 cgiCopyTemplateLang("error.tmpl");
3313 cgiEndHTML();
3314 return;
3315 }
3316
3317 /*
fa73b229 3318 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3319 * following attributes:
ef416fc2 3320 *
3321 * attributes-charset
3322 * attributes-natural-language
3323 * printer-uri
3324 * printer-is-shared
3325 */
3326
fa73b229 3327 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3328
a4d04587 3329 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3330 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3331 printer);
ef416fc2 3332 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3333 NULL, uri);
3334
3335 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3336
3337 /*
3338 * Do the request and get back a response...
3339 */
3340
3341 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3342 {
ef416fc2 3343 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3344
3345 ippDelete(response);
3346 }
ef416fc2 3347
355e94dc
MS
3348 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3349 {
3350 puts("Status: 401\n");
3351 exit(0);
3352 }
3353 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3354 {
fa73b229 3355 cgiStartHTML(cgiText(_("Set Publishing")));
3356 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
ef416fc2 3357 }
3358 else
3359 {
3360 /*
3361 * Redirect successful updates back to the printer page...
3362 */
3363
fa73b229 3364 char url[1024], /* Printer/class URL */
3365 refresh[1024]; /* Refresh URL */
ef416fc2 3366
ef416fc2 3367
fa73b229 3368 cgiRewriteURL(uri, url, sizeof(url), NULL);
3369 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3370 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
fa73b229 3371 cgiSetVariable("refresh_page", refresh);
ef416fc2 3372
fa73b229 3373 cgiStartHTML(cgiText(_("Set Publishing")));
3374 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3375 "printer-modified.tmpl");
ef416fc2 3376 }
3377
3378 cgiEndHTML();
3379}
3380
3381
3382/*
3383 * 'match_string()' - Return the number of matching characters.
3384 */
3385
3386static int /* O - Number of matching characters */
3387match_string(const char *a, /* I - First string */
3388 const char *b) /* I - Second string */
3389{
3390 int count; /* Number of matching characters */
3391
3392
3393 /*
3394 * Loop through both strings until we hit the end of either or we find
3395 * a non-matching character. For the purposes of comparison, we ignore
3396 * whitespace and do a case-insensitive comparison so that we have a
3397 * better chance of finding a match...
3398 */
3399
3400 for (count = 0; *a && *b; a++, b++, count ++)
3401 {
3402 /*
3403 * Skip leading whitespace characters...
3404 */
3405
3406 while (isspace(*a & 255))
3407 a ++;
3408
3409 while (isspace(*b & 255))
3410 b ++;
3411
3412 /*
3413 * Break out if we run out of characters...
3414 */
3415
3416 if (!*a || !*b)
3417 break;
3418
3419 /*
3420 * Do a case-insensitive comparison of the next two chars...
3421 */
3422
3423 if (tolower(*a & 255) != tolower(*b & 255))
3424 break;
3425 }
3426
3427 return (count);
3428}
3429
3430
3431/*
2e4ff8af 3432 * End of "$Id: admin.c 7012 2007-10-10 21:22:45Z mike $".
ef416fc2 3433 */