Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / vcl / unx / generic / printer / printerinfomanager.cxx
blob8c05206206f2b2f57c9f38b540fc63dd3842fed7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <unistd.h>
21 #include <sys/wait.h>
22 #include <signal.h>
24 #include "cupsmgr.hxx"
25 #include "vcl/strhelper.hxx"
27 #include "unx/saldata.hxx"
29 #include "tools/urlobj.hxx"
30 #include "tools/stream.hxx"
31 #include "tools/debug.hxx"
32 #include "tools/config.hxx"
34 #include "i18nutil/paper.hxx"
35 #include <comphelper/string.hxx>
36 #include "rtl/strbuf.hxx"
37 #include <sal/macros.h>
39 #include "osl/thread.hxx"
40 #include "osl/mutex.hxx"
41 #include "osl/process.h"
43 #include <boost/scoped_ptr.hpp>
45 // filename of configuration files
46 #define PRINT_FILENAME "psprint.conf"
47 // the group of the global defaults
48 #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
50 #include <boost/unordered_set.hpp>
52 using namespace psp;
53 using namespace osl;
55 namespace psp
57 class SystemQueueInfo : public Thread
59 mutable Mutex m_aMutex;
60 bool m_bChanged;
61 std::list< PrinterInfoManager::SystemPrintQueue >
62 m_aQueues;
63 OUString m_aCommand;
65 virtual void run() SAL_OVERRIDE;
67 public:
68 SystemQueueInfo();
69 virtual ~SystemQueueInfo();
71 bool hasChanged() const;
72 OUString getCommand() const;
74 // sets changed status to false; therefore not const
75 void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
77 } // namespace
80 * class PrinterInfoManager
83 PrinterInfoManager& PrinterInfoManager::get()
85 SalData* pSalData = GetSalData();
87 if( ! pSalData->m_pPIManager )
89 pSalData->m_pPIManager = CUPSManager::tryLoadCUPS();
90 if( ! pSalData->m_pPIManager )
91 pSalData->m_pPIManager = new PrinterInfoManager();
93 pSalData->m_pPIManager->initialize();
94 #if OSL_DEBUG_LEVEL > 1
95 fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() );
96 #endif
99 return *pSalData->m_pPIManager;
102 void PrinterInfoManager::release()
104 SalData* pSalData = GetSalData();
105 delete pSalData->m_pPIManager;
106 pSalData->m_pPIManager = NULL;
109 PrinterInfoManager::PrinterInfoManager( Type eType ) :
110 m_pQueueInfo( NULL ),
111 m_eType( eType ),
112 m_bUseIncludeFeature( false ),
113 m_bUseJobPatch( true ),
114 m_aSystemDefaultPaper( "A4" )
116 if( eType == Default )
117 m_pQueueInfo = new SystemQueueInfo();
118 initSystemDefaultPaper();
121 PrinterInfoManager::~PrinterInfoManager()
123 delete m_pQueueInfo;
124 #if OSL_DEBUG_LEVEL > 1
125 fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() );
126 #endif
129 void PrinterInfoManager::initSystemDefaultPaper()
131 m_aSystemDefaultPaper = OStringToOUString(
132 PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
133 RTL_TEXTENCODING_UTF8);
136 bool PrinterInfoManager::checkPrintersChanged( bool bWait )
138 // check if files were created, deleted or modified since initialize()
139 ::std::list< WatchFile >::const_iterator it;
140 bool bChanged = false;
141 for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
143 DirectoryItem aItem;
144 if( DirectoryItem::get( it->m_aFilePath, aItem ) )
146 if( it->m_aModified.Seconds != 0 )
147 bChanged = true; // file probably has vanished
149 else
151 FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
152 if( aItem.getFileStatus( aStatus ) )
153 bChanged = true; // unlikely but not impossible
154 else
156 TimeValue aModified = aStatus.getModifyTime();
157 if( aModified.Seconds != it->m_aModified.Seconds )
158 bChanged = true;
163 if( bWait && m_pQueueInfo )
165 #if OSL_DEBUG_LEVEL > 1
166 fprintf( stderr, "syncing printer discovery thread\n" );
167 #endif
168 m_pQueueInfo->join();
169 #if OSL_DEBUG_LEVEL > 1
170 fprintf( stderr, "done: syncing printer discovery thread\n" );
171 #endif
174 if( ! bChanged && m_pQueueInfo )
175 bChanged = m_pQueueInfo->hasChanged();
176 if( bChanged )
178 initialize();
181 return bChanged;
184 void PrinterInfoManager::initialize()
186 m_bUseIncludeFeature = false;
187 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
188 m_aPrinters.clear();
189 m_aWatchFiles.clear();
190 OUString aDefaultPrinter;
192 // first initialize the global defaults
193 // have to iterate over all possible files
194 // there should be only one global setup section in all
195 // available config files
196 m_aGlobalDefaults = PrinterInfo();
198 // need a parser for the PPDContext. generic printer should do.
199 m_aGlobalDefaults.m_pParser = PPDParser::getParser( OUString( "SGENPRT" ) );
200 m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
202 if( ! m_aGlobalDefaults.m_pParser )
204 #if OSL_DEBUG_LEVEL > 1
205 fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
206 #endif
207 return;
210 std::list< OUString > aDirList;
211 psp::getPrinterPathList( aDirList, NULL );
212 std::list< OUString >::const_iterator print_dir_it;
213 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
215 INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
216 aFile.Append( OUString( PRINT_FILENAME ) );
217 Config aConfig( aFile.PathToFileName() );
218 if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
220 #if OSL_DEBUG_LEVEL > 1
221 fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
222 #endif
223 aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
225 OString aValue( aConfig.ReadKey( "Copies" ) );
226 if (!aValue.isEmpty())
227 m_aGlobalDefaults.m_nCopies = aValue.toInt32();
229 aValue = aConfig.ReadKey( "Orientation" );
230 if (!aValue.isEmpty())
231 m_aGlobalDefaults.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
233 using comphelper::string::getToken;
235 aValue = aConfig.ReadKey( "MarginAdjust" );
236 if (!aValue.isEmpty())
238 m_aGlobalDefaults.m_nLeftMarginAdjust = getToken(aValue, 0, ',').toInt32();
239 m_aGlobalDefaults.m_nRightMarginAdjust = getToken(aValue, 1, ',').toInt32();
240 m_aGlobalDefaults.m_nTopMarginAdjust = getToken(aValue, 2, ',').toInt32();
241 m_aGlobalDefaults.m_nBottomMarginAdjust = getToken(aValue, 3, ',').toInt32();
244 aValue = aConfig.ReadKey( "ColorDepth", "24" );
245 if (!aValue.isEmpty())
246 m_aGlobalDefaults.m_nColorDepth = aValue.toInt32();
248 aValue = aConfig.ReadKey( "ColorDevice" );
249 if (!aValue.isEmpty())
250 m_aGlobalDefaults.m_nColorDevice = aValue.toInt32();
252 aValue = aConfig.ReadKey( "PSLevel" );
253 if (!aValue.isEmpty())
254 m_aGlobalDefaults.m_nPSLevel = aValue.toInt32();
256 aValue = aConfig.ReadKey( "PDFDevice" );
257 if (!aValue.isEmpty())
258 m_aGlobalDefaults.m_nPDFDevice = aValue.toInt32();
260 // get the PPDContext of global JobData
261 for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
263 OString aKey( aConfig.GetKeyName( nKey ) );
264 if (aKey.startsWith("PPD_"))
266 aValue = aConfig.ReadKey( aKey );
267 const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
268 if( pKey )
270 m_aGlobalDefaults.m_aContext.
271 setValue( pKey,
272 aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
273 true );
279 setDefaultPaper( m_aGlobalDefaults.m_aContext );
281 // now collect all available printers
282 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
284 INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
285 INetURLObject aFile( aDir );
286 aFile.Append( OUString( PRINT_FILENAME ) );
288 // check directory validity
289 OUString aUniPath;
290 FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
291 Directory aDirectory( aUniPath );
292 if( aDirectory.open() )
293 continue;
294 aDirectory.close();
296 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
297 FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
298 DirectoryItem aItem;
300 // setup WatchFile list
301 WatchFile aWatchFile;
302 aWatchFile.m_aFilePath = aUniPath;
303 if( ! DirectoryItem::get( aUniPath, aItem ) &&
304 ! aItem.getFileStatus( aStatus ) )
306 aWatchFile.m_aModified = aStatus.getModifyTime();
308 else
310 aWatchFile.m_aModified.Seconds = 0;
311 aWatchFile.m_aModified.Nanosec = 0;
313 m_aWatchFiles.push_back( aWatchFile );
315 Config aConfig( aFile.PathToFileName() );
316 for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
318 aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
319 OString aValue = aConfig.ReadKey( "Printer" );
320 if (!aValue.isEmpty())
322 OUString aPrinterName;
324 sal_Int32 nNamePos = aValue.indexOf('/');
325 // check for valid value of "Printer"
326 if (nNamePos == -1)
327 continue;
329 Printer aPrinter;
330 // initialize to global defaults
331 aPrinter.m_aInfo = m_aGlobalDefaults;
333 aPrinterName = OStringToOUString(aValue.copy(nNamePos+1),
334 RTL_TEXTENCODING_UTF8);
335 aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
336 aPrinter.m_aInfo.m_aDriverName = OStringToOUString(aValue.copy(0, nNamePos), RTL_TEXTENCODING_UTF8);
338 // set parser, merge settings
339 // don't do this for CUPS printers as this is done
340 // by the CUPS system itself
341 if( !aPrinter.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
343 aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
344 aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
345 // note: setParser also purges the context
347 // ignore this printer if its driver is not found
348 if( ! aPrinter.m_aInfo.m_pParser )
349 continue;
351 // merge the ppd context keys if the printer has the same keys and values
352 // this is a bit tricky, since it involves mixing two PPDs
353 // without constraints which might end up badly
354 // this feature should be use with caution
355 // it is mainly to select default paper sizes for new printers
356 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
358 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
359 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
360 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
361 if( pDefKey && pPrinterKey )
362 // at least the options exist in both PPDs
364 if( pDefValue )
366 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
367 if( pPrinterValue )
368 // the printer has a corresponding option for the key
369 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
371 else
372 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
376 aValue = aConfig.ReadKey( "Command" );
377 // no printer without a command
378 if (aValue.isEmpty())
380 /* TODO:
381 * porters: please append your platform to the Solaris
382 * case if your platform has SystemV printing per default.
384 #if defined SOLARIS
385 aValue = "lp";
386 #else
387 aValue = "lpr";
388 #endif
390 aPrinter.m_aInfo.m_aCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
393 aValue = aConfig.ReadKey( "QuickCommand" );
394 aPrinter.m_aInfo.m_aQuickCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
396 aValue = aConfig.ReadKey( "Features" );
397 aPrinter.m_aInfo.m_aFeatures = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
399 // override the settings in m_aGlobalDefaults if keys exist
400 aValue = aConfig.ReadKey( "DefaultPrinter" );
401 if (!aValue.equals("0") && !aValue.equalsIgnoreAsciiCase("false"))
402 aDefaultPrinter = aPrinterName;
404 aValue = aConfig.ReadKey( "Location" );
405 aPrinter.m_aInfo.m_aLocation = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
407 aValue = aConfig.ReadKey( "Comment" );
408 aPrinter.m_aInfo.m_aComment = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
410 aValue = aConfig.ReadKey( "Copies" );
411 if (!aValue.isEmpty())
412 aPrinter.m_aInfo.m_nCopies = aValue.toInt32();
414 aValue = aConfig.ReadKey( "Orientation" );
415 if (!aValue.isEmpty())
416 aPrinter.m_aInfo.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
418 using comphelper::string::getToken;
420 aValue = aConfig.ReadKey( "MarginAdjust" );
421 if (!aValue.isEmpty())
423 aPrinter.m_aInfo.m_nLeftMarginAdjust = getToken(aValue, 0, ',' ).toInt32();
424 aPrinter.m_aInfo.m_nRightMarginAdjust = getToken(aValue, 1, ',' ).toInt32();
425 aPrinter.m_aInfo.m_nTopMarginAdjust = getToken(aValue, 2, ',' ).toInt32();
426 aPrinter.m_aInfo.m_nBottomMarginAdjust = getToken(aValue, 3, ',' ).toInt32();
429 aValue = aConfig.ReadKey( "ColorDepth" );
430 if (!aValue.isEmpty())
431 aPrinter.m_aInfo.m_nColorDepth = aValue.toInt32();
433 aValue = aConfig.ReadKey( "ColorDevice" );
434 if (!aValue.isEmpty())
435 aPrinter.m_aInfo.m_nColorDevice = aValue.toInt32();
437 aValue = aConfig.ReadKey( "PSLevel" );
438 if (!aValue.isEmpty())
439 aPrinter.m_aInfo.m_nPSLevel = aValue.toInt32();
441 aValue = aConfig.ReadKey( "PDFDevice" );
442 if (!aValue.isEmpty())
443 aPrinter.m_aInfo.m_nPDFDevice = aValue.toInt32();
445 // now iterate over all keys to extract multi key information:
446 // 1. PPDContext information
447 for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
449 OString aKey( aConfig.GetKeyName( nKey ) );
450 if( aKey.startsWith("PPD_") && aPrinter.m_aInfo.m_pParser )
452 aValue = aConfig.ReadKey( aKey );
453 const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
454 if( pKey )
456 aPrinter.m_aInfo.m_aContext.
457 setValue( pKey,
458 aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
459 true );
464 setDefaultPaper( aPrinter.m_aInfo.m_aContext );
466 // finally insert printer
467 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
468 aPrinter.m_bModified = false;
469 aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
470 boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator find_it =
471 m_aPrinters.find( aPrinterName );
472 if( find_it != m_aPrinters.end() )
474 aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
475 aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
477 m_aPrinters[ aPrinterName ] = aPrinter;
482 // set default printer
483 if( m_aPrinters.size() )
485 if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
486 aDefaultPrinter = m_aPrinters.begin()->first;
488 else
489 aDefaultPrinter = OUString();
490 m_aDefaultPrinter = aDefaultPrinter;
492 if( m_eType != Default )
493 return;
495 // add a default printer for every available print queue
496 // merge paper default printer, all else from global defaults
497 PrinterInfo aMergeInfo( m_aGlobalDefaults );
498 aMergeInfo.m_aDriverName = "SGENPRT";
499 aMergeInfo.m_aFeatures = "autoqueue";
501 if( !m_aDefaultPrinter.isEmpty() )
503 PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
505 const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( OUString( "PageSize" ) );
506 const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( OUString( "PageSize" ) );
507 const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
508 const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
509 if( pMergeKey && pMergeValue )
510 aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
513 getSystemPrintQueues();
514 for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
516 OUString aPrinterName( "<" );
517 aPrinterName += it->m_aQueue;
518 aPrinterName += ">";
520 if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
521 // probably user made this one permanent
522 continue;
524 OUString aCmd( m_aSystemPrintCommand );
525 aCmd = aCmd.replaceAll( "(PRINTER)", it->m_aQueue );
527 Printer aPrinter;
529 // initialize to merged defaults
530 aPrinter.m_aInfo = aMergeInfo;
531 aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
532 aPrinter.m_aInfo.m_aCommand = aCmd;
533 aPrinter.m_aInfo.m_aComment = it->m_aComment;
534 aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
535 aPrinter.m_bModified = false;
536 aPrinter.m_aGroup = OUStringToOString(aPrinterName, aEncoding); //provide group name in case user makes this one permanent
538 m_aPrinters[ aPrinterName ] = aPrinter;
542 void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
544 ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it;
545 rList.clear();
546 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
547 rList.push_back( it->first );
550 const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
552 static PrinterInfo aEmptyInfo;
553 ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
555 DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" );
557 return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
560 void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
562 ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
564 DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
566 if( it != m_aPrinters.end() )
568 it->second.m_aInfo = rNewInfo;
569 it->second.m_bModified = true;
570 writePrinterConfig();
574 // need to check writeability / creatability of config files
575 static bool checkWriteability( const OUString& rUniPath )
577 bool bRet = false;
578 OUString aSysPath;
579 FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
580 SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
581 if( aStream.IsOpen() && aStream.IsWritable() )
582 bRet = true;
583 return bRet;
586 bool PrinterInfoManager::writePrinterConfig()
588 // find at least one writeable config
589 ::boost::unordered_map< OUString, Config*, OUStringHash > files;
590 ::boost::unordered_map< OUString, int, OUStringHash > rofiles;
591 ::boost::unordered_map< OUString, Config*, OUStringHash >::iterator file_it;
593 for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
595 if( checkWriteability( wit->m_aFilePath ) )
597 files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
598 break;
602 if( files.empty() )
603 return false;
605 Config* pGlobal = files.begin()->second;
606 pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
608 ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it;
609 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
611 if( ! it->second.m_bModified )
612 // printer was not changed, do nothing
613 continue;
615 // don't save autoqueue printers
616 sal_Int32 nIndex = 0;
617 bool bAutoQueue = false;
618 while( nIndex != -1 && ! bAutoQueue )
620 OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
621 if( aToken.equalsAscii( "autoqueue" ) )
622 bAutoQueue = true;
624 if( bAutoQueue )
625 continue;
627 if( !it->second.m_aFile.isEmpty() )
629 // check if file is writable
630 if( files.find( it->second.m_aFile ) == files.end() )
632 bool bInsertToNewFile = false;
633 // maybe it is simply not inserted yet
634 if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
636 if( checkWriteability( it->second.m_aFile ) )
637 files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
638 else
639 bInsertToNewFile = true;
641 else
642 bInsertToNewFile = true;
643 // original file is read only, insert printer in a new writeable file
644 if( bInsertToNewFile )
646 rofiles[ it->second.m_aFile ] = 1;
647 // update alternate file list
648 // the remove operation ensures uniqueness of each alternate
649 it->second.m_aAlternateFiles.remove( it->second.m_aFile );
650 it->second.m_aAlternateFiles.remove( files.begin()->first );
651 it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
652 // update file
653 it->second.m_aFile = files.begin()->first;
657 else // a new printer, write it to the first file available
658 it->second.m_aFile = files.begin()->first;
660 if( it->second.m_aGroup.isEmpty() ) // probably a new printer
661 it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
663 if( files.find( it->second.m_aFile ) != files.end() )
665 Config* pConfig = files[ it->second.m_aFile ];
666 pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
667 pConfig->SetGroup( it->second.m_aGroup );
669 OStringBuffer aValue(OUStringToOString(it->second.m_aInfo.m_aDriverName, RTL_TEXTENCODING_UTF8));
670 aValue.append('/');
671 aValue.append(OUStringToOString(it->first, RTL_TEXTENCODING_UTF8));
672 pConfig->WriteKey("Printer", aValue.makeStringAndClear());
673 pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
674 pConfig->WriteKey( "Location", OUStringToOString(it->second.m_aInfo.m_aLocation, RTL_TEXTENCODING_UTF8) );
675 pConfig->WriteKey( "Comment", OUStringToOString(it->second.m_aInfo.m_aComment, RTL_TEXTENCODING_UTF8) );
676 pConfig->WriteKey( "Command", OUStringToOString(it->second.m_aInfo.m_aCommand, RTL_TEXTENCODING_UTF8) );
677 pConfig->WriteKey( "QuickCommand", OUStringToOString(it->second.m_aInfo.m_aQuickCommand, RTL_TEXTENCODING_UTF8) );
678 pConfig->WriteKey( "Features", OUStringToOString(it->second.m_aInfo.m_aFeatures, RTL_TEXTENCODING_UTF8) );
679 pConfig->WriteKey("Copies", OString::number(it->second.m_aInfo.m_nCopies));
680 pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
681 pConfig->WriteKey("PSLevel", OString::number(it->second.m_aInfo.m_nPSLevel));
682 pConfig->WriteKey("PDFDevice", OString::number(it->second.m_aInfo.m_nPDFDevice));
683 pConfig->WriteKey("ColorDevice", OString::number(it->second.m_aInfo.m_nColorDevice));
684 pConfig->WriteKey("ColorDepth", OString::number(it->second.m_aInfo.m_nColorDepth));
685 aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nLeftMarginAdjust));
686 aValue.append(',');
687 aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nRightMarginAdjust));
688 aValue.append(',');
689 aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nTopMarginAdjust));
690 aValue.append(',');
691 aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nBottomMarginAdjust));
692 pConfig->WriteKey("MarginAdjust", aValue.makeStringAndClear());
694 if( ! it->second.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
696 // write PPDContext (not for CUPS)
697 for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
699 const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
700 OStringBuffer aKey("PPD_");
701 aKey.append(OUStringToOString(pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1));
703 const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
704 if (pValue)
705 aValue.append(OUStringToOString(pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1));
706 else
707 aValue.append("*nil");
708 pConfig->WriteKey(aKey.makeStringAndClear(), aValue.makeStringAndClear());
714 // get rid of Config objects. this also writes any changes
715 for( file_it = files.begin(); file_it != files.end(); ++file_it )
716 delete file_it->second;
718 return true;
721 bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
723 bool bSuccess = false;
725 const PPDParser* pParser = NULL;
726 if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
728 Printer aPrinter;
729 aPrinter.m_bModified = true;
730 aPrinter.m_aInfo = m_aGlobalDefaults;
731 aPrinter.m_aInfo.m_aDriverName = rDriverName;
732 aPrinter.m_aInfo.m_pParser = pParser;
733 aPrinter.m_aInfo.m_aContext.setParser( pParser );
734 aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
736 // merge PPD values with global defaults
737 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
739 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
740 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
741 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
742 if( pDefKey && pPrinterKey )
743 // at least the options exist in both PPDs
745 if( pDefValue )
747 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
748 if( pPrinterValue )
749 // the printer has a corresponding option for the key
750 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
752 else
753 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
757 m_aPrinters[ rPrinterName ] = aPrinter;
758 bSuccess = true;
759 #if OSL_DEBUG_LEVEL > 1
760 fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n",
761 OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
762 m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
763 m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice,
764 m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
765 m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
766 #endif
767 // comment: logically one should writePrinterConfig() here
768 // but immediately after addPrinter() a changePrinterInfo()
769 // will follow which writes it again, so we can currently save some
770 // performance here
772 return bSuccess;
775 bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
777 bool bSuccess = true;
779 ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
780 if( it != m_aPrinters.end() )
782 if( !it->second.m_aFile.isEmpty() )
784 // this printer already exists in a config file
786 // check writeability of config file(s)
787 if( ! checkWriteability( it->second.m_aFile ) )
788 bSuccess = false;
789 else
791 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
792 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
794 if( ! checkWriteability( *file_it ) )
795 bSuccess = false;
798 if( bSuccess && ! bCheckOnly )
801 Config aConfig( it->second.m_aFile );
802 aConfig.DeleteGroup( it->second.m_aGroup );
803 aConfig.Flush();
804 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
805 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
807 Config aAltConfig( *file_it );
808 aAltConfig.DeleteGroup( it->second.m_aGroup );
809 aAltConfig.Flush();
813 if( bSuccess && ! bCheckOnly )
815 m_aPrinters.erase( it );
816 // need this here because someone may call
817 // checkPrintersChanged after the removal
818 // but then other added printers were not flushed
819 // to disk, so they are discarded
820 writePrinterConfig();
823 return bSuccess;
826 bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
828 bool bSuccess = false;
830 ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
831 if( it != m_aPrinters.end() )
833 bSuccess = true;
834 it->second.m_bModified = true;
835 if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
836 it->second.m_bModified = true;
837 m_aDefaultPrinter = rPrinterName;
838 writePrinterConfig();
840 return bSuccess;
843 void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
845 if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
847 m_aSystemPrintCommand = m_pQueueInfo->getCommand();
848 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
849 delete m_pQueueInfo, m_pQueueInfo = NULL;
852 std::list< SystemPrintQueue >::const_iterator it;
853 rCommands.clear();
854 OUString aPrinterConst( "(PRINTER)" );
855 for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
857 OUString aCmd( m_aSystemPrintCommand );
858 aCmd = aCmd.replaceAll( aPrinterConst, it->m_aQueue );
859 rCommands.push_back( aCmd );
863 const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
865 if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
867 m_aSystemPrintCommand = m_pQueueInfo->getCommand();
868 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
869 delete m_pQueueInfo, m_pQueueInfo = NULL;
872 return m_aSystemPrintQueues;
875 bool PrinterInfoManager::checkFeatureToken( const OUString& rPrinterName, const char* pToken ) const
877 const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
878 sal_Int32 nIndex = 0;
879 while( nIndex != -1 )
881 OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
882 sal_Int32 nInnerIndex = 0;
883 OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
884 if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
885 return true;
887 return false;
890 FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
892 const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
893 const OUString& rCommand = (bQuickCommand && !rPrinterInfo.m_aQuickCommand.isEmpty() ) ?
894 rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
895 OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
896 aShellCommand += OString( " 2>/dev/null" );
898 return popen (aShellCommand.getStr(), "w");
901 bool PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/, const OUString& /*rFaxNumber*/ )
903 return (0 == pclose( pFile ));
906 void PrinterInfoManager::setupJobContextData( JobData& rData )
908 boost::unordered_map< OUString, Printer, OUStringHash >::iterator it =
909 m_aPrinters.find( rData.m_aPrinterName );
910 if( it != m_aPrinters.end() )
912 rData.m_pParser = it->second.m_aInfo.m_pParser;
913 rData.m_aContext = it->second.m_aInfo.m_aContext;
917 void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
919 if( ! rContext.getParser() )
920 return;
922 const PPDKey* pPageSizeKey = rContext.getParser()->getKey( OUString( "PageSize" ) );
923 if( ! pPageSizeKey )
924 return;
926 int nModified = rContext.countValuesModified();
927 while( nModified-- &&
928 rContext.getModifiedKey( nModified ) != pPageSizeKey )
931 if( nModified >= 0 ) // paper was set already, do not modify
933 #if OSL_DEBUG_LEVEL > 1
934 fprintf( stderr, "not setting default paper, already set %s\n",
935 OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
936 #endif
937 return;
940 // paper not set, fill in default value
941 const PPDValue* pPaperVal = NULL;
942 int nValues = pPageSizeKey->countValues();
943 for( int i = 0; i < nValues && ! pPaperVal; i++ )
945 const PPDValue* pVal = pPageSizeKey->getValue( i );
946 if( pVal->m_aOption.equalsIgnoreAsciiCase( m_aSystemDefaultPaper ) )
947 pPaperVal = pVal;
949 if( pPaperVal )
951 #if OSL_DEBUG_LEVEL > 1
952 fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
953 #endif
954 rContext.setValue( pPageSizeKey, pPaperVal );
955 #if OSL_DEBUG_LEVEL > 1
956 pPaperVal = rContext.getValue( pPageSizeKey );
957 fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
958 #endif
962 SystemQueueInfo::SystemQueueInfo() :
963 m_bChanged( false )
965 create();
968 SystemQueueInfo::~SystemQueueInfo()
970 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
971 if( ! pNoSyncDetection || !*pNoSyncDetection )
972 join();
973 else
974 terminate();
977 bool SystemQueueInfo::hasChanged() const
979 MutexGuard aGuard( m_aMutex );
980 bool bChanged = m_bChanged;
981 return bChanged;
984 void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
986 MutexGuard aGuard( m_aMutex );
987 rQueues = m_aQueues;
988 m_bChanged = false;
991 OUString SystemQueueInfo::getCommand() const
993 MutexGuard aGuard( m_aMutex );
994 OUString aRet = m_aCommand;
995 return aRet;
998 struct SystemCommandParameters;
999 typedef void(* tokenHandler)(const std::list< OString >&,
1000 std::list< PrinterInfoManager::SystemPrintQueue >&,
1001 const SystemCommandParameters*);
1003 struct SystemCommandParameters
1005 const char* pQueueCommand;
1006 const char* pPrintCommand;
1007 const char* pForeToken;
1008 const char* pAftToken;
1009 unsigned int nForeTokenCount;
1010 tokenHandler pHandler;
1013 #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD))
1014 static void lpgetSysQueueTokenHandler(
1015 const std::list< OString >& i_rLines,
1016 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1017 const SystemCommandParameters* )
1019 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1020 boost::unordered_set< OUString, OUStringHash > aUniqueSet;
1021 boost::unordered_set< OUString, OUStringHash > aOnlySet;
1022 aUniqueSet.insert( OUString( "_all" ) );
1023 aUniqueSet.insert( OUString( "_default" ) );
1025 // the eventual "all" attribute of the "_all" queue tells us, which
1026 // printers are to be used for this user at all
1028 // find _all: line
1029 OString aAllLine( "_all:" );
1030 OString aAllAttr( "all=" );
1031 for( std::list< OString >::const_iterator it = i_rLines.begin();
1032 it != i_rLines.end(); ++it )
1034 if( it->indexOf( aAllLine, 0 ) == 0 )
1036 // now find the "all" attribute
1037 ++it;
1038 while( it != i_rLines.end() )
1040 OString aClean( WhitespaceToSpace( *it ) );
1041 if( aClean.startsWith( aAllAttr ) )
1043 // insert the comma separated entries into the set of printers to use
1044 sal_Int32 nPos = aAllAttr.getLength();
1045 while( nPos != -1 )
1047 OString aTok( aClean.getToken( 0, ',', nPos ) );
1048 if( !aTok.isEmpty() )
1049 aOnlySet.insert( OStringToOUString( aTok, aEncoding ) );
1051 break;
1054 break;
1058 bool bInsertAttribute = false;
1059 OString aDescrStr( "description=" );
1060 OString aLocStr( "location=" );
1061 for( std::list< OString >::const_iterator it = i_rLines.begin();
1062 it != i_rLines.end(); ++it )
1064 sal_Int32 nPos = 0;
1065 // find the begin of a new printer section
1066 nPos = it->indexOf( ':', 0 );
1067 if( nPos != -1 )
1069 OUString aSysQueue( OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
1070 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1071 // in case there was a "_all" section, insert only those printer explicitly
1072 // set in the "all" attribute
1073 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
1074 ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
1077 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1078 o_rQueues.back().m_aQueue = aSysQueue;
1079 o_rQueues.back().m_aLocation = aSysQueue;
1080 aUniqueSet.insert( aSysQueue );
1081 bInsertAttribute = true;
1083 else
1084 bInsertAttribute = false;
1085 continue;
1087 if( bInsertAttribute && ! o_rQueues.empty() )
1089 // look for "description" attribute, insert as comment
1090 nPos = it->indexOf( aDescrStr, 0 );
1091 if( nPos != -1 )
1093 OString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
1094 if( !aComment.isEmpty() )
1095 o_rQueues.back().m_aComment = OStringToOUString(aComment, aEncoding);
1096 continue;
1098 // look for "location" attribute, inser as location
1099 nPos = it->indexOf( aLocStr, 0 );
1100 if( nPos != -1 )
1102 OString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
1103 if( !aLoc.isEmpty() )
1104 o_rQueues.back().m_aLocation = OStringToOUString(aLoc, aEncoding);
1105 continue;
1110 #endif
1111 static void standardSysQueueTokenHandler(
1112 const std::list< OString >& i_rLines,
1113 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1114 const SystemCommandParameters* i_pParms)
1116 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1117 boost::unordered_set< OUString, OUStringHash > aUniqueSet;
1118 OString aForeToken( i_pParms->pForeToken );
1119 OString aAftToken( i_pParms->pAftToken );
1120 /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
1122 for( std::list< OString >::const_iterator it = i_rLines.begin();
1123 it != i_rLines.end(); ++it )
1125 sal_Int32 nPos = 0;
1127 // search for a line describing a printer:
1128 // find if there are enough tokens before the name
1129 for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
1131 nPos = it->indexOf( aForeToken, nPos );
1132 if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
1133 nPos += aForeToken.getLength();
1135 if( nPos != -1 )
1137 // find if there is the token after the queue
1138 sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
1139 if( nAftPos != -1 )
1141 // get the queue name between fore and aft tokens
1142 OUString aSysQueue( OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
1143 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1144 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
1146 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1147 o_rQueues.back().m_aQueue = aSysQueue;
1148 o_rQueues.back().m_aLocation = aSysQueue;
1149 aUniqueSet.insert( aSysQueue );
1156 static const struct SystemCommandParameters aParms[] =
1158 #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD)
1159 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1160 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1161 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
1162 #else
1163 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
1164 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
1165 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1166 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
1167 #endif
1170 void SystemQueueInfo::run()
1172 char pBuffer[1024];
1173 FILE *pPipe;
1174 std::list< OString > aLines;
1176 /* Discover which command we can use to get a list of all printer queues */
1177 for( unsigned int i = 0; i < SAL_N_ELEMENTS(aParms); i++ )
1179 aLines.clear();
1180 OStringBuffer aCmdLine( 128 );
1181 aCmdLine.append( aParms[i].pQueueCommand );
1182 #if OSL_DEBUG_LEVEL > 1
1183 fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
1184 #endif
1185 aCmdLine.append( " 2>/dev/null" );
1186 if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
1188 while( fgets( pBuffer, 1024, pPipe ) )
1189 aLines.push_back( OString( pBuffer ) );
1190 if( ! pclose( pPipe ) )
1192 std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
1193 aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
1194 MutexGuard aGuard( m_aMutex );
1195 m_bChanged = true;
1196 m_aQueues = aSysPrintQueues;
1197 m_aCommand = OUString::createFromAscii( aParms[i].pPrintCommand );
1198 #if OSL_DEBUG_LEVEL > 1
1199 fprintf( stderr, "success\n" );
1200 #endif
1201 break;
1204 #if OSL_DEBUG_LEVEL > 1
1205 fprintf( stderr, "failed\n" );
1206 #endif
1210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */