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