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