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