1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
57 class SystemQueueInfo
: public Thread
59 mutable Mutex m_aMutex
;
61 std::list
< PrinterInfoManager::SystemPrintQueue
>
65 virtual void run() SAL_OVERRIDE
;
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
);
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() );
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
),
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()
124 #if OSL_DEBUG_LEVEL > 1
125 fprintf( stderr
, "PrinterInfoManager: destroyed Manager of type %d\n", getType() );
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
)
144 if( DirectoryItem::get( it
->m_aFilePath
, aItem
) )
146 if( it
->m_aModified
.Seconds
!= 0 )
147 bChanged
= true; // file probably has vanished
151 FileStatus
aStatus( osl_FileStatus_Mask_ModifyTime
);
152 if( aItem
.getFileStatus( aStatus
) )
153 bChanged
= true; // unlikely but not impossible
156 TimeValue aModified
= aStatus
.getModifyTime();
157 if( aModified
.Seconds
!= it
->m_aModified
.Seconds
)
163 if( bWait
&& m_pQueueInfo
)
165 #if OSL_DEBUG_LEVEL > 1
166 fprintf( stderr
, "syncing printer discovery thread\n" );
168 m_pQueueInfo
->join();
169 #if OSL_DEBUG_LEVEL > 1
170 fprintf( stderr
, "done: syncing printer discovery thread\n" );
174 if( ! bChanged
&& m_pQueueInfo
)
175 bChanged
= m_pQueueInfo
->hasChanged();
184 void PrinterInfoManager::initialize()
186 m_bUseIncludeFeature
= false;
187 rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
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" );
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() );
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
));
270 m_aGlobalDefaults
.m_aContext
.
272 aValue
.equals("*nil") ? NULL
: pKey
->getValue(OStringToOUString(aValue
, RTL_TEXTENCODING_ISO_8859_1
)),
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
290 FileBase::getFileURLFromSystemPath( aDir
.PathToFileName(), aUniPath
);
291 Directory
aDirectory( aUniPath
);
292 if( aDirectory
.open() )
296 FileBase::getFileURLFromSystemPath( aFile
.PathToFileName(), aUniPath
);
297 FileStatus
aStatus( osl_FileStatus_Mask_ModifyTime
);
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();
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"
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
)
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
366 const PPDValue
* pPrinterValue
= pPrinterKey
->getValue( pDefValue
->m_aOption
);
368 // the printer has a corresponding option for the key
369 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, pPrinterValue
);
372 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, NULL
);
376 aValue
= aConfig
.ReadKey( "Command" );
377 // no printer without a command
378 if (aValue
.isEmpty())
381 * porters: please append your platform to the Solaris
382 * case if your platform has SystemV printing per default.
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
));
456 aPrinter
.m_aInfo
.m_aContext
.
458 aValue
.equals("*nil") ? NULL
: pKey
->getValue(OStringToOUString(aValue
, RTL_TEXTENCODING_ISO_8859_1
)),
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
;
489 aDefaultPrinter
= OUString();
490 m_aDefaultPrinter
= aDefaultPrinter
;
492 if( m_eType
!= Default
)
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
;
520 if( m_aPrinters
.find( aPrinterName
) != m_aPrinters
.end() )
521 // probably user made this one permanent
524 OUString
aCmd( m_aSystemPrintCommand
);
525 aCmd
= aCmd
.replaceAll( "(PRINTER)", it
->m_aQueue
);
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
;
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
)
579 FileBase::getSystemPathFromFileURL( rUniPath
, aSysPath
);
580 SvFileStream
aStream( aSysPath
, STREAM_READ
| STREAM_WRITE
);
581 if( aStream
.IsOpen() && aStream
.IsWritable() )
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
);
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
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" ) )
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
);
639 bInsertToNewFile
= true;
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
);
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
));
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
));
687 aValue
.append(static_cast<sal_Int32
>(it
->second
.m_aInfo
.m_nRightMarginAdjust
));
689 aValue
.append(static_cast<sal_Int32
>(it
->second
.m_aInfo
.m_nTopMarginAdjust
));
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
);
705 aValue
.append(OUStringToOString(pValue
->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
));
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
;
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
) ) )
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
747 const PPDValue
* pPrinterValue
= pPrinterKey
->getValue( pDefValue
->m_aOption
);
749 // the printer has a corresponding option for the key
750 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, pPrinterValue
);
753 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, NULL
);
757 m_aPrinters
[ rPrinterName
] = aPrinter
;
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
);
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
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
) )
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
) )
798 if( bSuccess
&& ! bCheckOnly
)
801 Config
aConfig( it
->second
.m_aFile
);
802 aConfig
.DeleteGroup( it
->second
.m_aGroup
);
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
);
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();
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() )
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();
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
;
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
) )
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() )
922 const PPDKey
* pPageSizeKey
= rContext
.getParser()->getKey( OUString( "PageSize" ) );
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() );
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
) )
951 #if OSL_DEBUG_LEVEL > 1
952 fprintf( stderr
, "setting default paper %s\n", OUStringToOString( pPaperVal
->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
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() );
962 SystemQueueInfo::SystemQueueInfo() :
968 SystemQueueInfo::~SystemQueueInfo()
970 static const char* pNoSyncDetection
= getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
971 if( ! pNoSyncDetection
|| !*pNoSyncDetection
)
977 bool SystemQueueInfo::hasChanged() const
979 MutexGuard
aGuard( m_aMutex
);
980 bool bChanged
= m_bChanged
;
984 void SystemQueueInfo::getSystemQueues( std::list
< PrinterInfoManager::SystemPrintQueue
>& rQueues
)
986 MutexGuard
aGuard( m_aMutex
);
991 OUString
SystemQueueInfo::getCommand() const
993 MutexGuard
aGuard( m_aMutex
);
994 OUString aRet
= m_aCommand
;
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
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
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();
1047 OString
aTok( aClean
.getToken( 0, ',', nPos
) );
1048 if( !aTok
.isEmpty() )
1049 aOnlySet
.insert( OStringToOUString( aTok
, aEncoding
) );
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
)
1065 // find the begin of a new printer section
1066 nPos
= it
->indexOf( ':', 0 );
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;
1084 bInsertAttribute
= false;
1087 if( bInsertAttribute
&& ! o_rQueues
.empty() )
1089 // look for "description" attribute, insert as comment
1090 nPos
= it
->indexOf( aDescrStr
, 0 );
1093 OString
aComment( WhitespaceToSpace( it
->copy(nPos
+12) ) );
1094 if( !aComment
.isEmpty() )
1095 o_rQueues
.back().m_aComment
= OStringToOUString(aComment
, aEncoding
);
1098 // look for "location" attribute, inser as location
1099 nPos
= it
->indexOf( aLocStr
, 0 );
1102 OString
aLoc( WhitespaceToSpace( it
->copy(nPos
+9) ) );
1103 if( !aLoc
.isEmpty() )
1104 o_rQueues
.back().m_aLocation
= OStringToOUString(aLoc
, aEncoding
);
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
)
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();
1137 // find if there is the token after the queue
1138 sal_Int32 nAftPos
= it
->indexOf( aAftToken
, nPos
);
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
}
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
}
1170 void SystemQueueInfo::run()
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
++ )
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
);
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
);
1196 m_aQueues
= aSysPrintQueues
;
1197 m_aCommand
= OUString::createFromAscii( aParms
[i
].pPrintCommand
);
1198 #if OSL_DEBUG_LEVEL > 1
1199 fprintf( stderr
, "success\n" );
1204 #if OSL_DEBUG_LEVEL > 1
1205 fprintf( stderr
, "failed\n" );
1210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */