1 /**************************************************************************
2 *   Copyright (C) 2005-2020 by Oleksandr Shneyder                         *
3 *                              <o.shneyder@phoca-gmbh.de>                 *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *   This program is distributed in the hope that it will be useful,       *
10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 *   GNU General Public License for more details.                          *
13 *                                                                         *
14 *   You should have received a copy of the GNU General Public License     *
15 *   along with this program.  If not, see <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17 
18 #include "cupsprint.h"
19 #ifndef Q_OS_WIN
20 #include "x2gologdebug.h"
21 #include "x2gosettings.h"
22 #include <QDir>
CUPSPrint()23 CUPSPrint::CUPSPrint()
24 {
25 	ppd=0l;
26 	num_dests= cupsGetDests ( &dests );
27 }
28 
29 
~CUPSPrint()30 CUPSPrint::~CUPSPrint()
31 {
32 	cupsFreeDests ( num_dests, dests );
33 	if ( ppd )
34 		ppdClose ( ppd );
35 	ppd=0l;
36 }
37 
38 
getPrinters()39 QStringList CUPSPrint::getPrinters()
40 {
41 	QStringList printers;
42 
43 	for ( int i=0;i<num_dests;++i )
44 		printers<<dests[i].name;
45 	return printers;
46 }
47 
getDefaultUserPrinter()48 QString CUPSPrint::getDefaultUserPrinter()
49 {
50 	X2goSettings st ( "printing" );
51 
52 	QString defPrint=st.setting()->value (
53 	                     "CUPS/defaultprinter","" ). toString();
54 	if ( defPrint.length() >0 )
55 	{
56 		cups_dest_t *dest = cupsGetDest ( defPrint.toLatin1(),
57 		                                  0l, num_dests, dests );
58 		if ( dest )
59 			return defPrint;
60 	}
61 
62 	cups_dest_t *dest = cupsGetDest ( 0l, 0l, num_dests, dests );
63 	if ( dest )
64 		defPrint=dest->name;
65 
66 	return defPrint;
67 }
68 
setDefaultUserPrinter(QString printer)69 void CUPSPrint::setDefaultUserPrinter ( QString printer )
70 {
71 	X2goSettings st ( "printing" );
72 	st.setting()->setValue ( "CUPS/defaultprinter", QVariant ( printer ) );
73 }
74 
getPrinterInfo(const QString & printerName,QString & info,bool & acceptJobs,QString & location,QString & model,printState & state,QString & stateReason)75 bool CUPSPrint::getPrinterInfo ( const QString& printerName, QString& info,
76                                  bool& acceptJobs, QString& location,
77                                  QString& model, printState& state,
78                                  QString& stateReason )
79 {
80 	cups_dest_t *dest = cupsGetDest ( printerName.toLatin1(), 0l,
81 	                                  num_dests,
82 	                                  dests );
83 	if ( !dest )
84 		return false;
85 	acceptJobs=qstrcmp ( cupsGetOption ( "printer-is-accepting-jobs",
86 	                                     dest->num_options,
87 	                                     dest->options ),"0" );
88 
89 	info=QString::fromLocal8Bit (
90 	         cupsGetOption ( "printer-info",
91 	                         dest->num_options, dest->options ) );
92 
93 	location=QString::fromLocal8Bit (
94 	             cupsGetOption ( "printer-location",
95 	                             dest->num_options, dest->options ) );
96 	model=QString::fromLocal8Bit (
97 	          cupsGetOption ( "printer-make-and-model",
98 	                          dest->num_options, dest->options ) );
99 	QString st=cupsGetOption ( "printer-state",
100 	                           dest->num_options, dest->options );
101 	state=NDEF;
102 	if ( st=="3" )
103 		state=IDLE;
104 	if ( st=="4" )
105 		state=PRINTING;
106 	if ( st=="5" )
107 		state=STOPPED;
108 	stateReason=QString::fromLocal8Bit (
109 	                cupsGetOption ( "printer-state-reasons",
110 	                                dest->num_options, dest->options ) );
111 	return true;
112 }
113 
setCurrentPrinter(QString prn)114 bool CUPSPrint::setCurrentPrinter ( QString prn )
115 {
116 	currentPrinter=prn;
117 	QString fl=cupsGetPPD ( prn.toLatin1() );
118 	if ( fl.length() <=0 )
119 		return false;
120 
121 	if ( ppd )
122 		ppdClose ( ppd );
123 	ppd=0l;
124 	ppd=ppdOpenFile ( fl.toLatin1() );
125 	unlink ( fl.toLatin1() );
126 	if ( ppd==0l )
127 		return false;
128 	ppdMarkDefaults ( ppd );
129 	loadUserOptions();
130 	if ( ppdConflicts ( ppd ) !=0 )
131 	{
132 		x2goDebug<<"There are conflicting options in user settings,\n"
133 		"loading defaults"<<endl;
134 		setDefaults();
135 	}
136 	return true;
137 }
138 
getOptionValue(const QString & option,QString & value,QString & valueText)139 bool CUPSPrint::getOptionValue ( const QString& option,
140                                  QString& value, QString& valueText )
141 {
142 	if ( !ppd )
143 		return false;
144 	ppd_choice_t* choice=ppdFindMarkedChoice ( ppd,option.toLatin1() );
145 	if ( !choice )
146 	{
147 		ppd_option_t* opt=ppdFindOption ( ppd,option.toLatin1() );
148 		if ( !opt )
149 			return false;
150 		choice=ppdFindChoice ( opt,opt->defchoice );
151 		if ( !choice )
152 			return false;
153 	}
154 	value=QString::fromLocal8Bit ( choice->choice );
155 	valueText=QString::fromLocal8Bit ( choice->text );
156 // 	x2goDebug<<"getValue:"<<value<<endl;
157 	return true;
158 }
159 
getOptionValues(const QString & option,QStringList & values,QStringList & descriptions)160 int CUPSPrint::getOptionValues ( const QString& option,
161                                  QStringList& values,
162                                  QStringList& descriptions )
163 {
164 	values.clear();
165 	descriptions.clear();
166 	if ( !ppd )
167 		return -1;
168 	int cur_val=-1;
169 	values.clear();
170 	descriptions.clear();
171 	ppd_option_t* opt=ppdFindOption ( ppd,option.toLatin1() );
172 	if ( !opt )
173 		return -1;
174 	for ( int k=0;k<opt->num_choices;++k )
175 	{
176 		ppd_choice_t* choice=& ( opt->choices[k] );
177 		if ( choice->marked )
178 		{
179 			cur_val=values.size();
180 		}
181 		//if no choice is marked, return default
182 		if ( !qstrcmp ( choice->choice,opt->defchoice ) && cur_val==-1 )
183 		{
184 			cur_val=values.size();
185 		}
186 		values<<QString::fromLocal8Bit ( choice->choice );
187 		descriptions<<QString::fromLocal8Bit ( choice->text );
188 	}
189 	return cur_val;
190 
191 }
192 
193 
getOptionGroups(QStringList & names,QStringList & texts)194 int CUPSPrint::getOptionGroups ( QStringList& names, QStringList& texts )
195 {
196 	names.clear();
197 	texts.clear();
198 	if ( !ppd )
199 		return -1;
200 
201 	for ( int i=0;i<ppd->num_groups;++i )
202 	{
203 		ppd_group_t* group=& ( ppd->groups[i] );
204 		names<<QString::fromLocal8Bit ( group->name );
205 		texts<<QString::fromLocal8Bit ( group->text );
206 	}
207 	return names.size();
208 }
209 
getOptionsList(const QString & groupName,QStringList & names,QStringList & texts)210 int CUPSPrint::getOptionsList ( const QString& groupName, QStringList& names,
211                                 QStringList& texts )
212 {
213 	names.clear();
214 	texts.clear();
215 	if ( !ppd )
216 		return -1;
217 
218 	for ( int i=0;i<ppd->num_groups;++i )
219 	{
220 		ppd_group_t* group=& ( ppd->groups[i] );
221 		if ( groupName.length() >0 && groupName !=
222 		        QString::fromLocal8Bit ( group->name ) )
223 			continue;
224 		for ( int j=0;j<group->num_options;++j )
225 		{
226 			ppd_option_t* option=& ( group->options[j] );
227 			names<<QString::fromLocal8Bit ( option->keyword );
228 			texts<<QString::fromLocal8Bit ( option->text );
229 		}
230 	}
231 	return names.size();
232 }
233 
234 
setValue(const QString & option,const QString & value,QString & conflict_opt,QString & conflict_val)235 bool CUPSPrint::setValue ( const QString& option, const QString& value,
236                            QString& conflict_opt, QString& conflict_val )
237 {
238 	if ( !ppd )
239 		return false;
240 	int conflictsBefore= ppdConflicts ( ppd );
241 	QString valueBefore, textBefore;
242 	if ( !getOptionValue ( option,valueBefore,textBefore ) )
243 		return false;
244 	ppdMarkOption ( ppd,option.toLatin1(),value.toLatin1() );
245 
246 	if ( conflictsBefore==ppdConflicts ( ppd ) )
247 	{
248 		return true;
249 	}
250 
251 	//find conflicting option
252 	for ( int i=0;i<ppd->num_consts;++i )
253 	{
254 		QString confOpt,confVal;
255 		if ( option==ppd->consts[i].option1 &&
256 		        value==ppd->consts[i].choice1 )
257 		{
258 			confOpt=ppd->consts[i].option2;
259 			confVal=ppd->consts[i].choice2;
260 		}
261 		else if ( option==ppd->consts[i].option2 &&
262 		          value==ppd->consts[i].choice2 )
263 		{
264 			confOpt=ppd->consts[i].option1;
265 			confVal=ppd->consts[i].choice1;
266 		}
267 		else
268 			continue;
269 		QString selectedValue, selectedText;
270 		if ( getOptionValue ( confOpt,selectedValue,selectedText ) )
271 		{
272 			if ( selectedValue==confVal )
273 			{
274 				//conflicting option/choice found
275 				conflict_val=confVal;
276 				conflict_opt=confOpt;
277 				break;
278 			}
279 		}
280 	}
281 
282 
283 	//set previous value
284 	ppdMarkOption ( ppd,option.toLatin1(),valueBefore.toLatin1() );
285 	return false;
286 }
287 
288 
getOptionText(const QString & option,QString & text)289 bool CUPSPrint::getOptionText ( const QString& option, QString& text )
290 {
291 	if ( !ppd )
292 		return false;
293 	ppd_option_t* opt=ppdFindOption ( ppd,option.toLatin1() );
294 	if ( !opt )
295 		return false;
296 	text=QString::fromLocal8Bit ( opt->text );
297 	return true;
298 }
299 
setDefaults()300 void CUPSPrint::setDefaults()
301 {
302 	//don't use ppdMarkDefaults here
303 	//ppdMarkDefaults do not unmark
304 	//already marked choices
305 	if ( !ppd )
306 		return;
307 	for ( int i=0;i<ppd->num_groups;++i )
308 	{
309 		ppd_group_t* group=& ( ppd->groups[i] );
310 		for ( int j=0;j<group->num_options;++j )
311 		{
312 			ppd_option_t* option=& ( group->options[j] );
313 			ppdMarkOption ( ppd,option->keyword,option->defchoice );
314 
315 		}
316 	}
317 }
318 
319 
320 
saveOptions()321 void CUPSPrint::saveOptions()
322 {
323 	if ( !ppd )
324 		return;
325 	X2goSettings st( "printing" );
326 
327 	QStringList options;
328 	for ( int i=0;i<ppd->num_groups;++i )
329 	{
330 		ppd_group_t* group=& ( ppd->groups[i] );
331 		for ( int j=0;j<group->num_options;++j )
332 		{
333 			ppd_option_t* option=& ( group->options[j] );
334 			QString val,valtext;
335 			if ( !getOptionValue ( option->keyword,val,valtext ) )
336 				continue; //something is wrong here
337 			if ( val!=option->defchoice )
338 			{
339 				QString opt=option->keyword;
340 				opt+="="+val;
341 				options<<opt;
342 			}
343 		}
344 	}
345 	st.setting()->setValue ( "CUPS/options/"+currentPrinter,
346 	              QVariant ( options ) );
347 }
348 
349 
loadUserOptions()350 void CUPSPrint::loadUserOptions()
351 {
352 	X2goSettings st ( "printing" );
353 	QStringList options=st.setting()->value (
354 	                        "CUPS/options/"+currentPrinter ).toStringList();
355 	for ( int i=0;i<options.size();++i )
356 	{
357 		QStringList opt=options[i].split ( "=" );
358 		ppdMarkOption ( ppd,opt[0].toLatin1(),opt[1].toLatin1() );
359 	}
360 }
361 
362 
print(const QString & file,QString title)363 void CUPSPrint::print ( const QString& file, QString title )
364 {
365 	if ( !ppd )
366 		return;
367 
368 	int num_options = 0;
369 	cups_option_t *options = NULL;
370 
371 
372 	for ( int i=0;i<ppd->num_groups;++i )
373 	{
374 		ppd_group_t* group=& ( ppd->groups[i] );
375 		for ( int j=0;j<group->num_options;++j )
376 		{
377 			ppd_option_t* option=& ( group->options[j] );
378 			QString val,valtext;
379 			if ( !getOptionValue ( option->keyword,val,valtext ) )
380 				continue; //something is wrong here
381 			if ( val!=option->defchoice )
382 			{
383 				num_options = cupsAddOption ( option->keyword,
384 				                              val.toLatin1(),
385 				                              num_options,
386 				                              &options );
387 			}
388 		}
389 	}
390 	cupsPrintFile ( currentPrinter.toLatin1(),file.toLatin1(),
391 	                title.toLatin1(), num_options,options );
392 	cupsFreeOptions ( num_options, options );
393 }
394 #endif
395