Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <unistd.h>
21 : #include <sys/wait.h>
22 : #include <signal.h>
23 :
24 : #include "cupsmgr.hxx"
25 : #include "vcl/strhelper.hxx"
26 :
27 : #include "unx/saldata.hxx"
28 :
29 : #include "tools/urlobj.hxx"
30 : #include "tools/stream.hxx"
31 : #include "tools/debug.hxx"
32 : #include "tools/config.hxx"
33 :
34 : #include "i18nutil/paper.hxx"
35 : #include <comphelper/string.hxx>
36 : #include "rtl/strbuf.hxx"
37 : #include <sal/macros.h>
38 :
39 : #include "osl/thread.hxx"
40 : #include "osl/mutex.hxx"
41 : #include "osl/process.h"
42 :
43 : // filename of configuration files
44 : #define PRINT_FILENAME "psprint.conf"
45 : // the group of the global defaults
46 : #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
47 :
48 : #include <unordered_set>
49 :
50 : using namespace psp;
51 : using namespace osl;
52 :
53 : namespace psp
54 : {
55 : class SystemQueueInfo : public Thread
56 : {
57 : mutable Mutex m_aMutex;
58 : bool m_bChanged;
59 : std::list< PrinterInfoManager::SystemPrintQueue >
60 : m_aQueues;
61 : OUString m_aCommand;
62 :
63 : virtual void run() SAL_OVERRIDE;
64 :
65 : public:
66 : SystemQueueInfo();
67 : virtual ~SystemQueueInfo();
68 :
69 : bool hasChanged() const;
70 : OUString getCommand() const;
71 :
72 : // sets changed status to false; therefore not const
73 : void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
74 : };
75 : } // namespace
76 :
77 : /*
78 : * class PrinterInfoManager
79 : */
80 :
81 3506 : PrinterInfoManager& PrinterInfoManager::get()
82 : {
83 3506 : SalData* pSalData = GetSalData();
84 :
85 3506 : if( ! pSalData->m_pPIManager )
86 : {
87 79 : pSalData->m_pPIManager = CUPSManager::tryLoadCUPS();
88 79 : if( ! pSalData->m_pPIManager )
89 0 : pSalData->m_pPIManager = new PrinterInfoManager();
90 :
91 79 : pSalData->m_pPIManager->initialize();
92 : #if OSL_DEBUG_LEVEL > 1
93 : fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() );
94 : #endif
95 : }
96 :
97 3506 : return *pSalData->m_pPIManager;
98 : }
99 :
100 0 : void PrinterInfoManager::release()
101 : {
102 0 : SalData* pSalData = GetSalData();
103 0 : delete pSalData->m_pPIManager;
104 0 : pSalData->m_pPIManager = NULL;
105 0 : }
106 :
107 79 : PrinterInfoManager::PrinterInfoManager( Type eType ) :
108 : m_pQueueInfo( NULL ),
109 : m_eType( eType ),
110 : m_bUseIncludeFeature( false ),
111 : m_bUseJobPatch( true ),
112 79 : m_aSystemDefaultPaper( "A4" )
113 : {
114 79 : if( eType == Default )
115 0 : m_pQueueInfo = new SystemQueueInfo();
116 79 : initSystemDefaultPaper();
117 79 : }
118 :
119 0 : PrinterInfoManager::~PrinterInfoManager()
120 : {
121 0 : delete m_pQueueInfo;
122 : #if OSL_DEBUG_LEVEL > 1
123 : fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() );
124 : #endif
125 0 : }
126 :
127 79 : void PrinterInfoManager::initSystemDefaultPaper()
128 : {
129 158 : m_aSystemDefaultPaper = OStringToOUString(
130 : PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
131 79 : RTL_TEXTENCODING_UTF8);
132 79 : }
133 :
134 48 : bool PrinterInfoManager::checkPrintersChanged( bool bWait )
135 : {
136 : // check if files were created, deleted or modified since initialize()
137 48 : ::std::list< WatchFile >::const_iterator it;
138 48 : bool bChanged = false;
139 144 : for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
140 : {
141 96 : DirectoryItem aItem;
142 96 : if( DirectoryItem::get( it->m_aFilePath, aItem ) )
143 : {
144 48 : if( it->m_aModified.Seconds != 0 )
145 0 : bChanged = true; // file probably has vanished
146 : }
147 : else
148 : {
149 48 : FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
150 48 : if( aItem.getFileStatus( aStatus ) )
151 0 : bChanged = true; // unlikely but not impossible
152 : else
153 : {
154 48 : TimeValue aModified = aStatus.getModifyTime();
155 48 : if( aModified.Seconds != it->m_aModified.Seconds )
156 0 : bChanged = true;
157 48 : }
158 : }
159 96 : }
160 :
161 48 : if( bWait && m_pQueueInfo )
162 : {
163 : #if OSL_DEBUG_LEVEL > 1
164 : fprintf( stderr, "syncing printer discovery thread\n" );
165 : #endif
166 0 : m_pQueueInfo->join();
167 : #if OSL_DEBUG_LEVEL > 1
168 : fprintf( stderr, "done: syncing printer discovery thread\n" );
169 : #endif
170 : }
171 :
172 48 : if( ! bChanged && m_pQueueInfo )
173 0 : bChanged = m_pQueueInfo->hasChanged();
174 48 : if( bChanged )
175 : {
176 0 : initialize();
177 : }
178 :
179 48 : return bChanged;
180 : }
181 :
182 79 : void PrinterInfoManager::initialize()
183 : {
184 79 : m_bUseIncludeFeature = false;
185 79 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
186 79 : m_aPrinters.clear();
187 79 : m_aWatchFiles.clear();
188 79 : OUString aDefaultPrinter;
189 :
190 : // first initialize the global defaults
191 : // have to iterate over all possible files
192 : // there should be only one global setup section in all
193 : // available config files
194 79 : m_aGlobalDefaults = PrinterInfo();
195 :
196 : // need a parser for the PPDContext. generic printer should do.
197 79 : m_aGlobalDefaults.m_pParser = PPDParser::getParser( OUString( "SGENPRT" ) );
198 79 : m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
199 :
200 79 : if( ! m_aGlobalDefaults.m_pParser )
201 : {
202 : #if OSL_DEBUG_LEVEL > 1
203 : fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
204 : #endif
205 0 : return;
206 : }
207 :
208 79 : std::list< OUString > aDirList;
209 79 : psp::getPrinterPathList( aDirList, NULL );
210 79 : std::list< OUString >::const_iterator print_dir_it;
211 237 : for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
212 : {
213 158 : INetURLObject aFile( *print_dir_it, INetProtocol::File, INetURLObject::ENCODE_ALL );
214 158 : aFile.Append( OUString( PRINT_FILENAME ) );
215 316 : Config aConfig( aFile.PathToFileName() );
216 158 : if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
217 : {
218 : #if OSL_DEBUG_LEVEL > 1
219 : fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
220 : #endif
221 79 : aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
222 :
223 79 : OString aValue( aConfig.ReadKey( "Copies" ) );
224 79 : if (!aValue.isEmpty())
225 0 : m_aGlobalDefaults.m_nCopies = aValue.toInt32();
226 :
227 79 : aValue = aConfig.ReadKey( "Orientation" );
228 79 : if (!aValue.isEmpty())
229 0 : m_aGlobalDefaults.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
230 :
231 79 : aValue = aConfig.ReadKey( "MarginAdjust" );
232 79 : if (!aValue.isEmpty())
233 : {
234 0 : m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.getToken(0, ',').toInt32();
235 0 : m_aGlobalDefaults.m_nRightMarginAdjust = aValue.getToken(1, ',').toInt32();
236 0 : m_aGlobalDefaults.m_nTopMarginAdjust = aValue.getToken(2, ',').toInt32();
237 0 : m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.getToken(3, ',').toInt32();
238 : }
239 :
240 79 : aValue = aConfig.ReadKey( "ColorDepth", "24" );
241 79 : if (!aValue.isEmpty())
242 79 : m_aGlobalDefaults.m_nColorDepth = aValue.toInt32();
243 :
244 79 : aValue = aConfig.ReadKey( "ColorDevice" );
245 79 : if (!aValue.isEmpty())
246 0 : m_aGlobalDefaults.m_nColorDevice = aValue.toInt32();
247 :
248 79 : aValue = aConfig.ReadKey( "PSLevel" );
249 79 : if (!aValue.isEmpty())
250 0 : m_aGlobalDefaults.m_nPSLevel = aValue.toInt32();
251 :
252 79 : aValue = aConfig.ReadKey( "PDFDevice" );
253 79 : if (!aValue.isEmpty())
254 0 : m_aGlobalDefaults.m_nPDFDevice = aValue.toInt32();
255 :
256 : // get the PPDContext of global JobData
257 79 : for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
258 : {
259 0 : OString aKey( aConfig.GetKeyName( nKey ) );
260 0 : if (aKey.startsWith("PPD_"))
261 : {
262 0 : aValue = aConfig.ReadKey( aKey );
263 0 : const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
264 0 : if( pKey )
265 : {
266 : m_aGlobalDefaults.m_aContext.
267 : setValue( pKey,
268 0 : aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
269 0 : true );
270 : }
271 : }
272 79 : }
273 : }
274 158 : }
275 79 : setDefaultPaper( m_aGlobalDefaults.m_aContext );
276 :
277 : // now collect all available printers
278 237 : for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
279 : {
280 158 : INetURLObject aDir( *print_dir_it, INetProtocol::File, INetURLObject::ENCODE_ALL );
281 316 : INetURLObject aFile( aDir );
282 158 : aFile.Append( OUString( PRINT_FILENAME ) );
283 :
284 : // check directory validity
285 316 : OUString aUniPath;
286 158 : FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
287 316 : Directory aDirectory( aUniPath );
288 158 : if( aDirectory.open() )
289 0 : continue;
290 158 : aDirectory.close();
291 :
292 158 : FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
293 316 : FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
294 316 : DirectoryItem aItem;
295 :
296 : // setup WatchFile list
297 316 : WatchFile aWatchFile;
298 158 : aWatchFile.m_aFilePath = aUniPath;
299 237 : if( ! DirectoryItem::get( aUniPath, aItem ) &&
300 79 : ! aItem.getFileStatus( aStatus ) )
301 : {
302 79 : aWatchFile.m_aModified = aStatus.getModifyTime();
303 : }
304 : else
305 : {
306 79 : aWatchFile.m_aModified.Seconds = 0;
307 79 : aWatchFile.m_aModified.Nanosec = 0;
308 : }
309 158 : m_aWatchFiles.push_back( aWatchFile );
310 :
311 316 : Config aConfig( aFile.PathToFileName() );
312 395 : for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
313 : {
314 237 : aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
315 237 : OString aValue = aConfig.ReadKey( "Printer" );
316 237 : if (!aValue.isEmpty())
317 : {
318 79 : OUString aPrinterName;
319 :
320 79 : sal_Int32 nNamePos = aValue.indexOf('/');
321 : // check for valid value of "Printer"
322 79 : if (nNamePos == -1)
323 0 : continue;
324 :
325 158 : Printer aPrinter;
326 : // initialize to global defaults
327 79 : aPrinter.m_aInfo = m_aGlobalDefaults;
328 :
329 158 : aPrinterName = OStringToOUString(aValue.copy(nNamePos+1),
330 79 : RTL_TEXTENCODING_UTF8);
331 79 : aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
332 79 : aPrinter.m_aInfo.m_aDriverName = OStringToOUString(aValue.copy(0, nNamePos), RTL_TEXTENCODING_UTF8);
333 :
334 : // set parser, merge settings
335 : // don't do this for CUPS printers as this is done
336 : // by the CUPS system itself
337 79 : if( !aPrinter.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
338 : {
339 79 : aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
340 79 : aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
341 : // note: setParser also purges the context
342 :
343 : // ignore this printer if its driver is not found
344 79 : if( ! aPrinter.m_aInfo.m_pParser )
345 0 : continue;
346 :
347 : // merge the ppd context keys if the printer has the same keys and values
348 : // this is a bit tricky, since it involves mixing two PPDs
349 : // without constraints which might end up badly
350 : // this feature should be use with caution
351 : // it is mainly to select default paper sizes for new printers
352 158 : for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
353 : {
354 79 : const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
355 79 : const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
356 79 : const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
357 79 : if( pDefKey && pPrinterKey )
358 : // at least the options exist in both PPDs
359 : {
360 79 : if( pDefValue )
361 : {
362 79 : const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
363 79 : if( pPrinterValue )
364 : // the printer has a corresponding option for the key
365 79 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
366 : }
367 : else
368 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
369 : }
370 : }
371 :
372 79 : aValue = aConfig.ReadKey( "Command" );
373 : // no printer without a command
374 79 : if (aValue.isEmpty())
375 : {
376 : /* TODO:
377 : * porters: please append your platform to the Solaris
378 : * case if your platform has SystemV printing per default.
379 : */
380 : #if defined SOLARIS
381 : aValue = "lp";
382 : #else
383 79 : aValue = "lpr";
384 : #endif
385 : }
386 79 : aPrinter.m_aInfo.m_aCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
387 : }
388 :
389 79 : aValue = aConfig.ReadKey( "QuickCommand" );
390 79 : aPrinter.m_aInfo.m_aQuickCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
391 :
392 79 : aValue = aConfig.ReadKey( "Features" );
393 79 : aPrinter.m_aInfo.m_aFeatures = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
394 :
395 : // override the settings in m_aGlobalDefaults if keys exist
396 79 : aValue = aConfig.ReadKey( "DefaultPrinter" );
397 79 : if (!aValue.equals("0") && !aValue.equalsIgnoreAsciiCase("false"))
398 79 : aDefaultPrinter = aPrinterName;
399 :
400 79 : aValue = aConfig.ReadKey( "Location" );
401 79 : aPrinter.m_aInfo.m_aLocation = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
402 :
403 79 : aValue = aConfig.ReadKey( "Comment" );
404 79 : aPrinter.m_aInfo.m_aComment = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
405 :
406 79 : aValue = aConfig.ReadKey( "Copies" );
407 79 : if (!aValue.isEmpty())
408 0 : aPrinter.m_aInfo.m_nCopies = aValue.toInt32();
409 :
410 79 : aValue = aConfig.ReadKey( "Orientation" );
411 79 : if (!aValue.isEmpty())
412 0 : aPrinter.m_aInfo.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
413 :
414 79 : aValue = aConfig.ReadKey( "MarginAdjust" );
415 79 : if (!aValue.isEmpty())
416 : {
417 0 : aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.getToken(0, ',' ).toInt32();
418 0 : aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.getToken(1, ',' ).toInt32();
419 0 : aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.getToken(2, ',' ).toInt32();
420 0 : aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.getToken(3, ',' ).toInt32();
421 : }
422 :
423 79 : aValue = aConfig.ReadKey( "ColorDepth" );
424 79 : if (!aValue.isEmpty())
425 0 : aPrinter.m_aInfo.m_nColorDepth = aValue.toInt32();
426 :
427 79 : aValue = aConfig.ReadKey( "ColorDevice" );
428 79 : if (!aValue.isEmpty())
429 0 : aPrinter.m_aInfo.m_nColorDevice = aValue.toInt32();
430 :
431 79 : aValue = aConfig.ReadKey( "PSLevel" );
432 79 : if (!aValue.isEmpty())
433 0 : aPrinter.m_aInfo.m_nPSLevel = aValue.toInt32();
434 :
435 79 : aValue = aConfig.ReadKey( "PDFDevice" );
436 79 : if (!aValue.isEmpty())
437 0 : aPrinter.m_aInfo.m_nPDFDevice = aValue.toInt32();
438 :
439 : // now iterate over all keys to extract multi key information:
440 : // 1. PPDContext information
441 474 : for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
442 : {
443 395 : OString aKey( aConfig.GetKeyName( nKey ) );
444 395 : if( aKey.startsWith("PPD_") && aPrinter.m_aInfo.m_pParser )
445 : {
446 0 : aValue = aConfig.ReadKey( aKey );
447 0 : const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
448 0 : if( pKey )
449 : {
450 : aPrinter.m_aInfo.m_aContext.
451 : setValue( pKey,
452 0 : aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
453 0 : true );
454 : }
455 : }
456 395 : }
457 :
458 79 : setDefaultPaper( aPrinter.m_aInfo.m_aContext );
459 :
460 : // finally insert printer
461 79 : FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
462 79 : aPrinter.m_bModified = false;
463 79 : aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
464 : std::unordered_map< OUString, Printer, OUStringHash >::const_iterator find_it =
465 79 : m_aPrinters.find( aPrinterName );
466 79 : if( find_it != m_aPrinters.end() )
467 : {
468 0 : aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
469 0 : aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
470 : }
471 158 : m_aPrinters[ aPrinterName ] = aPrinter;
472 : }
473 237 : }
474 158 : }
475 :
476 : // set default printer
477 79 : if( m_aPrinters.size() )
478 : {
479 79 : if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
480 0 : aDefaultPrinter = m_aPrinters.begin()->first;
481 : }
482 : else
483 0 : aDefaultPrinter.clear();
484 79 : m_aDefaultPrinter = aDefaultPrinter;
485 :
486 79 : if( m_eType != Default )
487 79 : return;
488 :
489 : // add a default printer for every available print queue
490 : // merge paper default printer, all else from global defaults
491 0 : PrinterInfo aMergeInfo( m_aGlobalDefaults );
492 0 : aMergeInfo.m_aDriverName = "SGENPRT";
493 0 : aMergeInfo.m_aFeatures = "autoqueue";
494 :
495 0 : if( !m_aDefaultPrinter.isEmpty() )
496 : {
497 0 : PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
498 :
499 0 : const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( OUString( "PageSize" ) );
500 0 : const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( OUString( "PageSize" ) );
501 0 : const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
502 0 : const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
503 0 : if( pMergeKey && pMergeValue )
504 0 : aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
505 : }
506 :
507 0 : getSystemPrintQueues();
508 0 : for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
509 : {
510 0 : OUString aPrinterName( "<" );
511 0 : aPrinterName += it->m_aQueue;
512 0 : aPrinterName += ">";
513 :
514 0 : if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
515 : // probably user made this one permanent
516 0 : continue;
517 :
518 0 : OUString aCmd( m_aSystemPrintCommand );
519 0 : aCmd = aCmd.replaceAll( "(PRINTER)", it->m_aQueue );
520 :
521 0 : Printer aPrinter;
522 :
523 : // initialize to merged defaults
524 0 : aPrinter.m_aInfo = aMergeInfo;
525 0 : aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
526 0 : aPrinter.m_aInfo.m_aCommand = aCmd;
527 0 : aPrinter.m_aInfo.m_aComment = it->m_aComment;
528 0 : aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
529 0 : aPrinter.m_bModified = false;
530 0 : aPrinter.m_aGroup = OUStringToOString(aPrinterName, aEncoding); //provide group name in case user makes this one permanent
531 :
532 0 : m_aPrinters[ aPrinterName ] = aPrinter;
533 0 : }
534 : }
535 :
536 48 : void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
537 : {
538 48 : std::unordered_map< OUString, Printer, OUStringHash >::const_iterator it;
539 48 : rList.clear();
540 96 : for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
541 48 : rList.push_back( it->first );
542 48 : }
543 :
544 1468 : const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
545 : {
546 1468 : static PrinterInfo aEmptyInfo;
547 1468 : std::unordered_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
548 :
549 : DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" );
550 :
551 1468 : return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
552 : }
553 :
554 0 : void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
555 : {
556 0 : std::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
557 :
558 : DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
559 :
560 0 : if( it != m_aPrinters.end() )
561 : {
562 0 : it->second.m_aInfo = rNewInfo;
563 0 : it->second.m_bModified = true;
564 0 : writePrinterConfig();
565 : }
566 0 : }
567 :
568 : // need to check writeability / creatability of config files
569 0 : static bool checkWriteability( const OUString& rUniPath )
570 : {
571 0 : bool bRet = false;
572 0 : OUString aSysPath;
573 0 : FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
574 0 : SvFileStream aStream( aSysPath, StreamMode::READ | StreamMode::WRITE );
575 0 : if( aStream.IsOpen() && aStream.IsWritable() )
576 0 : bRet = true;
577 0 : return bRet;
578 : }
579 :
580 0 : bool PrinterInfoManager::writePrinterConfig()
581 : {
582 : // find at least one writeable config
583 0 : std::unordered_map< OUString, Config*, OUStringHash > files;
584 0 : std::unordered_map< OUString, int, OUStringHash > rofiles;
585 0 : std::unordered_map< OUString, Config*, OUStringHash >::iterator file_it;
586 :
587 0 : for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
588 : {
589 0 : if( checkWriteability( wit->m_aFilePath ) )
590 : {
591 0 : files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
592 0 : break;
593 : }
594 : }
595 :
596 0 : if( files.empty() )
597 0 : return false;
598 :
599 0 : Config* pGlobal = files.begin()->second;
600 0 : pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
601 :
602 0 : std::unordered_map< OUString, Printer, OUStringHash >::iterator it;
603 0 : for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
604 : {
605 0 : if( ! it->second.m_bModified )
606 : // printer was not changed, do nothing
607 0 : continue;
608 :
609 : // don't save autoqueue printers
610 0 : sal_Int32 nIndex = 0;
611 0 : bool bAutoQueue = false;
612 0 : while( nIndex != -1 && ! bAutoQueue )
613 : {
614 0 : OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
615 0 : if( aToken == "autoqueue" )
616 0 : bAutoQueue = true;
617 0 : }
618 0 : if( bAutoQueue )
619 0 : continue;
620 :
621 0 : if( !it->second.m_aFile.isEmpty() )
622 : {
623 : // check if file is writable
624 0 : if( files.find( it->second.m_aFile ) == files.end() )
625 : {
626 0 : bool bInsertToNewFile = false;
627 : // maybe it is simply not inserted yet
628 0 : if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
629 : {
630 0 : if( checkWriteability( it->second.m_aFile ) )
631 0 : files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
632 : else
633 0 : bInsertToNewFile = true;
634 : }
635 : else
636 0 : bInsertToNewFile = true;
637 : // original file is read only, insert printer in a new writeable file
638 0 : if( bInsertToNewFile )
639 : {
640 0 : rofiles[ it->second.m_aFile ] = 1;
641 : // update alternate file list
642 : // the remove operation ensures uniqueness of each alternate
643 0 : it->second.m_aAlternateFiles.remove( it->second.m_aFile );
644 0 : it->second.m_aAlternateFiles.remove( files.begin()->first );
645 0 : it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
646 : // update file
647 0 : it->second.m_aFile = files.begin()->first;
648 : }
649 : }
650 : }
651 : else // a new printer, write it to the first file available
652 0 : it->second.m_aFile = files.begin()->first;
653 :
654 0 : if( it->second.m_aGroup.isEmpty() ) // probably a new printer
655 0 : it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
656 :
657 0 : if( files.find( it->second.m_aFile ) != files.end() )
658 : {
659 0 : Config* pConfig = files[ it->second.m_aFile ];
660 0 : pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
661 0 : pConfig->SetGroup( it->second.m_aGroup );
662 :
663 0 : OStringBuffer aValue(OUStringToOString(it->second.m_aInfo.m_aDriverName, RTL_TEXTENCODING_UTF8));
664 0 : aValue.append('/');
665 0 : aValue.append(OUStringToOString(it->first, RTL_TEXTENCODING_UTF8));
666 0 : pConfig->WriteKey("Printer", aValue.makeStringAndClear());
667 0 : pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
668 0 : pConfig->WriteKey( "Location", OUStringToOString(it->second.m_aInfo.m_aLocation, RTL_TEXTENCODING_UTF8) );
669 0 : pConfig->WriteKey( "Comment", OUStringToOString(it->second.m_aInfo.m_aComment, RTL_TEXTENCODING_UTF8) );
670 0 : pConfig->WriteKey( "Command", OUStringToOString(it->second.m_aInfo.m_aCommand, RTL_TEXTENCODING_UTF8) );
671 0 : pConfig->WriteKey( "QuickCommand", OUStringToOString(it->second.m_aInfo.m_aQuickCommand, RTL_TEXTENCODING_UTF8) );
672 0 : pConfig->WriteKey( "Features", OUStringToOString(it->second.m_aInfo.m_aFeatures, RTL_TEXTENCODING_UTF8) );
673 0 : pConfig->WriteKey("Copies", OString::number(it->second.m_aInfo.m_nCopies));
674 0 : pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
675 0 : pConfig->WriteKey("PSLevel", OString::number(it->second.m_aInfo.m_nPSLevel));
676 0 : pConfig->WriteKey("PDFDevice", OString::number(it->second.m_aInfo.m_nPDFDevice));
677 0 : pConfig->WriteKey("ColorDevice", OString::number(it->second.m_aInfo.m_nColorDevice));
678 0 : pConfig->WriteKey("ColorDepth", OString::number(it->second.m_aInfo.m_nColorDepth));
679 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nLeftMarginAdjust));
680 0 : aValue.append(',');
681 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nRightMarginAdjust));
682 0 : aValue.append(',');
683 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nTopMarginAdjust));
684 0 : aValue.append(',');
685 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nBottomMarginAdjust));
686 0 : pConfig->WriteKey("MarginAdjust", aValue.makeStringAndClear());
687 :
688 0 : if( ! it->second.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
689 : {
690 : // write PPDContext (not for CUPS)
691 0 : for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
692 : {
693 0 : const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
694 0 : OStringBuffer aKey("PPD_");
695 0 : aKey.append(OUStringToOString(pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1));
696 :
697 0 : const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
698 0 : if (pValue)
699 0 : aValue.append(OUStringToOString(pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1));
700 : else
701 0 : aValue.append("*nil");
702 0 : pConfig->WriteKey(aKey.makeStringAndClear(), aValue.makeStringAndClear());
703 0 : }
704 0 : }
705 : }
706 : }
707 :
708 : // get rid of Config objects. this also writes any changes
709 0 : for( file_it = files.begin(); file_it != files.end(); ++file_it )
710 0 : delete file_it->second;
711 :
712 0 : return true;
713 : }
714 :
715 0 : bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
716 : {
717 0 : bool bSuccess = false;
718 :
719 0 : const PPDParser* pParser = NULL;
720 0 : if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
721 : {
722 0 : Printer aPrinter;
723 0 : aPrinter.m_bModified = true;
724 0 : aPrinter.m_aInfo = m_aGlobalDefaults;
725 0 : aPrinter.m_aInfo.m_aDriverName = rDriverName;
726 0 : aPrinter.m_aInfo.m_pParser = pParser;
727 0 : aPrinter.m_aInfo.m_aContext.setParser( pParser );
728 0 : aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
729 :
730 : // merge PPD values with global defaults
731 0 : for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
732 : {
733 0 : const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
734 0 : const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
735 0 : const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
736 0 : if( pDefKey && pPrinterKey )
737 : // at least the options exist in both PPDs
738 : {
739 0 : if( pDefValue )
740 : {
741 0 : const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
742 0 : if( pPrinterValue )
743 : // the printer has a corresponding option for the key
744 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
745 : }
746 : else
747 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
748 : }
749 : }
750 :
751 0 : m_aPrinters[ rPrinterName ] = aPrinter;
752 0 : bSuccess = true;
753 : #if OSL_DEBUG_LEVEL > 1
754 : fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n",
755 : OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
756 : m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
757 : m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice,
758 : m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
759 : m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
760 : #endif
761 : // comment: logically one should writePrinterConfig() here
762 : // but immediately after addPrinter() a changePrinterInfo()
763 : // will follow which writes it again, so we can currently save some
764 : // performance here
765 : }
766 0 : return bSuccess;
767 : }
768 :
769 0 : bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
770 : {
771 0 : bool bSuccess = true;
772 :
773 0 : std::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
774 0 : if( it != m_aPrinters.end() )
775 : {
776 0 : if( !it->second.m_aFile.isEmpty() )
777 : {
778 : // this printer already exists in a config file
779 :
780 : // check writeability of config file(s)
781 0 : if( ! checkWriteability( it->second.m_aFile ) )
782 0 : bSuccess = false;
783 : else
784 : {
785 0 : for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
786 0 : file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
787 : {
788 0 : if( ! checkWriteability( *file_it ) )
789 0 : bSuccess = false;
790 : }
791 : }
792 0 : if( bSuccess && ! bCheckOnly )
793 : {
794 :
795 0 : Config aConfig( it->second.m_aFile );
796 0 : aConfig.DeleteGroup( it->second.m_aGroup );
797 0 : aConfig.Flush();
798 0 : for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
799 0 : file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
800 : {
801 0 : Config aAltConfig( *file_it );
802 0 : aAltConfig.DeleteGroup( it->second.m_aGroup );
803 0 : aAltConfig.Flush();
804 0 : }
805 : }
806 : }
807 0 : if( bSuccess && ! bCheckOnly )
808 : {
809 0 : m_aPrinters.erase( it );
810 : // need this here because someone may call
811 : // checkPrintersChanged after the removal
812 : // but then other added printers were not flushed
813 : // to disk, so they are discarded
814 0 : writePrinterConfig();
815 : }
816 : }
817 0 : return bSuccess;
818 : }
819 :
820 0 : bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
821 : {
822 0 : bool bSuccess = false;
823 :
824 0 : std::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
825 0 : if( it != m_aPrinters.end() )
826 : {
827 0 : bSuccess = true;
828 0 : it->second.m_bModified = true;
829 0 : if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
830 0 : it->second.m_bModified = true;
831 0 : m_aDefaultPrinter = rPrinterName;
832 0 : writePrinterConfig();
833 : }
834 0 : return bSuccess;
835 : }
836 :
837 0 : const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
838 : {
839 0 : if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
840 : {
841 0 : m_aSystemPrintCommand = m_pQueueInfo->getCommand();
842 0 : m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
843 0 : delete m_pQueueInfo, m_pQueueInfo = NULL;
844 : }
845 :
846 0 : return m_aSystemPrintQueues;
847 : }
848 :
849 0 : bool PrinterInfoManager::checkFeatureToken( const OUString& rPrinterName, const char* pToken ) const
850 : {
851 0 : const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
852 0 : sal_Int32 nIndex = 0;
853 0 : while( nIndex != -1 )
854 : {
855 0 : OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
856 0 : sal_Int32 nInnerIndex = 0;
857 0 : OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
858 0 : if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
859 0 : return true;
860 0 : }
861 0 : return false;
862 : }
863 :
864 0 : FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
865 : {
866 0 : const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
867 0 : const OUString& rCommand = (bQuickCommand && !rPrinterInfo.m_aQuickCommand.isEmpty() ) ?
868 0 : rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
869 0 : OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
870 0 : aShellCommand += OString( " 2>/dev/null" );
871 :
872 0 : return popen (aShellCommand.getStr(), "w");
873 : }
874 :
875 0 : bool PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/, const OUString& /*rFaxNumber*/ )
876 : {
877 0 : return (0 == pclose( pFile ));
878 : }
879 :
880 0 : void PrinterInfoManager::setupJobContextData( JobData& rData )
881 : {
882 : std::unordered_map< OUString, Printer, OUStringHash >::iterator it =
883 0 : m_aPrinters.find( rData.m_aPrinterName );
884 0 : if( it != m_aPrinters.end() )
885 : {
886 0 : rData.m_pParser = it->second.m_aInfo.m_pParser;
887 0 : rData.m_aContext = it->second.m_aInfo.m_aContext;
888 : }
889 0 : }
890 :
891 158 : void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
892 : {
893 158 : if( ! rContext.getParser() )
894 0 : return;
895 :
896 158 : const PPDKey* pPageSizeKey = rContext.getParser()->getKey( OUString( "PageSize" ) );
897 158 : if( ! pPageSizeKey )
898 0 : return;
899 :
900 158 : int nModified = rContext.countValuesModified();
901 237 : while( nModified-- &&
902 79 : rContext.getModifiedKey( nModified ) != pPageSizeKey )
903 : ;
904 :
905 158 : if( nModified >= 0 ) // paper was set already, do not modify
906 : {
907 : #if OSL_DEBUG_LEVEL > 1
908 : fprintf( stderr, "not setting default paper, already set %s\n",
909 : OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
910 : #endif
911 79 : return;
912 : }
913 :
914 : // paper not set, fill in default value
915 79 : const PPDValue* pPaperVal = NULL;
916 79 : int nValues = pPageSizeKey->countValues();
917 733 : for( int i = 0; i < nValues && ! pPaperVal; i++ )
918 : {
919 654 : const PPDValue* pVal = pPageSizeKey->getValue( i );
920 654 : if( pVal->m_aOption.equalsIgnoreAsciiCase( m_aSystemDefaultPaper ) )
921 79 : pPaperVal = pVal;
922 : }
923 79 : if( pPaperVal )
924 : {
925 : #if OSL_DEBUG_LEVEL > 1
926 : fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
927 : #endif
928 79 : rContext.setValue( pPageSizeKey, pPaperVal );
929 : #if OSL_DEBUG_LEVEL > 1
930 : pPaperVal = rContext.getValue( pPageSizeKey );
931 : fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
932 : #endif
933 : }
934 : }
935 :
936 0 : bool PrinterInfoManager::startBatchPrint()
937 : {
938 0 : return false; // not implemented
939 : }
940 :
941 0 : bool PrinterInfoManager::supportsBatchPrint() const
942 : {
943 0 : return false;
944 : }
945 :
946 0 : bool PrinterInfoManager::flushBatchPrint()
947 : {
948 0 : return false;
949 : }
950 :
951 0 : SystemQueueInfo::SystemQueueInfo() :
952 0 : m_bChanged( false )
953 : {
954 0 : create();
955 0 : }
956 :
957 0 : SystemQueueInfo::~SystemQueueInfo()
958 : {
959 0 : static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
960 0 : if( ! pNoSyncDetection || !*pNoSyncDetection )
961 0 : join();
962 : else
963 0 : terminate();
964 0 : }
965 :
966 0 : bool SystemQueueInfo::hasChanged() const
967 : {
968 0 : MutexGuard aGuard( m_aMutex );
969 0 : bool bChanged = m_bChanged;
970 0 : return bChanged;
971 : }
972 :
973 0 : void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
974 : {
975 0 : MutexGuard aGuard( m_aMutex );
976 0 : rQueues = m_aQueues;
977 0 : m_bChanged = false;
978 0 : }
979 :
980 0 : OUString SystemQueueInfo::getCommand() const
981 : {
982 0 : MutexGuard aGuard( m_aMutex );
983 0 : OUString aRet = m_aCommand;
984 0 : return aRet;
985 : }
986 :
987 : struct SystemCommandParameters;
988 : typedef void(* tokenHandler)(const std::list< OString >&,
989 : std::list< PrinterInfoManager::SystemPrintQueue >&,
990 : const SystemCommandParameters*);
991 :
992 : struct SystemCommandParameters
993 : {
994 : const char* pQueueCommand;
995 : const char* pPrintCommand;
996 : const char* pForeToken;
997 : const char* pAftToken;
998 : unsigned int nForeTokenCount;
999 : tokenHandler pHandler;
1000 : };
1001 :
1002 : #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD))
1003 : static void lpgetSysQueueTokenHandler(
1004 : const std::list< OString >& i_rLines,
1005 : std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1006 : const SystemCommandParameters* )
1007 : {
1008 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1009 : std::unordered_set< OUString, OUStringHash > aUniqueSet;
1010 : std::unordered_set< OUString, OUStringHash > aOnlySet;
1011 : aUniqueSet.insert( OUString( "_all" ) );
1012 : aUniqueSet.insert( OUString( "_default" ) );
1013 :
1014 : // the eventual "all" attribute of the "_all" queue tells us, which
1015 : // printers are to be used for this user at all
1016 :
1017 : // find _all: line
1018 : OString aAllLine( "_all:" );
1019 : OString aAllAttr( "all=" );
1020 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1021 : it != i_rLines.end(); ++it )
1022 : {
1023 : if( it->indexOf( aAllLine, 0 ) == 0 )
1024 : {
1025 : // now find the "all" attribute
1026 : ++it;
1027 : while( it != i_rLines.end() )
1028 : {
1029 : OString aClean( WhitespaceToSpace( *it ) );
1030 : if( aClean.startsWith( aAllAttr ) )
1031 : {
1032 : // insert the comma separated entries into the set of printers to use
1033 : sal_Int32 nPos = aAllAttr.getLength();
1034 : while( nPos != -1 )
1035 : {
1036 : OString aTok( aClean.getToken( 0, ',', nPos ) );
1037 : if( !aTok.isEmpty() )
1038 : aOnlySet.insert( OStringToOUString( aTok, aEncoding ) );
1039 : }
1040 : break;
1041 : }
1042 : }
1043 : break;
1044 : }
1045 : }
1046 :
1047 : bool bInsertAttribute = false;
1048 : OString aDescrStr( "description=" );
1049 : OString aLocStr( "location=" );
1050 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1051 : it != i_rLines.end(); ++it )
1052 : {
1053 : sal_Int32 nPos = 0;
1054 : // find the begin of a new printer section
1055 : nPos = it->indexOf( ':', 0 );
1056 : if( nPos != -1 )
1057 : {
1058 : OUString aSysQueue( OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
1059 : // do not insert duplicates (e.g. lpstat tends to produce such lines)
1060 : // in case there was a "_all" section, insert only those printer explicitly
1061 : // set in the "all" attribute
1062 : if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
1063 : ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
1064 : )
1065 : {
1066 : o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1067 : o_rQueues.back().m_aQueue = aSysQueue;
1068 : o_rQueues.back().m_aLocation = aSysQueue;
1069 : aUniqueSet.insert( aSysQueue );
1070 : bInsertAttribute = true;
1071 : }
1072 : else
1073 : bInsertAttribute = false;
1074 : continue;
1075 : }
1076 : if( bInsertAttribute && ! o_rQueues.empty() )
1077 : {
1078 : // look for "description" attribute, insert as comment
1079 : nPos = it->indexOf( aDescrStr, 0 );
1080 : if( nPos != -1 )
1081 : {
1082 : OString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
1083 : if( !aComment.isEmpty() )
1084 : o_rQueues.back().m_aComment = OStringToOUString(aComment, aEncoding);
1085 : continue;
1086 : }
1087 : // look for "location" attribute, inser as location
1088 : nPos = it->indexOf( aLocStr, 0 );
1089 : if( nPos != -1 )
1090 : {
1091 : OString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
1092 : if( !aLoc.isEmpty() )
1093 : o_rQueues.back().m_aLocation = OStringToOUString(aLoc, aEncoding);
1094 : continue;
1095 : }
1096 : }
1097 : }
1098 : }
1099 : #endif
1100 0 : static void standardSysQueueTokenHandler(
1101 : const std::list< OString >& i_rLines,
1102 : std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1103 : const SystemCommandParameters* i_pParms)
1104 : {
1105 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1106 0 : std::unordered_set< OUString, OUStringHash > aUniqueSet;
1107 0 : OString aForeToken( i_pParms->pForeToken );
1108 0 : OString aAftToken( i_pParms->pAftToken );
1109 : /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
1110 : */
1111 0 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1112 0 : it != i_rLines.end(); ++it )
1113 : {
1114 0 : sal_Int32 nPos = 0;
1115 :
1116 : // search for a line describing a printer:
1117 : // find if there are enough tokens before the name
1118 0 : for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
1119 : {
1120 0 : nPos = it->indexOf( aForeToken, nPos );
1121 0 : if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
1122 0 : nPos += aForeToken.getLength();
1123 : }
1124 0 : if( nPos != -1 )
1125 : {
1126 : // find if there is the token after the queue
1127 0 : sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
1128 0 : if( nAftPos != -1 )
1129 : {
1130 : // get the queue name between fore and aft tokens
1131 0 : OUString aSysQueue( OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
1132 : // do not insert duplicates (e.g. lpstat tends to produce such lines)
1133 0 : if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
1134 : {
1135 0 : o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1136 0 : o_rQueues.back().m_aQueue = aSysQueue;
1137 0 : o_rQueues.back().m_aLocation = aSysQueue;
1138 0 : aUniqueSet.insert( aSysQueue );
1139 0 : }
1140 : }
1141 : }
1142 0 : }
1143 0 : }
1144 :
1145 : static const struct SystemCommandParameters aParms[] =
1146 : {
1147 : #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD)
1148 : { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1149 : { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1150 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
1151 : #else
1152 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
1153 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
1154 : { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1155 : { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
1156 : #endif
1157 : };
1158 :
1159 0 : void SystemQueueInfo::run()
1160 : {
1161 0 : osl_setThreadName("LPR psp::SystemQueueInfo");
1162 :
1163 : char pBuffer[1024];
1164 : FILE *pPipe;
1165 0 : std::list< OString > aLines;
1166 :
1167 : /* Discover which command we can use to get a list of all printer queues */
1168 0 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(aParms); i++ )
1169 : {
1170 0 : aLines.clear();
1171 0 : OStringBuffer aCmdLine( 128 );
1172 0 : aCmdLine.append( aParms[i].pQueueCommand );
1173 : #if OSL_DEBUG_LEVEL > 1
1174 : fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
1175 : #endif
1176 0 : aCmdLine.append( " 2>/dev/null" );
1177 0 : if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
1178 : {
1179 0 : while( fgets( pBuffer, 1024, pPipe ) )
1180 0 : aLines.push_back( OString( pBuffer ) );
1181 0 : if( ! pclose( pPipe ) )
1182 : {
1183 0 : std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
1184 0 : aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
1185 0 : MutexGuard aGuard( m_aMutex );
1186 0 : m_bChanged = true;
1187 0 : m_aQueues = aSysPrintQueues;
1188 0 : m_aCommand = OUString::createFromAscii( aParms[i].pPrintCommand );
1189 : #if OSL_DEBUG_LEVEL > 1
1190 : fprintf( stderr, "success\n" );
1191 : #endif
1192 0 : break;
1193 : }
1194 : }
1195 : #if OSL_DEBUG_LEVEL > 1
1196 : fprintf( stderr, "failed\n" );
1197 : #endif
1198 0 : }
1199 801 : }
1200 :
1201 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|