]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lpadmin.c
Fix lpadmin when both -m and -o are used (STR #4578)
[thirdparty/cups.git] / systemv / lpadmin.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
7e86f2f6 4 * "lpadmin" command for CUPS.
ef416fc2 5 *
fffed089 6 * Copyright 2007-2015 by Apple Inc.
7e86f2f6 7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
7e86f2f6
MS
9 * These coded instructions, statements, and computer programs are the
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
16/*
17 * Include necessary headers...
18 */
19
fffed089
MS
20#define _CUPS_NO_DEPRECATED
21#define _PPD_DEPRECATED
71e16022 22#include <cups/cups-private.h>
ef416fc2 23
24
25/*
26 * Local functions...
27 */
28
eac3a0a0
MS
29static int add_printer_to_class(http_t *http, char *printer, char *pclass);
30static int default_printer(http_t *http, char *printer);
31static int delete_printer(http_t *http, char *printer);
32static int delete_printer_from_class(http_t *http, char *printer,
33 char *pclass);
34static int delete_printer_option(http_t *http, char *printer,
35 char *option);
36static int enable_printer(http_t *http, char *printer);
fffed089 37static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize);
eac3a0a0
MS
38static cups_ptype_t get_printer_type(http_t *http, char *printer, char *uri,
39 size_t urisize);
40static int set_printer_options(http_t *http, char *printer,
41 int num_options, cups_option_t *options,
42 char *file);
43static int validate_name(const char *name);
ef416fc2 44
45
46/*
47 * 'main()' - Parse options and configure the scheduler.
48 */
49
50int
51main(int argc, /* I - Number of command-line arguments */
52 char *argv[]) /* I - Command-line arguments */
53{
54 int i; /* Looping var */
55 http_t *http; /* Connection to server */
56 char *printer, /* Destination printer */
57 *pclass, /* Printer class name */
58 *val; /* Pointer to allow/deny value */
59 int num_options; /* Number of options */
60 cups_option_t *options; /* Options */
fffed089
MS
61 char *file, /* New PPD file/interface script */
62 evefile[1024] = "";
63 /* IPP Everywhere PPD */
64 const char *ppd_name, /* ppd-name value */
65 *device_uri; /* device-uri value */
ef416fc2 66
67
07725fee 68 _cupsSetLocale(argv);
d09495fa 69
ef416fc2 70 http = NULL;
71 printer = NULL;
72 num_options = 0;
73 options = NULL;
7cf5915e 74 file = NULL;
ef416fc2 75
76 for (i = 1; i < argc; i ++)
77 if (argv[i][0] == '-')
78 switch (argv[i][1])
79 {
80 case 'c' : /* Add printer to class */
81 if (!http)
82 {
fffed089 83 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 84
85 if (http == NULL)
86 {
fa73b229 87 _cupsLangPrintf(stderr,
0837b7e8 88 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 89 strerror(errno));
90 return (1);
91 }
92 }
93
94 if (printer == NULL)
95 {
fa73b229 96 _cupsLangPuts(stderr,
ef416fc2 97 _("lpadmin: Unable to add a printer to the class:\n"
98 " You must specify a printer name "
0837b7e8 99 "first."));
ef416fc2 100 return (1);
101 }
102
103 if (argv[i][2])
104 pclass = argv[i] + 2;
105 else
106 {
107 i ++;
108
109 if (i >= argc)
110 {
fa73b229 111 _cupsLangPuts(stderr,
0837b7e8
MS
112 _("lpadmin: Expected class name after \"-c\" "
113 "option."));
ef416fc2 114 return (1);
115 }
116
117 pclass = argv[i];
118 }
119
120 if (!validate_name(pclass))
121 {
fa73b229 122 _cupsLangPuts(stderr,
ef416fc2 123 _("lpadmin: Class name can only contain printable "
0837b7e8 124 "characters."));
ef416fc2 125 return (1);
126 }
127
128 if (add_printer_to_class(http, printer, pclass))
129 return (1);
130 break;
131
132 case 'd' : /* Set as default destination */
133 if (!http)
134 {
fffed089 135 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 136
137 if (http == NULL)
138 {
fa73b229 139 _cupsLangPrintf(stderr,
0837b7e8 140 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 141 strerror(errno));
142 return (1);
143 }
144 }
145
146 if (argv[i][2])
147 printer = argv[i] + 2;
148 else
149 {
150 i ++;
151
152 if (i >= argc)
153 {
fa73b229 154 _cupsLangPuts(stderr,
0837b7e8
MS
155 _("lpadmin: Expected printer name after \"-d\" "
156 "option."));
ef416fc2 157 return (1);
158 }
159
160 printer = argv[i];
161 }
162
163 if (!validate_name(printer))
164 {
fa73b229 165 _cupsLangPuts(stderr,
ef416fc2 166 _("lpadmin: Printer name can only contain "
0837b7e8 167 "printable characters."));
ef416fc2 168 return (1);
169 }
170
171 if (default_printer(http, printer))
172 return (1);
173
174 i = argc;
175 break;
176
177 case 'h' : /* Connect to host */
178 if (http)
179 {
180 httpClose(http);
181 http = NULL;
182 }
183
184 if (argv[i][2] != '\0')
185 cupsSetServer(argv[i] + 2);
186 else
187 {
188 i ++;
189
190 if (i >= argc)
191 {
fa73b229 192 _cupsLangPuts(stderr,
0837b7e8
MS
193 _("lpadmin: Expected hostname after \"-h\" "
194 "option."));
ef416fc2 195 return (1);
196 }
197
198 cupsSetServer(argv[i]);
199 }
200 break;
201
202 case 'i' : /* Use the specified interface script */
ef416fc2 203 if (argv[i][2])
7cf5915e 204 file = argv[i] + 2;
ef416fc2 205 else
206 {
207 i ++;
208
209 if (i >= argc)
210 {
fa73b229 211 _cupsLangPuts(stderr,
0837b7e8
MS
212 _("lpadmin: Expected interface after \"-i\" "
213 "option."));
ef416fc2 214 return (1);
215 }
216
7cf5915e 217 file = argv[i];
ef416fc2 218 }
219 break;
220
221 case 'E' : /* Enable the printer */
222 if (printer == NULL)
223 {
224#ifdef HAVE_SSL
fffed089 225 cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED);
ef416fc2 226
227 if (http)
fffed089 228 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
ef416fc2 229#else
0837b7e8 230 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
ef416fc2 231 argv[0]);
232#endif /* HAVE_SSL */
233 break;
234 }
235
236 if (!http)
237 {
fffed089 238 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 239
240 if (http == NULL)
241 {
fa73b229 242 _cupsLangPrintf(stderr,
0837b7e8 243 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 244 strerror(errno));
245 return (1);
246 }
247 }
248
249 if (enable_printer(http, printer))
250 return (1);
251 break;
252
253 case 'm' : /* Use the specified standard script/PPD file */
ef416fc2 254 if (argv[i][2])
7cf5915e
MS
255 num_options = cupsAddOption("ppd-name", argv[i] + 2, num_options,
256 &options);
ef416fc2 257 else
258 {
259 i ++;
260
261 if (i >= argc)
262 {
fa73b229 263 _cupsLangPuts(stderr,
0837b7e8
MS
264 _("lpadmin: Expected model after \"-m\" "
265 "option."));
ef416fc2 266 return (1);
267 }
268
7cf5915e
MS
269 num_options = cupsAddOption("ppd-name", argv[i], num_options,
270 &options);
ef416fc2 271 }
272 break;
273
274 case 'o' : /* Set option */
275 if (argv[i][2])
276 num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
277 else
278 {
279 i ++;
280
281 if (i >= argc)
282 {
fa73b229 283 _cupsLangPuts(stderr,
0837b7e8
MS
284 _("lpadmin: Expected name=value after \"-o\" "
285 "option."));
ef416fc2 286 return (1);
287 }
288
289 num_options = cupsParseOptions(argv[i], num_options, &options);
290 }
291 break;
292
293 case 'p' : /* Add/modify a printer */
ef416fc2 294 if (argv[i][2])
295 printer = argv[i] + 2;
296 else
297 {
298 i ++;
299
300 if (i >= argc)
301 {
fa73b229 302 _cupsLangPuts(stderr,
0837b7e8
MS
303 _("lpadmin: Expected printer after \"-p\" "
304 "option."));
ef416fc2 305 return (1);
306 }
307
308 printer = argv[i];
309 }
310
311 if (!validate_name(printer))
312 {
fa73b229 313 _cupsLangPuts(stderr,
ef416fc2 314 _("lpadmin: Printer name can only contain "
0837b7e8 315 "printable characters."));
ef416fc2 316 return (1);
317 }
318 break;
319
320 case 'r' : /* Remove printer from class */
321 if (!http)
322 {
fffed089 323 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 324
325 if (http == NULL)
326 {
fa73b229 327 _cupsLangPrintf(stderr,
0837b7e8 328 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 329 strerror(errno));
330 return (1);
331 }
332 }
333
334 if (printer == NULL)
335 {
fa73b229 336 _cupsLangPuts(stderr,
ef416fc2 337 _("lpadmin: Unable to remove a printer from the "
338 "class:\n"
339 " You must specify a printer name "
0837b7e8 340 "first."));
ef416fc2 341 return (1);
342 }
343
344 if (argv[i][2])
345 pclass = argv[i] + 2;
346 else
347 {
348 i ++;
349
350 if (i >= argc)
351 {
fa73b229 352 _cupsLangPuts(stderr,
0837b7e8
MS
353 _("lpadmin: Expected class after \"-r\" "
354 "option."));
ef416fc2 355 return (1);
356 }
357
358 pclass = argv[i];
359 }
360
361 if (!validate_name(pclass))
362 {
fa73b229 363 _cupsLangPuts(stderr,
ef416fc2 364 _("lpadmin: Class name can only contain printable "
0837b7e8 365 "characters."));
ef416fc2 366 return (1);
367 }
368
369 if (delete_printer_from_class(http, printer, pclass))
370 return (1);
371 break;
372
eac3a0a0
MS
373 case 'R' : /* Remove option */
374 if (!http)
375 {
fffed089 376 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
eac3a0a0
MS
377
378 if (http == NULL)
379 {
380 _cupsLangPrintf(stderr,
381 _("lpadmin: Unable to connect to server: %s"),
382 strerror(errno));
383 return (1);
384 }
385 }
386
387 if (printer == NULL)
388 {
389 _cupsLangPuts(stderr,
390 _("lpadmin: Unable to delete option:\n"
391 " You must specify a printer name "
392 "first."));
393 return (1);
394 }
395
396 if (argv[i][2])
397 val = argv[i] + 2;
398 else
399 {
400 i ++;
401
402 if (i >= argc)
403 {
404 _cupsLangPuts(stderr,
405 _("lpadmin: Expected name after \"-R\" "
406 "option."));
407 return (1);
408 }
409
410 val = argv[i];
411 }
412
413 if (delete_printer_option(http, printer, val))
414 return (1);
415 break;
416
f301802f 417 case 'U' : /* Username */
418 if (argv[i][2] != '\0')
419 cupsSetUser(argv[i] + 2);
420 else
421 {
422 i ++;
423 if (i >= argc)
424 {
425 _cupsLangPrintf(stderr,
426 _("%s: Error - expected username after "
0837b7e8 427 "\"-U\" option."), argv[0]);
f301802f 428 return (1);
429 }
430
431 cupsSetUser(argv[i]);
432 }
433 break;
88f9aafc 434
ef416fc2 435 case 'u' : /* Allow/deny users */
436 if (argv[i][2])
437 val = argv[i] + 2;
438 else
439 {
440 i ++;
441
442 if (i >= argc)
443 {
fa73b229 444 _cupsLangPuts(stderr,
ef416fc2 445 _("lpadmin: Expected allow/deny:userlist after "
0837b7e8 446 "\"-u\" option."));
ef416fc2 447 return (1);
448 }
449
450 val = argv[i];
451 }
452
88f9aafc 453 if (!_cups_strncasecmp(val, "allow:", 6))
ef416fc2 454 num_options = cupsAddOption("requesting-user-name-allowed",
455 val + 6, num_options, &options);
88f9aafc 456 else if (!_cups_strncasecmp(val, "deny:", 5))
ef416fc2 457 num_options = cupsAddOption("requesting-user-name-denied",
458 val + 5, num_options, &options);
459 else
460 {
fa73b229 461 _cupsLangPrintf(stderr,
0837b7e8 462 _("lpadmin: Unknown allow/deny option \"%s\"."),
ef416fc2 463 val);
464 return (1);
465 }
466 break;
467
468 case 'v' : /* Set the device-uri attribute */
ef416fc2 469 if (argv[i][2])
7cf5915e
MS
470 num_options = cupsAddOption("device-uri", argv[i] + 2,
471 num_options, &options);
ef416fc2 472 else
473 {
474 i ++;
475
476 if (i >= argc)
477 {
fa73b229 478 _cupsLangPuts(stderr,
0837b7e8
MS
479 _("lpadmin: Expected device URI after \"-v\" "
480 "option."));
ef416fc2 481 return (1);
482 }
483
7cf5915e
MS
484 num_options = cupsAddOption("device-uri", argv[i],
485 num_options, &options);
ef416fc2 486 }
487 break;
488
489 case 'x' : /* Delete a printer */
490 if (!http)
491 {
fffed089 492 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 493
494 if (http == NULL)
495 {
fa73b229 496 _cupsLangPrintf(stderr,
0837b7e8 497 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 498 strerror(errno));
499 return (1);
500 }
501 }
502
503 if (argv[i][2])
504 printer = argv[i] + 2;
505 else
506 {
507 i ++;
508
509 if (i >= argc)
510 {
fa73b229 511 _cupsLangPuts(stderr,
ef416fc2 512 _("lpadmin: Expected printer or class after "
0837b7e8 513 "\"-x\" option."));
ef416fc2 514 return (1);
515 }
516
517 printer = argv[i];
518 }
519
520 if (!validate_name(printer))
521 {
fa73b229 522 _cupsLangPuts(stderr,
ef416fc2 523 _("lpadmin: Printer name can only contain "
0837b7e8 524 "printable characters."));
ef416fc2 525 return (1);
526 }
527
528 if (delete_printer(http, printer))
529 return (1);
530
531 i = argc;
532 break;
533
534 case 'D' : /* Set the printer-info attribute */
ef416fc2 535 if (argv[i][2])
7cf5915e
MS
536 num_options = cupsAddOption("printer-info", argv[i] + 2,
537 num_options, &options);
ef416fc2 538 else
539 {
540 i ++;
541
542 if (i >= argc)
543 {
fa73b229 544 _cupsLangPuts(stderr,
ef416fc2 545 _("lpadmin: Expected description after "
0837b7e8 546 "\"-D\" option."));
ef416fc2 547 return (1);
548 }
549
7cf5915e
MS
550 num_options = cupsAddOption("printer-info", argv[i],
551 num_options, &options);
ef416fc2 552 }
553 break;
554
555 case 'I' : /* Set the supported file types (ignored) */
556 i ++;
557
558 if (i >= argc)
559 {
fa73b229 560 _cupsLangPuts(stderr,
0837b7e8
MS
561 _("lpadmin: Expected file type(s) after \"-I\" "
562 "option."));
ef416fc2 563 return (1);
564 }
565
fa73b229 566 _cupsLangPuts(stderr,
0837b7e8 567 _("lpadmin: Warning - content type list ignored."));
ef416fc2 568 break;
88f9aafc 569
ef416fc2 570 case 'L' : /* Set the printer-location attribute */
ef416fc2 571 if (argv[i][2])
7cf5915e
MS
572 num_options = cupsAddOption("printer-location", argv[i] + 2,
573 num_options, &options);
ef416fc2 574 else
575 {
576 i ++;
577
578 if (i >= argc)
579 {
fa73b229 580 _cupsLangPuts(stderr,
0837b7e8
MS
581 _("lpadmin: Expected location after \"-L\" "
582 "option."));
ef416fc2 583 return (1);
584 }
585
7cf5915e
MS
586 num_options = cupsAddOption("printer-location", argv[i],
587 num_options, &options);
ef416fc2 588 }
589 break;
590
591 case 'P' : /* Use the specified PPD file */
ef416fc2 592 if (argv[i][2])
7cf5915e 593 file = argv[i] + 2;
ef416fc2 594 else
595 {
596 i ++;
597
598 if (i >= argc)
599 {
fa73b229 600 _cupsLangPuts(stderr,
0837b7e8 601 _("lpadmin: Expected PPD after \"-P\" option."));
ef416fc2 602 return (1);
603 }
604
7cf5915e 605 file = argv[i];
ef416fc2 606 }
607 break;
608
609 default :
fa73b229 610 _cupsLangPrintf(stderr,
0837b7e8 611 _("lpadmin: Unknown option \"%c\"."), argv[i][1]);
ef416fc2 612 return (1);
613 }
614 else
615 {
0837b7e8 616 _cupsLangPrintf(stderr, _("lpadmin: Unknown argument \"%s\"."),
ef416fc2 617 argv[i]);
618 return (1);
619 }
620
621 /*
622 * Set options as needed...
623 */
624
fffed089
MS
625 if ((ppd_name = cupsGetOption("ppd-name", num_options, options)) != NULL && !strcmp(ppd_name, "everywhere") && (device_uri = cupsGetOption("device-uri", num_options, options)) != NULL)
626 {
627 if ((file = get_printer_ppd(device_uri, evefile, sizeof(evefile))) == NULL)
628 return (1);
629
630 num_options = cupsRemoveOption("ppd-name", num_options, &options);
631 }
632
7cf5915e 633 if (num_options || file)
ef416fc2 634 {
635 if (!http)
636 {
fffed089 637 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 638
639 if (http == NULL)
640 {
fa73b229 641 _cupsLangPrintf(stderr,
0837b7e8 642 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 643 strerror(errno));
644 return (1);
645 }
646 }
647
648 if (printer == NULL)
649 {
fa73b229 650 _cupsLangPuts(stderr,
ef416fc2 651 _("lpadmin: Unable to set the printer options:\n"
0837b7e8 652 " You must specify a printer name first."));
ef416fc2 653 return (1);
654 }
655
7cf5915e 656 if (set_printer_options(http, printer, num_options, options, file))
ef416fc2 657 return (1);
658 }
659
fffed089
MS
660 if (evefile[0])
661 unlink(evefile);
662
ef416fc2 663 if (printer == NULL)
664 {
fa73b229 665 _cupsLangPuts(stdout,
ef416fc2 666 _("Usage:\n"
667 "\n"
668 " lpadmin [-h server] -d destination\n"
669 " lpadmin [-h server] -x destination\n"
670 " lpadmin [-h server] -p printer [-c add-class] "
671 "[-i interface] [-m model]\n"
672 " [-r remove-class] [-v device] "
673 "[-D description]\n"
674 " [-P ppd-file] [-o name=value]\n"
675 " [-u allow:user,user] "
0837b7e8 676 "[-u deny:user,user]"));
ef416fc2 677 }
678
679 if (http)
680 httpClose(http);
681
682 return (0);
683}
684
685
686/*
687 * 'add_printer_to_class()' - Add a printer to a class.
688 */
689
690static int /* O - 0 on success, 1 on fail */
691add_printer_to_class(http_t *http, /* I - Server connection */
692 char *printer, /* I - Printer to add */
693 char *pclass) /* I - Class to add to */
694{
695 int i; /* Looping var */
696 ipp_t *request, /* IPP Request */
697 *response; /* IPP Response */
698 ipp_attribute_t *attr, /* Current attribute */
699 *members; /* Members in class */
ef416fc2 700 char uri[HTTP_MAX_URI]; /* URI for printer/class */
701
702
703 DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
704 printer, pclass));
705
706 /*
fffed089 707 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
ef416fc2 708 * attributes:
709 *
710 * attributes-charset
711 * attributes-natural-language
712 * printer-uri
eac3a0a0 713 * requesting-user-name
ef416fc2 714 */
715
fffed089 716 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
fa73b229 717
a4d04587 718 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
719 "localhost", 0, "/classes/%s", pclass);
ef416fc2 720 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
721 "printer-uri", NULL, uri);
eac3a0a0
MS
722 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
723 NULL, cupsUser());
ef416fc2 724
725 /*
726 * Do the request and get back a response...
727 */
728
729 response = cupsDoRequest(http, request, "/");
730
731 /*
fffed089 732 * Build a CUPS-Add-Modify-Class request, which requires the following
ef416fc2 733 * attributes:
734 *
735 * attributes-charset
736 * attributes-natural-language
737 * printer-uri
eac3a0a0 738 * requesting-user-name
ef416fc2 739 * member-uris
740 */
741
fffed089 742 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 743
744 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
745 "printer-uri", NULL, uri);
eac3a0a0
MS
746 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
747 NULL, cupsUser());
ef416fc2 748
749 /*
750 * See if the printer is already in the class...
751 */
752
753 if (response != NULL &&
eac3a0a0
MS
754 (members = ippFindAttribute(response, "member-names",
755 IPP_TAG_NAME)) != NULL)
ef416fc2 756 for (i = 0; i < members->num_values; i ++)
88f9aafc 757 if (_cups_strcasecmp(printer, members->values[i].string.text) == 0)
ef416fc2 758 {
fa73b229 759 _cupsLangPrintf(stderr,
0837b7e8
MS
760 _("lpadmin: Printer %s is already a member of class "
761 "%s."), printer, pclass);
ef416fc2 762 ippDelete(request);
763 ippDelete(response);
764 return (0);
765 }
766
767 /*
768 * OK, the printer isn't part of the class, so add it...
769 */
770
a4d04587 771 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
772 "localhost", 0, "/printers/%s", printer);
ef416fc2 773
774 if (response != NULL &&
eac3a0a0
MS
775 (members = ippFindAttribute(response, "member-uris",
776 IPP_TAG_URI)) != NULL)
ef416fc2 777 {
778 /*
779 * Add the printer to the existing list...
780 */
781
782 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
783 "member-uris", members->num_values + 1, NULL, NULL);
784 for (i = 0; i < members->num_values; i ++)
eac3a0a0
MS
785 attr->values[i].string.text =
786 _cupsStrAlloc(members->values[i].string.text);
ef416fc2 787
1f0275e3 788 attr->values[i].string.text = _cupsStrAlloc(uri);
ef416fc2 789 }
790 else
1f0275e3
MS
791 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL,
792 uri);
ef416fc2 793
794 /*
795 * Then send the request...
796 */
797
798 ippDelete(response);
799
eac3a0a0 800 ippDelete(cupsDoRequest(http, request, "/admin/"));
fffed089 801 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 802 {
eac3a0a0 803 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 804
805 return (1);
806 }
807 else
ef416fc2 808 return (0);
ef416fc2 809}
810
811
812/*
813 * 'default_printer()' - Set the default printing destination.
814 */
815
816static int /* O - 0 on success, 1 on fail */
817default_printer(http_t *http, /* I - Server connection */
818 char *printer) /* I - Printer name */
819{
eac3a0a0 820 ipp_t *request; /* IPP Request */
ef416fc2 821 char uri[HTTP_MAX_URI]; /* URI for printer/class */
822
823
824 DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
825
826 /*
fffed089 827 * Build a CUPS-Set-Default request, which requires the following
ef416fc2 828 * attributes:
829 *
830 * attributes-charset
831 * attributes-natural-language
832 * printer-uri
eac3a0a0 833 * requesting-user-name
ef416fc2 834 */
835
a4d04587 836 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
837 "localhost", 0, "/printers/%s", printer);
ef416fc2 838
fffed089 839 request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
ef416fc2 840
841 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
842 "printer-uri", NULL, uri);
eac3a0a0
MS
843 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
844 NULL, cupsUser());
ef416fc2 845
846 /*
847 * Do the request and get back a response...
848 */
849
eac3a0a0 850 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 851
fffed089 852 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 853 {
eac3a0a0 854 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 855
856 return (1);
857 }
858 else
ef416fc2 859 return (0);
ef416fc2 860}
861
862
863/*
864 * 'delete_printer()' - Delete a printer from the system...
865 */
866
867static int /* O - 0 on success, 1 on fail */
868delete_printer(http_t *http, /* I - Server connection */
869 char *printer) /* I - Printer to delete */
870{
eac3a0a0 871 ipp_t *request; /* IPP Request */
ef416fc2 872 char uri[HTTP_MAX_URI]; /* URI for printer/class */
873
874
875 DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
876
877 /*
fffed089 878 * Build a CUPS-Delete-Printer request, which requires the following
ef416fc2 879 * attributes:
880 *
881 * attributes-charset
882 * attributes-natural-language
883 * printer-uri
eac3a0a0 884 * requesting-user-name
ef416fc2 885 */
886
fffed089 887 request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
fa73b229 888
a4d04587 889 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
890 "localhost", 0, "/printers/%s", printer);
ef416fc2 891 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
892 "printer-uri", NULL, uri);
eac3a0a0
MS
893 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
894 NULL, cupsUser());
ef416fc2 895
896 /*
897 * Do the request and get back a response...
898 */
899
eac3a0a0 900 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 901
fffed089 902 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 903 {
eac3a0a0 904 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 905
906 return (1);
907 }
908 else
ef416fc2 909 return (0);
ef416fc2 910}
911
912
913/*
914 * 'delete_printer_from_class()' - Delete a printer from a class.
915 */
916
917static int /* O - 0 on success, 1 on fail */
fa73b229 918delete_printer_from_class(
919 http_t *http, /* I - Server connection */
920 char *printer, /* I - Printer to remove */
921 char *pclass) /* I - Class to remove from */
ef416fc2 922{
923 int i, j, k; /* Looping vars */
924 ipp_t *request, /* IPP Request */
925 *response; /* IPP Response */
926 ipp_attribute_t *attr, /* Current attribute */
927 *members; /* Members in class */
ef416fc2 928 char uri[HTTP_MAX_URI]; /* URI for printer/class */
929
930
931 DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
932 printer, pclass));
933
934 /*
fffed089 935 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
ef416fc2 936 * attributes:
937 *
938 * attributes-charset
939 * attributes-natural-language
940 * printer-uri
eac3a0a0 941 * requesting-user-name
ef416fc2 942 */
943
fffed089 944 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
fa73b229 945
a4d04587 946 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
947 "localhost", 0, "/classes/%s", pclass);
ef416fc2 948 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
949 "printer-uri", NULL, uri);
eac3a0a0
MS
950 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
951 NULL, cupsUser());
ef416fc2 952
953 /*
954 * Do the request and get back a response...
955 */
956
957 if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
fffed089 958 response->request.status.status_code == IPP_STATUS_ERROR_NOT_FOUND)
ef416fc2 959 {
eac3a0a0 960 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
fa73b229 961
ef416fc2 962 ippDelete(response);
fa73b229 963
ef416fc2 964 return (1);
965 }
966
967 /*
968 * See if the printer is already in the class...
969 */
970
971 if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
972 {
0837b7e8 973 _cupsLangPuts(stderr, _("lpadmin: No member names were seen."));
fa73b229 974
ef416fc2 975 ippDelete(response);
fa73b229 976
ef416fc2 977 return (1);
978 }
979
980 for (i = 0; i < members->num_values; i ++)
88f9aafc 981 if (!_cups_strcasecmp(printer, members->values[i].string.text))
ef416fc2 982 break;
983
984 if (i >= members->num_values)
985 {
fa73b229 986 _cupsLangPrintf(stderr,
0837b7e8 987 _("lpadmin: Printer %s is not a member of class %s."),
fa73b229 988 printer, pclass);
989
ef416fc2 990 ippDelete(response);
fa73b229 991
ef416fc2 992 return (1);
993 }
994
995 if (members->num_values == 1)
996 {
997 /*
fffed089 998 * Build a CUPS-Delete-Class request, which requires the following
ef416fc2 999 * attributes:
1000 *
1001 * attributes-charset
1002 * attributes-natural-language
1003 * printer-uri
eac3a0a0 1004 * requesting-user-name
ef416fc2 1005 */
1006
fffed089 1007 request = ippNewRequest(IPP_OP_CUPS_DELETE_CLASS);
ef416fc2 1008
1009 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1010 "printer-uri", NULL, uri);
eac3a0a0
MS
1011 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1012 "requesting-user-name", NULL, cupsUser());
ef416fc2 1013 }
1014 else
1015 {
1016 /*
fffed089 1017 * Build a IPP_OP_CUPS_ADD_MODIFY_CLASS request, which requires the following
ef416fc2 1018 * attributes:
1019 *
1020 * attributes-charset
1021 * attributes-natural-language
1022 * printer-uri
eac3a0a0 1023 * requesting-user-name
ef416fc2 1024 * member-uris
1025 */
1026
fffed089 1027 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 1028
1029 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1030 "printer-uri", NULL, uri);
eac3a0a0
MS
1031 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1032 "requesting-user-name", NULL, cupsUser());
ef416fc2 1033
1034 /*
1035 * Delete the printer from the class...
1036 */
1037
1038 members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
1039 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
1040 "member-uris", members->num_values - 1, NULL, NULL);
1041
1042 for (j = 0, k = 0; j < members->num_values; j ++)
1043 if (j != i)
1f0275e3
MS
1044 attr->values[k ++].string.text =
1045 _cupsStrAlloc(members->values[j].string.text);
ef416fc2 1046 }
1047
1048 /*
1049 * Then send the request...
1050 */
1051
1052 ippDelete(response);
1053
eac3a0a0
MS
1054 ippDelete(cupsDoRequest(http, request, "/admin/"));
1055
fffed089 1056 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1057 {
eac3a0a0 1058 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
fa73b229 1059
ef416fc2 1060 return (1);
1061 }
eac3a0a0
MS
1062 else
1063 return (0);
1064}
ef416fc2 1065
ef416fc2 1066
eac3a0a0
MS
1067/*
1068 * 'delete_printer_option()' - Delete a printer option.
1069 */
1070
1071static int /* O - 0 on success, 1 on fail */
1072delete_printer_option(http_t *http, /* I - Server connection */
1073 char *printer, /* I - Printer */
1074 char *option) /* I - Option to delete */
1075{
1076 ipp_t *request; /* IPP request */
1077 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1078
1079
1080 /*
fffed089 1081 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
eac3a0a0
MS
1082 * requires the following attributes:
1083 *
1084 * attributes-charset
1085 * attributes-natural-language
1086 * printer-uri
1087 * requesting-user-name
1088 * option with deleteAttr tag
1089 */
1090
a2326b5b 1091 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1092 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 1093 else
fffed089 1094 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
eac3a0a0
MS
1095
1096 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1097 "printer-uri", NULL, uri);
1098 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1099 "requesting-user-name", NULL, cupsUser());
1100 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0);
1101
1102 /*
1103 * Do the request and get back a response...
1104 */
1105
1106 ippDelete(cupsDoRequest(http, request, "/admin/"));
1107
fffed089 1108 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1109 {
eac3a0a0 1110 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1111
eac3a0a0 1112 return (1);
ef416fc2 1113 }
eac3a0a0
MS
1114 else
1115 return (0);
ef416fc2 1116}
1117
1118
1119/*
1120 * 'enable_printer()' - Enable a printer...
1121 */
1122
1123static int /* O - 0 on success, 1 on fail */
1124enable_printer(http_t *http, /* I - Server connection */
1125 char *printer) /* I - Printer to enable */
1126{
eac3a0a0 1127 ipp_t *request; /* IPP Request */
ef416fc2 1128 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1129
1130
1131 DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
1132
1133 /*
fffed089 1134 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
eac3a0a0 1135 * require the following attributes:
ef416fc2 1136 *
1137 * attributes-charset
1138 * attributes-natural-language
1139 * printer-uri
eac3a0a0 1140 * requesting-user-name
ef416fc2 1141 * printer-state
1142 * printer-is-accepting-jobs
1143 */
1144
a2326b5b 1145 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1146 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
eac3a0a0 1147 else
fffed089 1148 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
fa73b229 1149
ef416fc2 1150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1151 "printer-uri", NULL, uri);
eac3a0a0
MS
1152 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1153 "requesting-user-name", NULL, cupsUser());
ef416fc2 1154 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
fffed089 1155 IPP_PSTATE_IDLE);
ef416fc2 1156 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1157
1158 /*
1159 * Do the request and get back a response...
1160 */
1161
eac3a0a0 1162 ippDelete(cupsDoRequest(http, request, "/admin/"));
fa73b229 1163
fffed089 1164 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1165 {
eac3a0a0 1166 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1167
1168 return (1);
1169 }
1170 else
eac3a0a0
MS
1171 return (0);
1172}
1173
1174
fffed089
MS
1175/*
1176 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
1177 */
1178
1179static char * /* O - Filename or NULL */
1180get_printer_ppd(const char *uri, /* I - Printer URI */
1181 char *buffer, /* I - Filename buffer */
1182 size_t bufsize) /* I - Size of filename buffer */
1183{
1184 http_t *http; /* Connection to printer */
1185 ipp_t *request, /* Get-Printer-Attributes request */
1186 *response; /* Get-Printer-Attributes response */
fb2d5470
MS
1187 char resolved[1024], /* Resolved URI */
1188 scheme[32], /* URI scheme */
fffed089
MS
1189 userpass[256], /* Username:password */
1190 host[256], /* Hostname */
1191 resource[256]; /* Resource path */
1192 int port; /* Port number */
1193
1194
1195 /*
1196 * Connect to the printer...
1197 */
1198
fb2d5470
MS
1199 if (strstr(uri, "._tcp"))
1200 {
1201 /*
1202 * Resolve URI...
1203 */
1204
1205 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
1206 {
1207 _cupsLangPrintf(stderr, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri);
1208 return (NULL);
1209 }
1210
1211 uri = resolved;
1212 }
1213
fffed089
MS
1214 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
1215 {
1216 _cupsLangPrintf(stderr, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri);
1217 return (NULL);
1218 }
1219
1220 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1221 if (!http)
1222 {
1223 _cupsLangPrintf(stderr, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host, port, cupsLastErrorString());
1224 return (NULL);
1225 }
1226
1227 /*
1228 * Send a Get-Printer-Attributes request...
1229 */
1230
1231 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1232 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1233 response = cupsDoRequest(http, request, resource);
1234
1235 if (!_ppdCreateFromIPP(buffer, bufsize, response))
1236 _cupsLangPrintf(stderr, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno));
1237
1238 ippDelete(response);
1239 httpClose(http);
1240
1241 if (buffer[0])
1242 return (buffer);
1243 else
1244 return (NULL);
1245}
1246
1247
eac3a0a0
MS
1248/*
1249 * 'get_printer_type()' - Determine the printer type and URI.
1250 */
1251
1252static cups_ptype_t /* O - printer-type value */
1253get_printer_type(http_t *http, /* I - Server connection */
1254 char *printer, /* I - Printer name */
1255 char *uri, /* I - URI buffer */
1256 size_t urisize) /* I - Size of URI buffer */
1257{
1258 ipp_t *request, /* IPP request */
1259 *response; /* IPP response */
1260 ipp_attribute_t *attr; /* printer-type attribute */
1261 cups_ptype_t type; /* printer-type value */
1262
1263
1264 /*
1265 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1266 * attributes:
1267 *
1268 * attributes-charset
1269 * attributes-natural-language
1270 * printer-uri
1271 * requested-attributes
1272 * requesting-user-name
1273 */
1274
7e86f2f6 1275 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
eac3a0a0 1276
fffed089 1277 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
eac3a0a0
MS
1278 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1279 "printer-uri", NULL, uri);
1280 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1281 "requested-attributes", NULL, "printer-type");
1282 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1283 "requesting-user-name", NULL, cupsUser());
1284
1285 /*
1286 * Do the request...
1287 */
1288
1289 response = cupsDoRequest(http, request, "/");
1290 if ((attr = ippFindAttribute(response, "printer-type",
1291 IPP_TAG_ENUM)) != NULL)
ef416fc2 1292 {
eac3a0a0 1293 type = (cups_ptype_t)attr->values[0].integer;
ef416fc2 1294
a2326b5b 1295 if (type & CUPS_PRINTER_CLASS)
7e86f2f6 1296 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer);
ef416fc2 1297 }
eac3a0a0
MS
1298 else
1299 type = CUPS_PRINTER_LOCAL;
1300
1301 ippDelete(response);
1302
1303 return (type);
ef416fc2 1304}
1305
1306
ef416fc2 1307/*
1308 * 'set_printer_options()' - Set the printer options.
1309 */
1310
1311static int /* O - 0 on success, 1 on fail */
fa73b229 1312set_printer_options(
1313 http_t *http, /* I - Server connection */
1314 char *printer, /* I - Printer */
1315 int num_options, /* I - Number of options */
7cf5915e
MS
1316 cups_option_t *options, /* I - Options */
1317 char *file) /* I - PPD file/interface script */
ef416fc2 1318{
eac3a0a0 1319 ipp_t *request; /* IPP Request */
b423cd4c 1320 const char *ppdfile; /* PPD filename */
61c9d9f8 1321 int ppdchanged = 0; /* PPD changed? */
b423cd4c 1322 ppd_file_t *ppd; /* PPD file */
1323 ppd_choice_t *choice; /* Marked choice */
ef416fc2 1324 char uri[HTTP_MAX_URI], /* URI for printer/class */
1325 line[1024], /* Line from PPD file */
1326 keyword[1024], /* Keyword from Default line */
1327 *keyptr, /* Pointer into keyword... */
1328 tempfile[1024]; /* Temporary filename */
7cf5915e 1329 cups_file_t *in, /* PPD file */
ef416fc2 1330 *out; /* Temporary file */
61c9d9f8
MS
1331 const char *ppdname, /* ppd-name value */
1332 *protocol, /* Old protocol option */
eac3a0a0
MS
1333 *customval, /* Custom option value */
1334 *boolval; /* Boolean value */
1335 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
61c9d9f8
MS
1336 wrote_snmp_supplies = 0,/* Wrote cupsSNMPSupplies keyword? */
1337 copied_options = 0; /* Copied options? */
ef416fc2 1338
1339
7cf5915e
MS
1340 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
1341 "options=%p, file=\"%s\")\n", http, printer, num_options,
1342 options, file));
ef416fc2 1343
ef416fc2 1344 /*
fffed089
MS
1345 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1346 * which requires the following attributes:
ef416fc2 1347 *
1348 * attributes-charset
1349 * attributes-natural-language
1350 * printer-uri
eac3a0a0 1351 * requesting-user-name
ef416fc2 1352 * other options
1353 */
1354
a2326b5b 1355 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1356 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
eac3a0a0 1357 else
fffed089 1358 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
ef416fc2 1359
fffed089
MS
1360 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1361 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
ef416fc2 1362
1363 /*
1364 * Add the options...
1365 */
1366
fffed089
MS
1367 if (file)
1368 ppdfile = file;
61c9d9f8
MS
1369 else if ((ppdname = cupsGetOption("ppd-name", num_options, options)) != NULL && strcmp(ppdname, "raw") && num_options > 1)
1370 {
1371 if ((ppdfile = cupsGetServerPPD(http, ppdname)) != NULL)
1372 {
1373 /*
1374 * Copy options array and remove ppd-name from it...
1375 */
1376
1377 cups_option_t *temp = NULL, *optr;
1378 int i, num_temp = 0;
1379 for (i = num_options, optr = options; i > 0; i --, optr ++)
1380 if (strcmp(optr->name, "ppd-name"))
1381 num_temp = cupsAddOption(optr->name, optr->value, num_temp, &temp);
1382
1383 copied_options = 1;
1384 ppdchanged = 1;
1385 num_options = num_temp;
1386 options = temp;
1387 }
1388 }
fffed089
MS
1389 else if (request->request.op.operation_id == IPP_OP_CUPS_ADD_MODIFY_PRINTER)
1390 ppdfile = cupsGetPPD(printer);
1391 else
1392 ppdfile = NULL;
1393
b0f26938 1394 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
b423cd4c 1395 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1396
1397 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1398 {
88f9aafc 1399 if (!_cups_strcasecmp(protocol, "bcp"))
a41f09e2 1400 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
b423cd4c 1401 NULL, "bcp");
88f9aafc 1402 else if (!_cups_strcasecmp(protocol, "tbcp"))
a41f09e2 1403 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
b423cd4c 1404 NULL, "tbcp");
1405 }
ef416fc2 1406
fffed089 1407 if (ppdfile)
ef416fc2 1408 {
1409 /*
1410 * Set default options in the PPD file...
1411 */
1412
61c9d9f8
MS
1413 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1414 {
1415 int linenum; /* Line number of error */
1416 ppd_status_t status = ppdLastError(&linenum);
1417 /* Status code */
1418
1419 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), linenum);
1420 }
1421
b423cd4c 1422 ppdMarkDefaults(ppd);
1423 cupsMarkOptions(ppd, num_options, options);
1424
0268488e 1425 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
ef416fc2 1426 {
0837b7e8 1427 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
ef416fc2 1428 ippDelete(request);
7cf5915e
MS
1429 if (ppdfile != file)
1430 unlink(ppdfile);
61c9d9f8
MS
1431 if (copied_options)
1432 cupsFreeOptions(num_options, options);
ef416fc2 1433 return (1);
1434 }
1435
7cf5915e 1436 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
ef416fc2 1437 {
fa73b229 1438 _cupsLangPrintf(stderr,
0837b7e8 1439 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
ef416fc2 1440 ppdfile, strerror(errno));
1441 ippDelete(request);
7cf5915e
MS
1442 if (ppdfile != file)
1443 unlink(ppdfile);
61c9d9f8
MS
1444 if (copied_options)
1445 cupsFreeOptions(num_options, options);
7cf5915e 1446 cupsFileClose(out);
ef416fc2 1447 unlink(tempfile);
1448 return (1);
1449 }
1450
7cf5915e 1451 while (cupsFileGets(in, line, sizeof(line)))
ef416fc2 1452 {
eac3a0a0
MS
1453 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1454 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1455 options)) != NULL)
1456 {
1457 wrote_ipp_supplies = 1;
1458 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
88f9aafc
MS
1459 (!_cups_strcasecmp(boolval, "true") ||
1460 !_cups_strcasecmp(boolval, "yes") ||
1461 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1462 }
1463 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1464 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1465 options)) != NULL)
1466 {
1467 wrote_snmp_supplies = 1;
1468 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
88f9aafc
MS
1469 (!_cups_strcasecmp(boolval, "true") ||
1470 !_cups_strcasecmp(boolval, "yes") ||
1471 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1472 }
1473 else if (strncmp(line, "*Default", 8))
7cf5915e 1474 cupsFilePrintf(out, "%s\n", line);
ef416fc2 1475 else
1476 {
1477 /*
1478 * Get default option name...
1479 */
1480
1481 strlcpy(keyword, line + 8, sizeof(keyword));
1482
1483 for (keyptr = keyword; *keyptr; keyptr ++)
1484 if (*keyptr == ':' || isspace(*keyptr & 255))
1485 break;
1486
b423cd4c 1487 *keyptr++ = '\0';
1488 while (isspace(*keyptr & 255))
1489 keyptr ++;
1490
1491 if (!strcmp(keyword, "PageRegion") ||
1492 !strcmp(keyword, "PageSize") ||
1493 !strcmp(keyword, "PaperDimension") ||
1494 !strcmp(keyword, "ImageableArea"))
1495 {
1496 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1497 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1498 }
ef416fc2 1499 else
b423cd4c 1500 choice = ppdFindMarkedChoice(ppd, keyword);
ef416fc2 1501
b423cd4c 1502 if (choice && strcmp(choice->choice, keyptr))
1503 {
7cf5915e
MS
1504 if (strcmp(choice->choice, "Custom"))
1505 {
1506 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1507 ppdchanged = 1;
1508 }
1509 else if ((customval = cupsGetOption(keyword, num_options,
1510 options)) != NULL)
1511 {
1512 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1513 ppdchanged = 1;
1514 }
1515 else
1516 cupsFilePrintf(out, "%s\n", line);
b423cd4c 1517 }
ef416fc2 1518 else
7cf5915e 1519 cupsFilePrintf(out, "%s\n", line);
ef416fc2 1520 }
1521 }
1522
eac3a0a0
MS
1523 if (!wrote_ipp_supplies &&
1524 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1525 options)) != NULL)
1526 {
1527 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
88f9aafc
MS
1528 (!_cups_strcasecmp(boolval, "true") ||
1529 !_cups_strcasecmp(boolval, "yes") ||
1530 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1531 }
1532
1533 if (!wrote_snmp_supplies &&
1534 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1535 options)) != NULL)
1536 {
1537 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
88f9aafc
MS
1538 (!_cups_strcasecmp(boolval, "true") ||
1539 !_cups_strcasecmp(boolval, "yes") ||
1540 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1541 }
1542
7cf5915e
MS
1543 cupsFileClose(in);
1544 cupsFileClose(out);
b423cd4c 1545 ppdClose(ppd);
ef416fc2 1546
1547 /*
1548 * Do the request...
1549 */
1550
b423cd4c 1551 ippDelete(cupsDoFileRequest(http, request, "/admin/",
7cf5915e 1552 ppdchanged ? tempfile : file));
ef416fc2 1553
1554 /*
1555 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1556 * lpadmin)
1557 */
1558
7cf5915e
MS
1559 if (ppdfile != file)
1560 unlink(ppdfile);
ef416fc2 1561 unlink(tempfile);
1562 }
1563 else
1564 {
1565 /*
1566 * No PPD file - just set the options...
1567 */
1568
b423cd4c 1569 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1570 }
1571
61c9d9f8
MS
1572 if (copied_options)
1573 cupsFreeOptions(num_options, options);
1574
ef416fc2 1575 /*
1576 * Check the response...
1577 */
1578
fffed089 1579 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1580 {
eac3a0a0 1581 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1582
1583 return (1);
1584 }
1585 else
ef416fc2 1586 return (0);
ef416fc2 1587}
1588
1589
1590/*
1591 * 'validate_name()' - Make sure the printer name only contains valid chars.
1592 */
1593
fa73b229 1594static int /* O - 0 if name is no good, 1 if name is good */
1595validate_name(const char *name) /* I - Name to check */
ef416fc2 1596{
fa73b229 1597 const char *ptr; /* Pointer into name */
ef416fc2 1598
1599
1600 /*
1601 * Scan the whole name...
1602 */
1603
1604 for (ptr = name; *ptr; ptr ++)
1605 if (*ptr == '@')
1606 break;
1607 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
1608 *ptr == '#')
1609 return (0);
1610
1611 /*
1612 * All the characters are good; validate the length, too...
1613 */
1614
1615 return ((ptr - name) < 128);
1616}
1617
1618
1619/*
f2d18633 1620 * End of "$Id$".
ef416fc2 1621 */