1 /*
2  *   PPD file generation program for the CUPS drivers.
3  *
4  *   Copyright 1993-2008 by Mike Sweet and Robert Krawitz.
5  *
6  *   This program is free software; you can redistribute it and/or modify it
7  *   under the terms of the GNU General Public License as published by the Free
8  *   Software Foundation; either version 2 of the License, or (at your option)
9  *   any later version.
10  *
11  *   This program is distributed in the hope that it will be useful, but
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  *   for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  *
19  * Contents:
20  *
21  *   main()              - Process files on the command-line...
22  *   cat_ppd()           - Copy the named PPD to stdout.
23  *   generate_ppd()      - Generate a PPD file.
24  *   getlangs()          - Get a list of available translations.
25  *   help()              - Show detailed help.
26  *   is_special_option() - Determine if an option should be grouped.
27  *   list_ppds()         - List the available drivers.
28  *   print_group_close() - Close a UI group.
29  *   print_group_open()  - Open a new UI group.
30  *   printlangs()        - Print list of available translations.
31  *   printmodels()       - Print a list of available models.
32  *   usage()             - Show program usage.
33  *   write_ppd()         - Write a PPD file.
34  */
35 
36 /*
37  * 'main()' - Process files on the command-line...
38  */
39 
40 #include "genppd.h"
41 
42 static int	cat_ppd(const char *uri);
43 static int	list_ppds(const char *argv0);
44 
45 
46 int				    /* O - Exit status */
main(int argc,char * argv[])47 main(int  argc,			    /* I - Number of command-line arguments */
48      char *argv[])		    /* I - Command-line arguments */
49 {
50  /*
51   * Force POSIX locale, since stp_init incorrectly calls setlocale...
52   */
53 
54   (void) setenv("LANG", "C", 1);
55   (void) setenv("LC_ALL", "C", 1);
56   (void) setenv("LC_NUMERIC", "C", 1);
57 
58  /*
59   * Initialise libgutenprint
60   */
61 
62   stp_init();
63 
64  /*
65   * Process command-line...
66   */
67 
68   if (argc == 2 && !strcmp(argv[1], "list"))
69     return (list_ppds(argv[0]));
70   else if (argc == 3 && !strcmp(argv[1], "cat"))
71     return (cat_ppd(argv[2]));
72   else if (argc == 2 && !strcmp(argv[1], "org.gutenprint.multicat"))
73     {
74       char buf[1024];
75       int status = 0;
76       while (fgets(buf, sizeof(buf) - 1, stdin))
77 	{
78 	  size_t len = strlen(buf);
79 	  if (len == 0)
80 	    continue;
81 	  if (buf[len - 1] == '\n')
82 	    buf[len - 1] = '\0';
83 	  status |= cat_ppd(buf);
84 	  fputs("*%*%EOFEOF\n", stdout);
85 	  (void) fflush(stdout);
86 	}
87     }
88   else if (argc == 2 && !strcmp(argv[1], "VERSION"))
89     {
90       printf("%s\n", VERSION);
91       return (0);
92     }
93   else if (argc == 2 && !strcasecmp(argv[1], "org.gutenprint.extensions"))
94     {
95       printf("org.gutenprint.multicat");
96       return (0);
97     }
98   else
99     {
100       fprintf(stderr, "Usage: %s list\n", argv[0]);
101       fprintf(stderr, "       %s cat URI\n", argv[0]);
102       return (1);
103     }
104   return (0);
105 }
106 
107 
108 /*
109  * 'cat_ppd()' - Copy the named PPD to stdout.
110  */
111 
112 static int				/* O - Exit status */
cat_ppd(const char * uri)113 cat_ppd(const char *uri)	/* I - Driver URI */
114 {
115   char			scheme[64],	/* URI scheme */
116 			userpass[32],	/* URI user/pass (unused) */
117 			hostname[32],	/* URI hostname */
118 			resource[1024];	/* URI resource */
119   int			port;		/* URI port (unused) */
120   http_uri_status_t	status;		/* URI decode status */
121   const stp_printer_t	*p;		/* Printer driver */
122   const char		*lang = NULL;
123   char			*s;
124   char			filename[1024],		/* Filename */
125 			ppd_location[2048];	/* Installed location */
126   const char 		*infix = "";
127   ppd_type_t 		ppd_type = PPD_STANDARD;
128   gpfile		outFD;
129 
130   if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri,
131                                 scheme, sizeof(scheme),
132                                 userpass, sizeof(userpass),
133 				hostname, sizeof(hostname),
134 		                &port, resource, sizeof(resource)))
135 				    < HTTP_URI_OK)
136   {
137     fprintf(stderr, "ERROR: Bad ppd-name \"%s\" (%d)!\n", uri, status);
138     return (1);
139   }
140 
141   if (strcmp(scheme, "gutenprint." GUTENPRINT_RELEASE_VERSION) != 0)
142     {
143       fprintf(stderr, "ERROR: Gutenprint version mismatch!\n");
144       return(1);
145     }
146 
147   s = strchr(resource + 1, '/');
148   if (s)
149     {
150       lang = s + 1;
151       *s = '\0';
152     }
153 
154   if ((p = stp_get_printer_by_driver(hostname)) == NULL)
155   {
156     fprintf(stderr, "ERROR: Unable to find driver \"%s\"!\n", hostname);
157     return (1);
158   }
159 
160   if (strcmp(resource + 1, "simple") == 0)
161     {
162       infix = ".sim";
163       ppd_type = PPD_SIMPLIFIED;
164     }
165   else if (strcmp(resource + 1, "nocolor") == 0)
166     {
167       infix = ".nc";
168       ppd_type = PPD_NO_COLOR_OPTS;
169     }
170 
171   /*
172    * This isn't really the right thing to do.  We really shouldn't
173    * be embedding filenames in automatically generated PPD files, but
174    * if the user ever decides to go back from generated PPD files to
175    * static PPD files we'll need to have this for genppdupdate to work.
176    */
177   snprintf(filename, sizeof(filename) - 1, "stp-%s.%s%s%s",
178 	   hostname, GUTENPRINT_RELEASE_VERSION, infix, ppdext);
179   snprintf(ppd_location, sizeof(ppd_location) - 1, "%s%s%s/ppd/%s%s",
180 	   cups_modeldir,
181 	   cups_modeldir[strlen(cups_modeldir) - 1] == '/' ? "" : "/",
182 	   lang ? lang : "C",
183 	   filename, gpext);
184 
185   outFD.f = stdout;
186   return (write_ppd(&outFD, p, lang, ppd_location, ppd_type, filename, 0));
187 }
188 
189 /*
190  * 'list_ppds()' - List the available drivers.
191  */
192 
193 static int				/* O - Exit status */
list_ppds(const char * argv0)194 list_ppds(const char *argv0)		/* I - Name of program */
195 {
196   const char		*scheme;	/* URI scheme */
197   int			i;		/* Looping var */
198   const stp_printer_t	*printer;	/* Pointer to printer driver */
199 
200   if ((scheme = strrchr(argv0, '/')) != NULL)
201     scheme ++;
202   else
203     scheme = argv0;
204 
205   for (i = 0; i < stp_printer_model_count(); i++)
206     if ((printer = stp_get_printer_by_index(i)) != NULL)
207     {
208       const char *device_id;
209       if (!strcmp(stp_printer_get_family(printer), "ps") ||
210 	  !strcmp(stp_printer_get_family(printer), "raw"))
211         continue;
212 
213       device_id = stp_printer_get_device_id(printer);
214       printf("\"%s://%s/expert\" "
215              "%s "
216 	     "\"%s\" "
217              "\"%s" CUPS_PPD_NICKNAME_STRING VERSION "\" "
218 	     "\"%s\"\n",
219              scheme, stp_printer_get_driver(printer),
220 	     "en",
221 	     stp_printer_get_manufacturer(printer),
222 	     stp_printer_get_long_name(printer),
223 	     device_id ? device_id : "");
224 
225 #ifdef GENERATE_SIMPLIFIED_PPDS
226       printf("\"%s://%s/simple\" "
227              "%s "
228 	     "\"%s\" "
229              "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " Simplified\" "
230 	     "\"%s\"\n",
231              scheme, stp_printer_get_driver(printer),
232 	     "en",
233 	     stp_printer_get_manufacturer(printer),
234 	     stp_printer_get_long_name(printer),
235 	     device_id ? device_id : "");
236 #endif
237 
238 #ifdef GENERATE_NOCOLOR_PPDS
239       printf("\"%s://%s/nocolor\" "
240              "%s "
241 	     "\"%s\" "
242              "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " No color options\" "
243 	     "\"%s\"\n",
244              scheme, stp_printer_get_driver(printer),
245 	     "en",
246 	     stp_printer_get_manufacturer(printer),
247 	     stp_printer_get_long_name(printer),
248 	     device_id ? device_id : "");
249 #endif
250     }
251 
252   return (0);
253 }
254