1 /*
2  * gprintersettings.cpp - Bridges GutenPrint's stp_vars_t and the configuration file.
3  * A subclass of ConfigSectionHandler.
4  *
5  * Copyright (c) 2004, 2008 by Alastair M. Robinson
6  * Distributed under the terms of the GNU General Public License -
7  * see the file named "COPYING" for more details.
8  *
9  * TODO: Add support for multi-line parameters (heredoc syntax?)
10  */
11 
12 #include <iostream>
13 
14 #include <string.h>
15 #include <glib.h>
16 #include <glib/gprintf.h>
17 
18 #include "stp_support/stputil.h"
19 #include "gprintersettings.h"
20 
21 #include "../support/debug.h"
22 #include "../support/util.h"
23 
24 #include "../miscwidgets/generaldialogs.h"
25 
26 #include "../config.h"
27 #include "../gettext.h"
28 
29 #define _(x) gettext(x)
30 #define N_(x) gettext_noop(x)
31 
32 
33 #define DEFAULT_PPD_STRING "<Default Queue PPD>"
34 
35 using namespace std;
36 
37 
dumpstrings(const stp_parameter_t * desc)38 static void dumpstrings(const stp_parameter_t *desc)
39 {
40 	int j,strcount;
41 	stp_string_list_t *strlist=desc->bounds.str;
42 	if(strlist)
43 	{
44 		strcount=stp_string_list_count(strlist);
45 		for(j=0;j<strcount;++j)
46 		{
47 			stp_param_string_t *p=stp_string_list_param(strlist,j);
48 			fprintf(stderr,"   %s (%s)\n",p->text,p->name);
49 		}
50 	}
51 	else
52 		fprintf(stderr,"  No string list!\n");
53 }
54 
55 
dumpvars(stp_vars_t * v)56 static void dumpvars(stp_vars_t *v)
57 {
58 	stp_parameter_list_t params = stp_get_parameter_list(v);
59 
60 	int count = stp_parameter_list_count(params);
61 
62 	for (int i = 0; i < count; i++)
63 	{
64 		const stp_parameter_t *p = stp_parameter_list_param(params, i);
65 //		if((p->p_level<=STP_PARAMETER_LEVEL_ADVANCED4)
66 //			&& ((p->p_class==STP_PARAMETER_CLASS_FEATURE) || (p->p_class==STP_PARAMETER_CLASS_OUTPUT)))
67 		{
68 			stp_parameter_t desc;
69 			stp_describe_parameter(v,p->name,&desc);
70 			const char *str;
71 			int ival;
72 			double fval;
73 
74 			fprintf(stderr,"%s, %d, %d, %d, %d ",desc.name,desc.p_type,p->p_type,desc.p_class,desc.p_level);
75 
76 			if(desc.is_active)
77 			{
78 				fprintf(stderr,", Active");
79 			}
80 			else
81 			{
82 				fprintf(stderr,", Inactive");
83 			}
84 				switch(desc.p_type)
85 				{
86 					case STP_PARAMETER_TYPE_STRING_LIST:
87 						str=stp_get_string_parameter(v,desc.name);
88 						fprintf(stderr,", StringList\n");
89 						dumpstrings(&desc);
90 						if(str)
91 							fprintf(stderr,"  Currently set to: %s\n",str);
92 						break;
93 
94 					case STP_PARAMETER_TYPE_INT:
95 						ival=stp_get_int_parameter(v,desc.name);
96 						fprintf(stderr,", Int\n");
97 						fprintf(stderr,"  Currently set to: %d\n",ival);
98 						break;
99 
100 					case STP_PARAMETER_TYPE_BOOLEAN:
101 						ival=stp_get_boolean_parameter(v,desc.name);
102 						fprintf(stderr,", Boolean\n");
103 						fprintf(stderr,"  Currently set to: %d\n",ival);
104 						break;
105 
106 					case STP_PARAMETER_TYPE_DOUBLE:
107 						fval=stp_get_float_parameter(v,desc.name);
108 						fprintf(stderr,", Double\n");
109 						fprintf(stderr,"  Currently set to: %f\n",fval);
110 						break;
111 
112 					default:
113 						fprintf(stderr,", Other\n");
114 						break;
115 			}
116 		}
117 	}
118 	stp_parameter_list_destroy(params);
119 }
120 
121 
Dump()122 void GPrinterSettings::Dump()
123 {
124 	dumpvars(stpvars);
125 }
126 
127 
GPrinterSettings(PrintOutput & output,ConfigFile * inf,const char * section)128 GPrinterSettings::GPrinterSettings(PrintOutput &output,ConfigFile *inf,const char *section)
129 	: ConfigSectionHandler(inf,section), PageExtent(), stpvars(NULL), output(output),
130 	initialised(false), ppdsizes_workaround_done(false)
131 {
132 	stpvars=stp_vars_create();
133 
134 	// Set the driver to that of the default queue in case no preset is loaded
135 	const char *driver=output.FindString("Driver");
136 	if(!SetDriver(driver))
137 		output.SetString("Driver",DEFAULT_PRINTER_DRIVER);
138 }
139 
140 
~GPrinterSettings()141 GPrinterSettings::~GPrinterSettings()
142 {
143 	if(stpvars)
144 		stp_vars_destroy(stpvars);
145 }
146 
147 
SelectSection()148 void GPrinterSettings::SelectSection()
149 {
150 	/* Slight hack here: The printer driver is stored in the [Output] section
151 	   which is prior to the [Print] section.  Clearing this forces the driver
152 	   to be set before the printer options are set */
153 
154 	initialised=false;
155 }
156 
157 
ParseString(const char * string)158 void GPrinterSettings::ParseString(const char *string)
159 {
160 	if(!initialised)
161 	{
162 		const char *driver=output.FindString("Driver");
163 		if(!SetDriver(driver))
164 			output.SetString("Driver",DEFAULT_PRINTER_DRIVER);
165 		initialised=true;
166 	}
167 
168 	while(*string==' ')
169 		++string;
170 
171 	char *value;
172 	char *token;
173 	value=token=strdup(string);
174 	int l=strlen(token)-1;
175 	while((l>0) && ((token[l]=='\n') || (token[l]=='\r')))
176 		--l;
177 	token[l+1]=0;
178 
179 	while(1)
180 	{
181 		switch (*value)
182 		{
183 			case '\0':
184 				free(token);
185 				return;
186 				break;
187 			case '=':
188 				*value='\0';
189 				++value;
190 				if(*value)
191 				{
192 					if(strcmp("CustomWidth",token)==0)
193 					{
194 						Debug[TRACE] << "Setting custom width to: " << value << endl;
195 						stp_set_page_width(stpvars,pagewidth=atoi(value));
196 					}
197 					else if(strcmp("CustomHeight",token)==0)
198 					{
199 						Debug[TRACE] << "Setting custom height to: " << value << endl;
200 						stp_set_page_height(stpvars,pageheight=atoi(value));
201 					}
202 					else
203 					{
204 						stp_parameter_t param;
205 						stp_describe_parameter(stpvars,token,&param);
206 						switch(param.p_type)
207 						{
208 							case STP_PARAMETER_TYPE_STRING_LIST:
209 								if(strcmp("PageSize",token)==0)
210 									Debug[TRACE] << "Setting PageSize to: " << value << endl;
211 								stp_set_string_parameter(stpvars,token,value);
212 								break;
213 
214 							case STP_PARAMETER_TYPE_FILE:
215 								// Because the queue PPD filenames returned by CUPS
216 								// aren't persistent between sessions, we have to
217 								// save an escape string, and substitute the current
218 								// filename at preset loading time.
219 								if(strcmp(value,DEFAULT_PPD_STRING)==0)
220 								{
221 									Debug[TRACE] << "*** Fetching default PPD filename" << endl;
222 									char *defppd=output.GetPPD();
223 									if(defppd)
224 									{
225 										Debug[TRACE] << "Got default PPD filename: " << defppd << endl;
226 										stp_set_file_parameter(stpvars,token,defppd);
227 										free(defppd);
228 
229 										stp_parameter_t desc2;
230 										stp_describe_parameter(stpvars,"PageSize",&desc2);
231 										Debug[TRACE] << "After setting PPD Default page size is now: " << desc2.deflt.str << endl;
232 										stp_set_string_parameter(stpvars,"PageSize",desc2.deflt.str);
233 										stp_parameter_description_destroy(&desc2);
234 										ppdsizes_workaround_done=true;
235 									}
236 									else
237 										Debug[TRACE] << "Couldn't get default PPD." << endl;
238 								}
239 								else
240 									stp_set_file_parameter(stpvars,token,value);
241 								break;
242 
243 							case STP_PARAMETER_TYPE_INT:
244 	//							Debug[TRACE] << "Setting " << token << " to " << value << endl;
245 								stp_set_int_parameter(stpvars,token,atoi(value));
246 								break;
247 
248 							case STP_PARAMETER_TYPE_BOOLEAN:
249 	//							Debug[TRACE] << "Setting " << token << " to " << value << endl;
250 								stp_set_boolean_parameter(stpvars,token,atoi(value));
251 								break;
252 
253 							case STP_PARAMETER_TYPE_DOUBLE:
254 	//							Debug[TRACE] << "Setting " << token << " to " << value << endl;
255 								stp_set_float_parameter(stpvars,token,atof(value));
256 								break;
257 
258 							default:
259 								break;
260 						}
261 						stp_parameter_description_destroy(&param);
262 					}
263 				}
264 				free(token);
265 				return;
266 				break;
267 		}
268 		++value;
269 	}
270 }
271 
272 
SaveSection(FILE * file)273 void GPrinterSettings::SaveSection(FILE *file)
274 {
275 	stp_parameter_list_t params = stp_get_parameter_list(stpvars);
276 	stp_parameter_t desc;
277 	desc.is_active=false;
278 
279 	int count = stp_parameter_list_count(params);
280 
281 	// PPDFile parameter must be saved first, because it must be restored
282 	// before other parameters upon loading.
283 	// Because CUPS returns a local temporary filename for a queue's PPD
284 	// which is not persistent between sessions, we must save an escape
285 	// string to indicate that the queue's default should be used.
286 
287 	stp_describe_parameter(stpvars,"PPDFile",&desc);
288 	if(desc.is_active)
289 	{
290 		Debug[TRACE] << "Saving PPDFile parameter..." << endl;
291 		const char *ppd=stp_get_file_parameter(stpvars,"PPDFile");
292 		char *defppd=output.GetPPD();
293 		if(ppd)
294 			Debug[TRACE] << "Current PPD: " << ppd << endl;
295 		if(defppd)
296 			Debug[TRACE] << "Default PPD: " << defppd << endl;
297 		if(defppd && ppd && CompareFiles(defppd,ppd))
298 			ppd=DEFAULT_PPD_STRING;
299 		if(!ppd)
300 			ppd=DEFAULT_PPD_STRING;
301 		if(defppd)
302 			free(defppd);
303 		fprintf(file,"PPDFile=%s\n",ppd);
304 	}
305 
306 	for (int i = 0; i < count; i++)
307 	{
308 		const stp_parameter_t *p = stp_parameter_list_param(params, i);
309 		if((p->p_level<=STP_PARAMETER_LEVEL_ADVANCED4))
310 		{
311 			stp_parameter_t desc;
312 			stp_describe_parameter(stpvars,p->name,&desc);
313 			if(desc.is_active)
314 			{
315 				switch(desc.p_type)
316 				{
317 					case STP_PARAMETER_TYPE_STRING_LIST:
318 						{
319 							if(stp_check_string_parameter(stpvars,desc.name,STP_PARAMETER_DEFAULTED))
320 							{
321 								const char *str=stp_get_string_parameter(stpvars,desc.name);
322 //								if(!desc.is_mandatory || strcmp(str,desc.deflt.str)!=0)
323 									fprintf(file,"%s=%s\n",desc.name,str);
324 							}
325 						}
326 						break;
327 
328 					case STP_PARAMETER_TYPE_INT:
329 						{
330 							if(stp_check_int_parameter(stpvars,desc.name,STP_PARAMETER_DEFAULTED))
331 							{
332 								int val=stp_get_int_parameter(stpvars,desc.name);
333 //								if(!desc.is_mandatory || val!=desc.deflt.integer)
334 									fprintf(file,"%s=%d\n",desc.name,val);
335 							}
336 						}
337 						break;
338 
339 					case STP_PARAMETER_TYPE_BOOLEAN:
340 						{
341 							if(stp_check_boolean_parameter(stpvars,desc.name,STP_PARAMETER_DEFAULTED))
342 							{
343 								int val=stp_get_boolean_parameter(stpvars,desc.name);
344 //								if(!desc.is_mandatory || val!=desc.deflt.boolean)
345 									fprintf(file,"%s=%d\n",desc.name,val);
346 							}
347 						}
348 						break;
349 
350 					case STP_PARAMETER_TYPE_DOUBLE:
351 						{
352 							if(stp_check_float_parameter(stpvars,desc.name,STP_PARAMETER_DEFAULTED))
353 							{
354 								double val=stp_get_float_parameter(stpvars,desc.name);
355 //								if(!desc.is_mandatory || val!=desc.deflt.dbl)
356 									fprintf(file,"%s=%f\n",desc.name,val);
357 							}
358 						}
359 						break;
360 
361 					default:
362 						break;
363 				}
364 			}
365 			stp_parameter_description_destroy(&desc);
366 		}
367 	}
368 
369 	fprintf(file,"CustomWidth=%d\n",pagewidth);
370 	fprintf(file,"CustomHeight=%d\n",pageheight);
371 
372 	stp_parameter_list_destroy(params);
373 }
374 
375 
376 // SetDriver
377 // Returns false if the driver isn't recognised, true otherwise.
378 
SetDriver(const char * driver)379 bool GPrinterSettings::SetDriver(const char *driver)
380 {
381 	bool result=true;
382 	bool driverchanged=false;
383 
384 	// FIXME - Not pretty.  We need to strdup() the result of this because it's
385 	// not valid after the driver has changed.
386 	const char *_oldpagesize=stp_get_string_parameter(stpvars,"PageSize");
387 	char *oldpagesize=NULL;
388 	if(_oldpagesize)
389 	{
390 		oldpagesize=strdup(_oldpagesize);
391 		Debug[TRACE] << "Old page size is: " << oldpagesize << endl;
392 	}
393 
394 	Debug[TRACE] << "Checking stpvars" << endl;
395 	if(stpvars)
396 	{
397 		// We avoid messing with this stuff as much as possible if the driver didn't change -
398 		// that way you can change from a printer's queue to "Save to file" without
399 		// messing up the print settings.
400 		const char *olddriver=stp_get_driver(stpvars);
401 		Debug[TRACE] << "Checking olddriver" << endl;
402 		if(!olddriver)
403 			olddriver="None";
404 		Debug[TRACE] << "Checking driver" << endl;
405 		if(!driver)
406 			driver=DEFAULT_PRINTER_DRIVER;
407 		Debug[TRACE] << "Comparing drivers:" << olddriver << " against " << driver << endl;
408 		if(strcmp(driver,olddriver)==0) // If the driver hasn't changed...
409 		{
410 			// We ensure we can get the printer.  If we can't, chances are the Gutenprint
411 			// data files weren't loaded correctly.
412 			if(!stp_get_printer(stpvars))
413 				throw _("Can't obtain printer from Gutenprint\nCheck STP_DATA_PATH and Gutenprint version!");
414 		}
415 		else
416 		{
417 			driverchanged=true;
418 			Debug[TRACE] << "SetDriver(): Setting driver to " << driver << endl;
419 
420 			// Work around the non-defaulting of inactive settings...
421 			const stp_vars_t *defaults=stp_default_settings();
422 			stp_vars_copy(stpvars,defaults);
423 
424 			stp_set_driver(stpvars,driver);
425 			output.SetString("Driver",driver);
426 
427 			const stp_printer_t *printer=stp_get_printer(stpvars);
428 			Debug[TRACE] << "Checking printer" << endl;
429 			if(printer)
430 			{
431 				Debug[TRACE] << "Setting defaults" << endl;
432 				stp_set_printer_defaults(stpvars,printer);
433 			}
434 			else
435 			{
436 				Debug[TRACE] << "Unable to get printer - reverting to default driver" << endl;
437 				output.SetString("Driver",DEFAULT_PRINTER_DRIVER);
438 				stp_set_driver(stpvars,DEFAULT_PRINTER_DRIVER);
439 				Debug[TRACE] << "Checking printer again" << endl;
440 				if((printer=stp_get_printer(stpvars)))
441 					stp_set_printer_defaults(stpvars,printer);
442 				else
443 					Debug[TRACE] << "Still can't get printer!" << endl;
444 				result=false;
445 			}
446 		}
447 		stp_set_page_width(stpvars,pagewidth);
448 		stp_set_page_height(stpvars,pageheight);
449 
450 
451 		stp_parameter_t desc;
452 		desc.is_active=false;
453 		stp_describe_parameter(stpvars,"PPDFile",&desc);
454 		if(desc.is_active)
455 		{
456 			driverchanged=true;
457 			Debug[TRACE] << "Getting default PPD..." << endl;
458 			char *defppd=output.GetPPD();
459 			Debug[TRACE] << "Checking defppd" << endl;
460 			if(defppd)
461 			{
462 				Debug[TRACE] << "Setting PPDFile to " << defppd << endl;
463 				stp_set_file_parameter(stpvars,"PPDFile",defppd);
464 				free(defppd);
465 
466 				Debug[TRACE] << "Checking ppdsizes_workaround_done" << endl;
467 				if(!ppdsizes_workaround_done)
468 				{
469 					stp_parameter_t desc2;
470 					stp_describe_parameter(stpvars,"PageSize",&desc2);
471 					Debug[TRACE] << "After setting PPD Default page size is now: " << desc2.deflt.str << endl;
472 					stp_set_string_parameter(stpvars,"PageSize",desc2.deflt.str);
473 					stp_parameter_description_destroy(&desc2);
474 					ppdsizes_workaround_done=true;
475 				}
476 			}
477 		}
478 		stp_parameter_description_destroy(&desc);
479 
480 		if(driverchanged)
481 		{
482 			// We attempt to set the previously used pagesize if possible.
483 			// We do this by looping through the known papersizes for the
484 			// new driver and comparing against the old papersize.
485 			if(oldpagesize)
486 			{
487 				Debug[TRACE] << "Old page size is: " << oldpagesize << endl;
488 				stp_describe_parameter(stpvars,"PageSize",&desc);
489 				stp_string_list_t *strlist=desc.bounds.str;
490 				if(strlist)
491 				{
492 					int strcount=stp_string_list_count(strlist);
493 					for(int j=0;j<strcount;++j)
494 					{
495 						stp_param_string_t *p=stp_string_list_param(strlist,j);
496 						Debug[TRACE] << "Comparing against " << p->text << endl;
497 						if(strcmp(p->text,oldpagesize)==0)
498 						{
499 							stp_set_string_parameter(stpvars,"PageSize",oldpagesize);
500 							j=strcount;
501 						}
502 					}
503 				}
504 				stp_parameter_description_destroy(&desc);
505 				free(oldpagesize);
506 			}
507 
508 			Validate();
509 		}
510 	}
511 	else
512 		Debug[TRACE] << "No stp vars!" << endl;
513 	return(result);
514 }
515 
516 
Validate()517 void GPrinterSettings::Validate()
518 {
519 	stputil_validate_parameters(stpvars);
520 }
521 
522 
Reset()523 void GPrinterSettings::Reset()
524 {
525 	stp_vars_destroy(stpvars);
526 	stpvars=stp_vars_create();
527 	// FIXME - a bit of a hack this - set the driver so we can compare against it.
528 	// (We set the queue's own driver here in case the app doesn't over-ride it
529 	// Make sure this doesn't break anything...)
530 	const char *driver=output.FindString("Driver");
531 	if(!SetDriver(driver))
532 		output.SetString("Driver",DEFAULT_PRINTER_DRIVER);
533 //	stp_set_driver(stpvars,"ps");
534 
535 	Debug[TRACE] << "Created fresh stp_vars" << endl;
536 	initialised=false;
537 }
538